Changeset 8e3ed06 in mainline for kernel/generic/include/synch/rcu.h
- Timestamp:
- 2012-07-29T17:28:45Z (12 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 5b03a72
- Parents:
- d99fac9
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
kernel/generic/include/synch/rcu.h
rd99fac9 r8e3ed06 36 36 #define KERN_RCU_H_ 37 37 38 #include <adt/list.h> 39 #include <synch/semaphore.h> 38 #include <synch/rcu_types.h> 40 39 #include <compiler/barrier.h> 41 40 42 41 43 /* Fwd decl. */44 struct thread;45 struct rcu_item;46 47 /** Grace period number typedef. */48 typedef uint64_t rcu_gp_t;49 50 /** RCU callback type. The passed rcu_item_t maybe freed. */51 typedef void (*rcu_func_t)(struct rcu_item *rcu_item);52 53 typedef 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. */60 typedef 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 /** Number of callbacks in cur_cbs. */74 size_t cur_cbs_cnt;75 /** Callbacks to invoke once the next grace period ends, ie next_cbs_gp.76 * Accessed by the local reclaimer only.77 */78 rcu_item_t *next_cbs;79 /** Number of callbacks in next_cbs. */80 size_t next_cbs_cnt;81 /** New callbacks are place at the end of this list. */82 rcu_item_t *arriving_cbs;83 /** Tail of arriving_cbs list. Disable interrupts to access. */84 rcu_item_t **parriving_cbs_tail;85 /** Number of callbacks currently in arriving_cbs.86 * Disable interrupts to access.87 */88 size_t arriving_cbs_cnt;89 90 /** At the end of this grace period callbacks in cur_cbs will be invoked.*/91 rcu_gp_t cur_cbs_gp;92 /** At the end of this grace period callbacks in next_cbs will be invoked.93 *94 * Should be the next grace period but it allows the reclaimer to95 * notice if it missed a grace period end announcement. In that96 * case it can execute next_cbs without waiting for another GP.97 *98 * Invariant: next_cbs_gp >= cur_cbs_gp99 */100 rcu_gp_t next_cbs_gp;101 102 /** This cpu has not yet passed a quiescent state and it is delaying the103 * detector. Once it reaches a QS it must sema_up(rcu.remaining_readers).104 */105 bool is_delaying_gp;106 107 /** Positive if there are callbacks pending in arriving_cbs. */108 semaphore_t arrived_flag;109 110 /** The reclaimer should expedite GPs for cbs in arriving_cbs. */111 bool expedite_arriving;112 113 /** Protected by global rcu.barrier_mtx. */114 rcu_item_t barrier_item;115 116 /** Interruptable attached reclaimer thread. */117 struct thread *reclaimer_thr;118 119 /* Some statistics. */120 size_t stat_max_cbs;121 size_t stat_avg_cbs;122 size_t stat_missed_gps;123 size_t stat_missed_gp_in_wait;124 size_t stat_max_slice_cbs;125 size_t last_arriving_cnt;126 } rcu_cpu_data_t;127 128 129 /** RCU related per-thread data. */130 typedef struct rcu_thread_data {131 /** The number of times an RCU reader section is nested.132 *133 * If positive, it is definitely executing reader code. If zero,134 * the thread might already be executing reader code thanks to135 * cpu instruction reordering.136 */137 size_t nesting_cnt;138 139 /** True if the thread was preempted in a reader section.140 *141 * The thread is place into rcu.cur_preempted or rcu.next_preempted142 * and must remove itself in rcu_read_unlock().143 *144 * Access with interrupts disabled.145 */146 bool was_preempted;147 /** Preempted threads link. Access with rcu.prempt_lock.*/148 link_t preempt_link;149 } rcu_thread_data_t;150 42 151 43 … … 201 93 #define rcu_access(ptr) ACCESS_ONCE(ptr) 202 94 203 extern void rcu_read_lock(void); 204 extern void rcu_read_unlock(void); 95 96 97 98 #include <debug.h> 99 #include <preemption.h> 100 #include <cpu.h> 101 #include <proc/thread.h> 102 103 205 104 extern bool rcu_read_locked(void); 206 105 extern void rcu_synchronize(void); … … 224 123 extern void _rcu_synchronize(bool expedite); 225 124 125 126 /* Fwd decl. required by the inlined implementation. Not part of public API. */ 127 extern rcu_gp_t _rcu_cur_gp; 128 extern void _rcu_signal_read_unlock(void); 129 130 131 /** Unconditionally records a quiescent state for the local cpu. */ 132 static inline void _rcu_record_qs(void) 133 { 134 ASSERT(PREEMPTION_DISABLED || interrupts_disabled()); 135 136 /* 137 * A new GP was started since the last time we passed a QS. 138 * Notify the detector we have reached a new QS. 139 */ 140 if (CPU->rcu.last_seen_gp != _rcu_cur_gp) { 141 rcu_gp_t cur_gp = ACCESS_ONCE(_rcu_cur_gp); 142 /* 143 * Contain memory accesses within a reader critical section. 144 * If we are in rcu_lock() it also makes changes prior to the 145 * start of the GP visible in the reader section. 146 */ 147 memory_barrier(); 148 /* 149 * Acknowledge we passed a QS since the beginning of rcu.cur_gp. 150 * Cache coherency will lazily transport the value to the 151 * detector while it sleeps in gp_sleep(). 152 * 153 * Note that there is a theoretical possibility that we 154 * overwrite a more recent/greater last_seen_gp here with 155 * an older/smaller value. If this cpu is interrupted here 156 * while in rcu_lock() reader sections in the interrupt handler 157 * will update last_seen_gp to the same value as is currently 158 * in local cur_gp. However, if the cpu continues processing 159 * interrupts and the detector starts a new GP immediately, 160 * local interrupt handlers may update last_seen_gp again (ie 161 * properly ack the new GP) with a value greater than local cur_gp. 162 * Resetting last_seen_gp to a previous value here is however 163 * benign and we only have to remember that this reader may end up 164 * in cur_preempted even after the GP ends. That is why we 165 * append next_preempted to cur_preempted rather than overwriting 166 * it as if cur_preempted were empty. 167 */ 168 CPU->rcu.last_seen_gp = cur_gp; 169 } 170 } 171 172 /** Delimits the start of an RCU reader critical section. 173 * 174 * Reader sections may be nested and are preemptable. You must not 175 * however block/sleep within reader sections. 176 */ 177 static inline void rcu_read_lock(void) 178 { 179 ASSERT(CPU); 180 preemption_disable(); 181 182 /* Record a QS if not in a reader critical section. */ 183 if (0 == *CPU->rcu.pnesting_cnt) 184 _rcu_record_qs(); 185 186 ++(*CPU->rcu.pnesting_cnt); 187 188 preemption_enable(); 189 } 190 191 /** Delimits the end of an RCU reader critical section. */ 192 static inline void rcu_read_unlock(void) 193 { 194 ASSERT(CPU); 195 preemption_disable(); 196 197 if (0 == --(*CPU->rcu.pnesting_cnt)) { 198 _rcu_record_qs(); 199 200 /* 201 * The thread was preempted while in a critical section or 202 * the detector is eagerly waiting for this cpu's reader 203 * to finish. 204 * 205 * Note that THREAD may be 0 in scheduler() and not just during boot. 206 */ 207 if ((THREAD && THREAD->rcu.was_preempted) || CPU->rcu.is_delaying_gp) { 208 /* Rechecks with disabled interrupts. */ 209 _rcu_signal_read_unlock(); 210 } 211 } 212 213 214 preemption_enable(); 215 } 216 217 226 218 #endif 227 219
Note:
See TracChangeset
for help on using the changeset viewer.