Lines 1-6
Link Here
|
1 |
/*- |
1 |
/*- |
2 |
* Copyright (c) 2016 Matthew Macy (mmacy@mattmacy.io) |
2 |
* Copyright (c) 2016 Matthew Macy (mmacy@mattmacy.io) |
3 |
* Copyright (c) 2017 Hans Petter Selasky (hselasky@freebsd.org) |
3 |
* Copyright (c) 2017-2020 Hans Petter Selasky (hselasky@freebsd.org) |
4 |
* All rights reserved. |
4 |
* All rights reserved. |
5 |
* |
5 |
* |
6 |
* Redistribution and use in source and binary forms, with or without |
6 |
* Redistribution and use in source and binary forms, with or without |
Lines 90-98
Link Here
|
90 |
*/ |
90 |
*/ |
91 |
CTASSERT(offsetof(struct linux_epoch_record, epoch_record) == 0); |
91 |
CTASSERT(offsetof(struct linux_epoch_record, epoch_record) == 0); |
92 |
|
92 |
|
93 |
static ck_epoch_t linux_epoch; |
93 |
static ck_epoch_t linux_epoch[RCU_TYPE_MAX]; |
94 |
static struct linux_epoch_head linux_epoch_head; |
94 |
static struct linux_epoch_head linux_epoch_head[RCU_TYPE_MAX]; |
95 |
DPCPU_DEFINE_STATIC(struct linux_epoch_record, linux_epoch_record); |
95 |
DPCPU_DEFINE_STATIC(struct linux_epoch_record, linux_epoch_record[RCU_TYPE_MAX]); |
96 |
|
96 |
|
97 |
static void linux_rcu_cleaner_func(void *, int); |
97 |
static void linux_rcu_cleaner_func(void *, int); |
98 |
|
98 |
|
Lines 101-123
Link Here
|
101 |
{ |
101 |
{ |
102 |
struct linux_epoch_head *head; |
102 |
struct linux_epoch_head *head; |
103 |
int i; |
103 |
int i; |
|
|
104 |
int j; |
104 |
|
105 |
|
105 |
ck_epoch_init(&linux_epoch); |
106 |
for (j = 0; j != RCU_TYPE_MAX; j++) { |
|
|
107 |
ck_epoch_init(&linux_epoch[j]); |
106 |
|
108 |
|
107 |
head = &linux_epoch_head; |
109 |
head = &linux_epoch_head[j]; |
108 |
|
110 |
|
109 |
mtx_init(&head->lock, "LRCU-HEAD", NULL, MTX_DEF); |
111 |
mtx_init(&head->lock, "LRCU-HEAD", NULL, MTX_DEF); |
110 |
TASK_INIT(&head->task, 0, linux_rcu_cleaner_func, NULL); |
112 |
TASK_INIT(&head->task, 0, linux_rcu_cleaner_func, head); |
111 |
STAILQ_INIT(&head->cb_head); |
113 |
STAILQ_INIT(&head->cb_head); |
112 |
|
114 |
|
113 |
CPU_FOREACH(i) { |
115 |
CPU_FOREACH(i) { |
114 |
struct linux_epoch_record *record; |
116 |
struct linux_epoch_record *record; |
115 |
|
117 |
|
116 |
record = &DPCPU_ID_GET(i, linux_epoch_record); |
118 |
record = &DPCPU_ID_GET(i, linux_epoch_record[j]); |
117 |
|
119 |
|
118 |
record->cpuid = i; |
120 |
record->cpuid = i; |
119 |
ck_epoch_register(&linux_epoch, &record->epoch_record, NULL); |
121 |
ck_epoch_register(&linux_epoch[j], |
120 |
TAILQ_INIT(&record->ts_head); |
122 |
&record->epoch_record, NULL); |
|
|
123 |
TAILQ_INIT(&record->ts_head); |
124 |
} |
121 |
} |
125 |
} |
122 |
} |
126 |
} |
123 |
SYSINIT(linux_rcu_runtime, SI_SUB_CPU, SI_ORDER_ANY, linux_rcu_runtime_init, NULL); |
127 |
SYSINIT(linux_rcu_runtime, SI_SUB_CPU, SI_ORDER_ANY, linux_rcu_runtime_init, NULL); |
Lines 126-141
Link Here
|
126 |
linux_rcu_runtime_uninit(void *arg __unused) |
130 |
linux_rcu_runtime_uninit(void *arg __unused) |
127 |
{ |
131 |
{ |
128 |
struct linux_epoch_head *head; |
132 |
struct linux_epoch_head *head; |
|
|
133 |
int j; |
129 |
|
134 |
|
130 |
head = &linux_epoch_head; |
135 |
for (j = 0; j != RCU_TYPE_MAX; j++) { |
|
|
136 |
head = &linux_epoch_head[j]; |
131 |
|
137 |
|
132 |
/* destroy head lock */ |
138 |
/* destroy head lock */ |
133 |
mtx_destroy(&head->lock); |
139 |
mtx_destroy(&head->lock); |
|
|
140 |
} |
134 |
} |
141 |
} |
135 |
SYSUNINIT(linux_rcu_runtime, SI_SUB_LOCK, SI_ORDER_SECOND, linux_rcu_runtime_uninit, NULL); |
142 |
SYSUNINIT(linux_rcu_runtime, SI_SUB_LOCK, SI_ORDER_SECOND, linux_rcu_runtime_uninit, NULL); |
136 |
|
143 |
|
137 |
static void |
144 |
static void |
138 |
linux_rcu_cleaner_func(void *context __unused, int pending __unused) |
145 |
linux_rcu_cleaner_func(void *context, int pending __unused) |
139 |
{ |
146 |
{ |
140 |
struct linux_epoch_head *head; |
147 |
struct linux_epoch_head *head; |
141 |
struct callback_head *rcu; |
148 |
struct callback_head *rcu; |
Lines 143-149
Link Here
|
143 |
|
150 |
|
144 |
linux_set_current(curthread); |
151 |
linux_set_current(curthread); |
145 |
|
152 |
|
146 |
head = &linux_epoch_head; |
153 |
head = context; |
147 |
|
154 |
|
148 |
/* move current callbacks into own queue */ |
155 |
/* move current callbacks into own queue */ |
149 |
mtx_lock(&head->lock); |
156 |
mtx_lock(&head->lock); |
Lines 152-158
Link Here
|
152 |
mtx_unlock(&head->lock); |
159 |
mtx_unlock(&head->lock); |
153 |
|
160 |
|
154 |
/* synchronize */ |
161 |
/* synchronize */ |
155 |
linux_synchronize_rcu(); |
162 |
linux_synchronize_rcu(head - linux_epoch_head); |
156 |
|
163 |
|
157 |
/* dispatch all callbacks, if any */ |
164 |
/* dispatch all callbacks, if any */ |
158 |
while ((rcu = STAILQ_FIRST(&tmp_head)) != NULL) { |
165 |
while ((rcu = STAILQ_FIRST(&tmp_head)) != NULL) { |
Lines 170-176
Link Here
|
170 |
} |
177 |
} |
171 |
|
178 |
|
172 |
void |
179 |
void |
173 |
linux_rcu_read_lock(void) |
180 |
linux_rcu_read_lock(unsigned type) |
174 |
{ |
181 |
{ |
175 |
struct linux_epoch_record *record; |
182 |
struct linux_epoch_record *record; |
176 |
struct task_struct *ts; |
183 |
struct task_struct *ts; |
Lines 184-190
Link Here
|
184 |
*/ |
191 |
*/ |
185 |
sched_pin(); |
192 |
sched_pin(); |
186 |
|
193 |
|
187 |
record = &DPCPU_GET(linux_epoch_record); |
194 |
record = &DPCPU_GET(linux_epoch_record[type]); |
188 |
ts = current; |
195 |
ts = current; |
189 |
|
196 |
|
190 |
/* |
197 |
/* |
Lines 200-206
Link Here
|
200 |
} |
207 |
} |
201 |
|
208 |
|
202 |
void |
209 |
void |
203 |
linux_rcu_read_unlock(void) |
210 |
linux_rcu_read_unlock(unsigned type) |
204 |
{ |
211 |
{ |
205 |
struct linux_epoch_record *record; |
212 |
struct linux_epoch_record *record; |
206 |
struct task_struct *ts; |
213 |
struct task_struct *ts; |
Lines 208-214
Link Here
|
208 |
if (RCU_SKIP()) |
215 |
if (RCU_SKIP()) |
209 |
return; |
216 |
return; |
210 |
|
217 |
|
211 |
record = &DPCPU_GET(linux_epoch_record); |
218 |
record = &DPCPU_GET(linux_epoch_record[type]); |
212 |
ts = current; |
219 |
ts = current; |
213 |
|
220 |
|
214 |
/* |
221 |
/* |
Lines 283-289
Link Here
|
283 |
} |
290 |
} |
284 |
|
291 |
|
285 |
void |
292 |
void |
286 |
linux_synchronize_rcu(void) |
293 |
linux_synchronize_rcu(unsigned type) |
287 |
{ |
294 |
{ |
288 |
struct thread *td; |
295 |
struct thread *td; |
289 |
int was_bound; |
296 |
int was_bound; |
Lines 314-320
Link Here
|
314 |
td->td_pinned = 0; |
321 |
td->td_pinned = 0; |
315 |
sched_bind(td, old_cpu); |
322 |
sched_bind(td, old_cpu); |
316 |
|
323 |
|
317 |
ck_epoch_synchronize_wait(&linux_epoch, |
324 |
ck_epoch_synchronize_wait(&linux_epoch[type], |
318 |
&linux_synchronize_rcu_cb, NULL); |
325 |
&linux_synchronize_rcu_cb, NULL); |
319 |
|
326 |
|
320 |
/* restore CPU binding, if any */ |
327 |
/* restore CPU binding, if any */ |
Lines 337-349
Link Here
|
337 |
} |
344 |
} |
338 |
|
345 |
|
339 |
void |
346 |
void |
340 |
linux_rcu_barrier(void) |
347 |
linux_rcu_barrier(unsigned type) |
341 |
{ |
348 |
{ |
342 |
struct linux_epoch_head *head; |
349 |
struct linux_epoch_head *head; |
343 |
|
350 |
|
344 |
linux_synchronize_rcu(); |
351 |
linux_synchronize_rcu(type); |
345 |
|
352 |
|
346 |
head = &linux_epoch_head; |
353 |
head = &linux_epoch_head[type]; |
347 |
|
354 |
|
348 |
/* wait for callbacks to complete */ |
355 |
/* wait for callbacks to complete */ |
349 |
taskqueue_drain(taskqueue_fast, &head->task); |
356 |
taskqueue_drain(taskqueue_fast, &head->task); |
Lines 350-359
Link Here
|
350 |
} |
357 |
} |
351 |
|
358 |
|
352 |
void |
359 |
void |
353 |
linux_call_rcu(struct rcu_head *context, rcu_callback_t func) |
360 |
linux_call_rcu(unsigned type, struct rcu_head *context, rcu_callback_t func) |
354 |
{ |
361 |
{ |
355 |
struct callback_head *rcu = (struct callback_head *)context; |
362 |
struct callback_head *rcu = (struct callback_head *)context; |
356 |
struct linux_epoch_head *head = &linux_epoch_head; |
363 |
struct linux_epoch_head *head = &linux_epoch_head[type]; |
357 |
|
364 |
|
358 |
mtx_lock(&head->lock); |
365 |
mtx_lock(&head->lock); |
359 |
rcu->func = func; |
366 |
rcu->func = func; |
Lines 376-382
Link Here
|
376 |
int |
383 |
int |
377 |
srcu_read_lock(struct srcu_struct *srcu) |
384 |
srcu_read_lock(struct srcu_struct *srcu) |
378 |
{ |
385 |
{ |
379 |
linux_rcu_read_lock(); |
386 |
linux_rcu_read_lock(RCU_TYPE_SLEEPABLE); |
380 |
return (0); |
387 |
return (0); |
381 |
} |
388 |
} |
382 |
|
389 |
|
Lines 383-399
Link Here
|
383 |
void |
390 |
void |
384 |
srcu_read_unlock(struct srcu_struct *srcu, int key __unused) |
391 |
srcu_read_unlock(struct srcu_struct *srcu, int key __unused) |
385 |
{ |
392 |
{ |
386 |
linux_rcu_read_unlock(); |
393 |
linux_rcu_read_unlock(RCU_TYPE_SLEEPABLE); |
387 |
} |
394 |
} |
388 |
|
395 |
|
389 |
void |
396 |
void |
390 |
synchronize_srcu(struct srcu_struct *srcu) |
397 |
synchronize_srcu(struct srcu_struct *srcu) |
391 |
{ |
398 |
{ |
392 |
linux_synchronize_rcu(); |
399 |
linux_synchronize_rcu(RCU_TYPE_SLEEPABLE); |
393 |
} |
400 |
} |
394 |
|
401 |
|
395 |
void |
402 |
void |
396 |
srcu_barrier(struct srcu_struct *srcu) |
403 |
srcu_barrier(struct srcu_struct *srcu) |
397 |
{ |
404 |
{ |
398 |
linux_rcu_barrier(); |
405 |
linux_rcu_barrier(RCU_TYPE_SLEEPABLE); |
399 |
} |
406 |
} |