source: mainline/kernel/generic/include/synch/rcu.h@ 057e77f

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

rcu: Added preemptible RCU's core API implementation.

  • Property mode set to 100644
File size: 6.4 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 /** 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))))
145#endif
146
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
220/** @}
221 */
Note: See TracBrowser for help on using the repository browser.