Changeset 181a746 in mainline for kernel/generic/include/synch/rcu.h


Ignore:
Timestamp:
2012-07-10T17:50:29Z (12 years ago)
Author:
Adam Hraska <adam.hraska+hos@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
5b6c033
Parents:
22b5924
Message:

rcu: Added preemptible RCU's core API implementation.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • kernel/generic/include/synch/rcu.h

    r22b5924 r181a746  
    3636#define KERN_RCU_H_
    3737
     38#include <adt/list.h>
     39#include <synch/semaphore.h>
     40#include <compiler/barrier.h>
     41
     42
    3843/* Fwd decl. */
    39 struct rcu_head;
    40 
    41 /** RCU callback type. */
    42 typedef void (*rcu_cb_func_t)(struct rcu_head *head);
    43 
    44 /** */
    45 struct rcu_head {
    46         struct rcu_head *next;
    47         rcu_cb_func_t func;
    48 };
    49 
    50 
    51 
    52 void rcu_read_lock(void);
    53 void rcu_read_unlock(void);
    54 void rcu_synchronize(void);
    55 void rcu_call(struct rcu_head *head, rcu_cb_func_t func);
    56 
    57 
     44struct thread;
     45struct rcu_item;
     46
     47/** Grace period number typedef. */
     48typedef uint64_t rcu_gp_t;
     49
     50/** RCU callback type. The passed rcu_item_t maybe freed. */
     51typedef void (*rcu_func_t)(struct rcu_item *rcu_item);
     52
     53typedef struct rcu_item {
     54        rcu_func_t func;
     55        struct rcu_item *next;
     56} rcu_item_t;
     57
     58
     59/** RCU related per-cpu data. */
     60typedef struct rcu_cpu_data {
     61        /** The cpu recorded a quiescent state last time during this grace period */
     62        rcu_gp_t last_seen_gp;
     63       
     64        /** Pointer to the currently used nesting count (THREAD's or CPU's). */
     65        size_t *pnesting_cnt;
     66        /** Temporary nesting count if THREAD is NULL, eg in scheduler(). */
     67        size_t tmp_nesting_cnt;
     68
     69        /** Callbacks to invoke once the current grace period ends, ie cur_cbs_gp.
     70         * Accessed by the local reclaimer only.
     71         */
     72        rcu_item_t *cur_cbs;
     73        /** Callbacks to invoke once the next grace period ends, ie next_cbs_gp.
     74         * Accessed by the local reclaimer only.
     75         */
     76        rcu_item_t *next_cbs;
     77        /** New callbacks are place at the end of this list. */
     78        rcu_item_t *arriving_cbs;
     79        /** Tail of arriving_cbs list. Disable interrupts to access. */
     80        rcu_item_t **parriving_cbs_tail;
     81        /** Number of callbacks currently in arriving_cbs.
     82         * Disable interrupts to access.
     83         */
     84        size_t arriving_cbs_cnt;
     85
     86        /** At the end of this grace period callbacks in cur_cbs will be invoked.*/
     87        rcu_gp_t cur_cbs_gp;
     88        /** At the end of this grace period callbacks in next_cbs will be invoked.
     89         *
     90         * Should be the next grace period but it allows the reclaimer to
     91         * notice if it missed a grace period end announcement. In that
     92         * case it can execute next_cbs without waiting for another GP.
     93         *
     94         * Invariant: next_cbs_gp >= cur_cbs_gp
     95         */
     96        rcu_gp_t next_cbs_gp;
     97       
     98        /** This cpu has not yet passed a quiescent state and it is delaying the
     99         * detector. Once it reaches a QS it must sema_up(rcu.remaining_readers).
     100         */
     101        bool is_delaying_gp;
     102       
     103        /** Positive if there are callbacks pending in arriving_cbs. */
     104        semaphore_t arrived_flag;
     105       
     106        /** The reclaimer should expedite GPs for cbs in arriving_cbs. */
     107        bool expedite_arriving;
     108       
     109        /** Interruptable attached reclaimer thread. */
     110        struct thread *reclaimer_thr;
     111       
     112        /* Some statistics. */
     113        size_t stat_max_cbs;
     114        size_t stat_avg_cbs;
     115        size_t stat_missed_gps;
     116} rcu_cpu_data_t;
     117
     118
     119/** RCU related per-thread data. */
     120typedef struct rcu_thread_data {
     121        /** The number of times an RCU reader section is nested.
     122         *
     123         * If positive, it is definitely executing reader code. If zero,
     124         * the thread might already be executing reader code thanks to
     125         * cpu instruction reordering.
     126         */
     127        size_t nesting_cnt;
     128       
     129        /** True if the thread was preempted in a reader section.
     130         *
     131         * The thread is place into rcu.cur_preempted or rcu.next_preempted
     132         * and must remove itself in rcu_read_unlock().
     133         *
     134         * Access with interrupts disabled.
     135         */
     136        bool was_preempted;
     137        /** Preempted threads link. Access with rcu.prempt_lock.*/
     138        link_t preempt_link;
     139} rcu_thread_data_t;
     140
     141
     142#ifndef member_to_inst
     143#define member_to_inst(ptr_member, type, member_identif) \
     144        ((type*) (((void*)(ptr_member)) - ((void*)&(((type*)0)->member_identif))))
    58145#endif
    59146
     147/** Use to assign a pointer to newly initialized data to a rcu reader
     148 * accessible pointer.
     149 *
     150 * Example:
     151 * @code
     152 * typedef struct exam {
     153 *     struct exam *next;
     154 *     int grade;
     155 * } exam_t;
     156 *
     157 * exam_t *exam_list;
     158 * // ..
     159 *
     160 * // Insert at the beginning of the list.
     161 * exam_t *my_exam = malloc(sizeof(exam_t), 0);
     162 * my_exam->grade = 5;
     163 * my_exam->next = exam_list;
     164 * rcu_assign(exam_list, my_exam);
     165 *
     166 * // Changes properly propagate. Every reader either sees
     167 * // the old version of exam_list or the new version with
     168 * // the fully initialized my_exam.
     169 * rcu_synchronize();
     170 * // Now we can be sure every reader sees my_exam.
     171 *
     172 * @endcode
     173 */
     174#define rcu_assign(ptr, value) \
     175        do { \
     176                memory_barrier(); \
     177                (ptr) = (value); \
     178        } while (0)
     179
     180/** Use to access RCU protected data in a reader section.
     181 *
     182 * Example:
     183 * @code
     184 * exam_t *exam_list;
     185 * // ...
     186 *
     187 * rcu_read_lock();
     188 * exam_t *first_exam = rcu_access(exam_list);
     189 * // We can now safely use first_exam, it won't change
     190 * // under us while we're using it.
     191 *
     192 * // ..
     193 * rcu_read_unlock();
     194 * @endcode
     195 */
     196#define rcu_access(ptr) ACCESS_ONCE(ptr)
     197
     198extern void rcu_read_lock(void);
     199extern void rcu_read_unlock(void);
     200extern void rcu_synchronize(void);
     201extern void rcu_call(rcu_item_t *rcu_item, rcu_func_t func);
     202
     203extern void rcu_print_stat(void);
     204
     205extern void rcu_init(void);
     206extern void rcu_stop(void);
     207extern void rcu_cpu_init(void);
     208extern void rcu_kinit_init(void);
     209extern void rcu_thread_init(struct thread*);
     210extern void rcu_thread_exiting(void);
     211extern void rcu_after_thread_ran(void);
     212extern void rcu_before_thread_runs(void);
     213
     214/* Debugging/testing support. Not part of public API. Do not use! */
     215extern uint64_t rcu_completed_gps(void);
     216extern void _rcu_call(bool expedite, rcu_item_t *rcu_item, rcu_func_t func);
     217
     218#endif
     219
    60220/** @}
    61221 */
    62  
Note: See TracChangeset for help on using the changeset viewer.