File: rcu-api.md

package info (click to toggle)
liburcu 0.15.6-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 8,356 kB
  • sloc: ansic: 23,370; xml: 23,227; sh: 6,480; makefile: 1,045; cpp: 15
file content (273 lines) | stat: -rw-r--r-- 7,624 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
<!--
SPDX-FileCopyrightText: 2023 EfficiOS Inc.

SPDX-License-Identifier: CC-BY-4.0
-->

Userspace RCU API
=================

by Mathieu Desnoyers and Paul E. McKenney


API
---

```c
void rcu_init(void);
```

This must be called before any of the following functions
are invoked.


```c
void rcu_read_lock(void);
```

Begin an RCU read-side critical section. These critical
sections may be nested.


```c
void rcu_read_unlock(void);
```

End an RCU read-side critical section.


```c
void rcu_register_thread(void);
```

Each thread must invoke this function before its first call to
`rcu_read_lock()`. Threads that never call `rcu_read_lock()` need
not invoke this function. In addition, `rcu-bp` ("bullet proof"
RCU) does not require any thread to invoke `rcu_register_thread()`.


```c
void rcu_unregister_thread(void);
```

Each thread that invokes `rcu_register_thread()` must invoke
`rcu_unregister_thread()` before `invoking pthread_exit()`
or before returning from its top-level function.


```c
void synchronize_rcu(void);
```

Wait until every pre-existing RCU read-side critical section
has completed. Note that this primitive will not necessarily
wait for RCU read-side critical sections that have not yet
started: this is not a reader-writer lock. The duration
actually waited is called an RCU grace period.


```c
struct urcu_gp_poll_state start_poll_synchronize_rcu(void);
```

Provides a handle for checking if a new grace period has started
and completed since the handle was obtained. It returns a
`struct urcu_gp_poll_state` handle that can be used with
`poll_state_synchronize_rcu` to check, by polling, if the
associated grace period has completed.

`start_poll_synchronize_rcu` must only be called from
registered RCU read-side threads. For the QSBR flavor, the
caller must be online.


```c
bool poll_state_synchronize_rcu(struct urcu_gp_poll_state state);
```

Checks if the grace period associated with the
`struct urcu_gp_poll_state` handle has completed. If the grace
period has completed, the function returns true. Otherwise,
it returns false.


```c
void call_rcu(struct rcu_head *head,
              void (*func)(struct rcu_head *head));
```

Registers the callback indicated by "head". This means
that `func` will be invoked after the end of a future
RCU grace period. The `rcu_head` structure referenced
by `head` will normally be a field in a larger RCU-protected
structure. A typical implementation of `func` is as
follows:

```c
void func(struct rcu_head *head)
{
    struct foo *p = container_of(head, struct foo, rcu);

    free(p);
}
```

This RCU callback function can be registered as follows
given a pointer `p` to the enclosing structure:

```c
call_rcu(&p->rcu, func);
```

`call_rcu` should be called from registered RCU read-side threads.
For the QSBR flavor, the caller should be online.


```c
void rcu_barrier(void);
```

Wait for all `call_rcu()` work initiated prior to `rcu_barrier()` by
_any_ thread on the system to have completed before `rcu_barrier()`
returns. `rcu_barrier()` should never be called from a `call_rcu()`
thread. This function can be used, for instance, to ensure that
all memory reclaim involving a shared object has completed
before allowing `dlclose()` of this shared object to complete.


```c
struct call_rcu_data *create_call_rcu_data(unsigned long flags,
                                           int cpu_affinity);
```

Returns a handle that can be passed to the following
primitives. The `flags` argument can be zero, or can be
`URCU_CALL_RCU_RT` if the worker threads associated with the
new helper thread are to get real-time response. The argument
`cpu_affinity` specifies a CPU on which the `call_rcu` thread should
be affined to. It is ignored if negative.


```c
void call_rcu_data_free(struct call_rcu_data *crdp);
```

Terminates a `call_rcu()` helper thread and frees its associated
data. The caller must have ensured that this thread is no longer
in use, for example, by passing `NULL` to `set_thread_call_rcu_data()`
and `set_cpu_call_rcu_data()` as required.


```c
struct call_rcu_data *get_default_call_rcu_data(void);
```

Returns the handle for the default `call_rcu()` helper thread.
Creates it if necessary.


```c
struct call_rcu_data *get_cpu_call_rcu_data(int cpu);
```

Returns the handle for the current CPU's `call_rcu()` helper
thread, or `NULL` if the current CPU has no helper thread
currently assigned. The call to this function and use of the
returned `call_rcu_data` should be protected by RCU read-side
lock.


```c
struct call_rcu_data *get_thread_call_rcu_data(void);
```

Returns the handle for the current thread's hard-assigned
`call_rcu()` helper thread, or `NULL` if the current thread is
instead using a per-CPU or the default helper thread.


```c
struct call_rcu_data *get_call_rcu_data(void);
```

Returns the handle for the current thread's `call_rcu()` helper
thread, which is either, in increasing order of preference:
per-thread hard-assigned helper thread, per-CPU helper thread,
or default helper thread. `get_call_rcu_data` should be called
from registered RCU read-side threads. For the QSBR flavor, the
caller should be online.


```c
pthread_t get_call_rcu_thread(struct call_rcu_data *crdp);
```

Returns the helper thread's pthread identifier linked to a call
rcu helper thread data.


```c
void set_thread_call_rcu_data(struct call_rcu_data *crdp);
```

Sets the current thread's hard-assigned `call_rcu()` helper to the
handle specified by `crdp`. Note that `crdp` can be `NULL` to
disassociate this thread from its helper. Once a thread is
disassociated from its helper, further `call_rcu()` invocations
use the current CPU's helper if there is one and the default
helper otherwise.


```c
int set_cpu_call_rcu_data(int cpu, struct call_rcu_data *crdp);
```

Sets the specified CPU's `call_rcu()` helper to the handle
specified by `crdp`. Again, `crdp` can be `NULL` to disassociate
this CPU from its helper thread. Once a CPU has been
disassociated from its helper, further `call_rcu()` invocations
that would otherwise have used this CPU's helper will instead
use the default helper.

The caller must wait for a grace-period to pass between return from
`set_cpu_call_rcu_data()` and call to `call_rcu_data_free()` passing the
previous call rcu data as argument.


```c
int create_all_cpu_call_rcu_data(unsigned long flags);
```

Creates a separate `call_rcu()` helper thread for each CPU.
After this primitive is invoked, the global default `call_rcu()`
helper thread will not be called.

The `set_thread_call_rcu_data()`, `set_cpu_call_rcu_data()`, and
`create_all_cpu_call_rcu_data()` functions may be combined to set up
pretty much any desired association between worker and `call_rcu()`
helper threads. If a given executable calls only `call_rcu()`,
then that executable will have only the single global default
`call_rcu()` helper thread. This will suffice in most cases.


```c
void free_all_cpu_call_rcu_data(void);
```

Clean up all the per-CPU `call_rcu` threads. Should be paired with
`create_all_cpu_call_rcu_data()` to perform teardown. Note that
this function invokes `synchronize_rcu()` internally, so the
caller should be careful not to hold mutexes (or mutexes within a
dependency chain) that are also taken within a RCU read-side
critical section, or in a section where QSBR threads are online.


```c
void call_rcu_before_fork_parent(void);
void call_rcu_after_fork_parent(void);
void call_rcu_after_fork_child(void);
```

Should be used as `pthread_atfork()` handler for programs using
`call_rcu` and performing `fork()` or `clone()` without a following
`exec()`.