source: mainline/kernel/generic/include/synch/rcu.h@ 0cf813d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0cf813d was 0cf813d, checked in by Adam Hraska <adam.hraska+hos@…>, 13 years ago

rcu: Added new statistics. Changed reclaimers to run callbacks with preemption disabled if too many callbacks are pending in order to avoid exhausting system memory.

  • Property mode set to 100644
File size: 6.6 KB
Line 
1/*
2 * Copyright (c) 2012 Adam Hraska
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup sync
30 * @{
31 */
32/** @file
33 */
34
35#ifndef KERN_RCU_H_
36#define KERN_RCU_H_
37
38#include <adt/list.h>
39#include <synch/semaphore.h>
40#include <compiler/barrier.h>
41
42
43/* Fwd decl. */
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 /** 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 to
95 * notice if it missed a grace period end announcement. In that
96 * case it can execute next_cbs without waiting for another GP.
97 *
98 * Invariant: next_cbs_gp >= cur_cbs_gp
99 */
100 rcu_gp_t next_cbs_gp;
101
102 /** This cpu has not yet passed a quiescent state and it is delaying the
103 * 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 /** Interruptable attached reclaimer thread. */
114 struct thread *reclaimer_thr;
115
116 /* Some statistics. */
117 size_t stat_max_cbs;
118 size_t stat_avg_cbs;
119 size_t stat_missed_gps;
120 size_t stat_missed_gp_in_wait;
121 size_t stat_max_slice_cbs;
122 size_t last_arriving_cnt;
123} rcu_cpu_data_t;
124
125
126/** RCU related per-thread data. */
127typedef struct rcu_thread_data {
128 /** The number of times an RCU reader section is nested.
129 *
130 * If positive, it is definitely executing reader code. If zero,
131 * the thread might already be executing reader code thanks to
132 * cpu instruction reordering.
133 */
134 size_t nesting_cnt;
135
136 /** True if the thread was preempted in a reader section.
137 *
138 * The thread is place into rcu.cur_preempted or rcu.next_preempted
139 * and must remove itself in rcu_read_unlock().
140 *
141 * Access with interrupts disabled.
142 */
143 bool was_preempted;
144 /** Preempted threads link. Access with rcu.prempt_lock.*/
145 link_t preempt_link;
146} rcu_thread_data_t;
147
148
149#ifndef member_to_inst
150#define member_to_inst(ptr_member, type, member_identif) \
151 ((type*) (((void*)(ptr_member)) - ((void*)&(((type*)0)->member_identif))))
152#endif
153
154/** Use to assign a pointer to newly initialized data to a rcu reader
155 * accessible pointer.
156 *
157 * Example:
158 * @code
159 * typedef struct exam {
160 * struct exam *next;
161 * int grade;
162 * } exam_t;
163 *
164 * exam_t *exam_list;
165 * // ..
166 *
167 * // Insert at the beginning of the list.
168 * exam_t *my_exam = malloc(sizeof(exam_t), 0);
169 * my_exam->grade = 5;
170 * my_exam->next = exam_list;
171 * rcu_assign(exam_list, my_exam);
172 *
173 * // Changes properly propagate. Every reader either sees
174 * // the old version of exam_list or the new version with
175 * // the fully initialized my_exam.
176 * rcu_synchronize();
177 * // Now we can be sure every reader sees my_exam.
178 *
179 * @endcode
180 */
181#define rcu_assign(ptr, value) \
182 do { \
183 memory_barrier(); \
184 (ptr) = (value); \
185 } while (0)
186
187/** Use to access RCU protected data in a reader section.
188 *
189 * Example:
190 * @code
191 * exam_t *exam_list;
192 * // ...
193 *
194 * rcu_read_lock();
195 * exam_t *first_exam = rcu_access(exam_list);
196 * // We can now safely use first_exam, it won't change
197 * // under us while we're using it.
198 *
199 * // ..
200 * rcu_read_unlock();
201 * @endcode
202 */
203#define rcu_access(ptr) ACCESS_ONCE(ptr)
204
205extern void rcu_read_lock(void);
206extern void rcu_read_unlock(void);
207extern void rcu_synchronize(void);
208extern void rcu_call(rcu_item_t *rcu_item, rcu_func_t func);
209
210extern void rcu_print_stat(void);
211
212extern void rcu_init(void);
213extern void rcu_stop(void);
214extern void rcu_cpu_init(void);
215extern void rcu_kinit_init(void);
216extern void rcu_thread_init(struct thread*);
217extern void rcu_thread_exiting(void);
218extern void rcu_after_thread_ran(void);
219extern void rcu_before_thread_runs(void);
220
221/* Debugging/testing support. Not part of public API. Do not use! */
222extern uint64_t rcu_completed_gps(void);
223extern void _rcu_call(bool expedite, rcu_item_t *rcu_item, rcu_func_t func);
224
225#endif
226
227/** @}
228 */
Note: See TracBrowser for help on using the repository browser.