Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/contrib/ck/include/ck_rwcohort.h
48255 views
1
/*
2
* Copyright 2013-2015 Samy Al Bahra.
3
* Copyright 2013 Brendon Scheinman.
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
* 1. Redistributions of source code must retain the above copyright
10
* notice, this list of conditions and the following disclaimer.
11
* 2. 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
*
15
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25
* SUCH DAMAGE.
26
*/
27
28
#ifndef CK_RWCOHORT_H
29
#define CK_RWCOHORT_H
30
31
/*
32
* This is an implementation of NUMA-aware reader-writer locks as described in:
33
* Calciu, I.; Dice, D.; Lev, Y.; Luchangco, V.; Marathe, V.; and Shavit, N. 2014.
34
* NUMA-Aware Reader-Writer Locks
35
*/
36
37
#include <ck_cc.h>
38
#include <ck_pr.h>
39
#include <ck_stddef.h>
40
#include <ck_cohort.h>
41
42
#define CK_RWCOHORT_WP_NAME(N) ck_rwcohort_wp_##N
43
#define CK_RWCOHORT_WP_INSTANCE(N) struct CK_RWCOHORT_WP_NAME(N)
44
#define CK_RWCOHORT_WP_INIT(N, RW, WL) ck_rwcohort_wp_##N##_init(RW, WL)
45
#define CK_RWCOHORT_WP_READ_LOCK(N, RW, C, GC, LC) \
46
ck_rwcohort_wp_##N##_read_lock(RW, C, GC, LC)
47
#define CK_RWCOHORT_WP_READ_UNLOCK(N, RW, C, GC, LC) \
48
ck_rwcohort_wp_##N##_read_unlock(RW)
49
#define CK_RWCOHORT_WP_WRITE_LOCK(N, RW, C, GC, LC) \
50
ck_rwcohort_wp_##N##_write_lock(RW, C, GC, LC)
51
#define CK_RWCOHORT_WP_WRITE_UNLOCK(N, RW, C, GC, LC) \
52
ck_rwcohort_wp_##N##_write_unlock(RW, C, GC, LC)
53
#define CK_RWCOHORT_WP_DEFAULT_WAIT_LIMIT 1000
54
55
#define CK_RWCOHORT_WP_PROTOTYPE(N) \
56
CK_RWCOHORT_WP_INSTANCE(N) { \
57
unsigned int read_counter; \
58
unsigned int write_barrier; \
59
unsigned int wait_limit; \
60
}; \
61
CK_CC_INLINE static void \
62
ck_rwcohort_wp_##N##_init(CK_RWCOHORT_WP_INSTANCE(N) *rw_cohort, \
63
unsigned int wait_limit) \
64
{ \
65
\
66
rw_cohort->read_counter = 0; \
67
rw_cohort->write_barrier = 0; \
68
rw_cohort->wait_limit = wait_limit; \
69
ck_pr_barrier(); \
70
return; \
71
} \
72
CK_CC_INLINE static void \
73
ck_rwcohort_wp_##N##_write_lock(CK_RWCOHORT_WP_INSTANCE(N) *rw_cohort, \
74
CK_COHORT_INSTANCE(N) *cohort, void *global_context, \
75
void *local_context) \
76
{ \
77
\
78
while (ck_pr_load_uint(&rw_cohort->write_barrier) > 0) \
79
ck_pr_stall(); \
80
\
81
CK_COHORT_LOCK(N, cohort, global_context, local_context); \
82
\
83
while (ck_pr_load_uint(&rw_cohort->read_counter) > 0) \
84
ck_pr_stall(); \
85
\
86
return; \
87
} \
88
CK_CC_INLINE static void \
89
ck_rwcohort_wp_##N##_write_unlock(CK_RWCOHORT_WP_INSTANCE(N) *rw_cohort, \
90
CK_COHORT_INSTANCE(N) *cohort, void *global_context, \
91
void *local_context) \
92
{ \
93
\
94
(void)rw_cohort; \
95
CK_COHORT_UNLOCK(N, cohort, global_context, local_context); \
96
return; \
97
} \
98
CK_CC_INLINE static void \
99
ck_rwcohort_wp_##N##_read_lock(CK_RWCOHORT_WP_INSTANCE(N) *rw_cohort, \
100
CK_COHORT_INSTANCE(N) *cohort, void *global_context, \
101
void *local_context) \
102
{ \
103
unsigned int wait_count = 0; \
104
bool raised = false; \
105
\
106
for (;;) { \
107
ck_pr_inc_uint(&rw_cohort->read_counter); \
108
ck_pr_fence_atomic_load(); \
109
if (CK_COHORT_LOCKED(N, cohort, global_context, \
110
local_context) == false) \
111
break; \
112
\
113
ck_pr_dec_uint(&rw_cohort->read_counter); \
114
while (CK_COHORT_LOCKED(N, cohort, global_context, \
115
local_context) == true) { \
116
ck_pr_stall(); \
117
if (++wait_count > rw_cohort->wait_limit && \
118
raised == false) { \
119
ck_pr_inc_uint(&rw_cohort->write_barrier); \
120
raised = true; \
121
} \
122
} \
123
} \
124
\
125
if (raised == true) \
126
ck_pr_dec_uint(&rw_cohort->write_barrier); \
127
\
128
ck_pr_fence_load(); \
129
return; \
130
} \
131
CK_CC_INLINE static void \
132
ck_rwcohort_wp_##N##_read_unlock(CK_RWCOHORT_WP_INSTANCE(N) *cohort) \
133
{ \
134
\
135
ck_pr_fence_load_atomic(); \
136
ck_pr_dec_uint(&cohort->read_counter); \
137
return; \
138
}
139
140
#define CK_RWCOHORT_WP_INITIALIZER { \
141
.read_counter = 0, \
142
.write_barrier = 0, \
143
.wait_limit = 0 \
144
}
145
146
#define CK_RWCOHORT_RP_NAME(N) ck_rwcohort_rp_##N
147
#define CK_RWCOHORT_RP_INSTANCE(N) struct CK_RWCOHORT_RP_NAME(N)
148
#define CK_RWCOHORT_RP_INIT(N, RW, WL) ck_rwcohort_rp_##N##_init(RW, WL)
149
#define CK_RWCOHORT_RP_READ_LOCK(N, RW, C, GC, LC) \
150
ck_rwcohort_rp_##N##_read_lock(RW, C, GC, LC)
151
#define CK_RWCOHORT_RP_READ_UNLOCK(N, RW, C, GC, LC) \
152
ck_rwcohort_rp_##N##_read_unlock(RW)
153
#define CK_RWCOHORT_RP_WRITE_LOCK(N, RW, C, GC, LC) \
154
ck_rwcohort_rp_##N##_write_lock(RW, C, GC, LC)
155
#define CK_RWCOHORT_RP_WRITE_UNLOCK(N, RW, C, GC, LC) \
156
ck_rwcohort_rp_##N##_write_unlock(RW, C, GC, LC)
157
#define CK_RWCOHORT_RP_DEFAULT_WAIT_LIMIT 1000
158
159
#define CK_RWCOHORT_RP_PROTOTYPE(N) \
160
CK_RWCOHORT_RP_INSTANCE(N) { \
161
unsigned int read_counter; \
162
unsigned int read_barrier; \
163
unsigned int wait_limit; \
164
}; \
165
CK_CC_INLINE static void \
166
ck_rwcohort_rp_##N##_init(CK_RWCOHORT_RP_INSTANCE(N) *rw_cohort, \
167
unsigned int wait_limit) \
168
{ \
169
\
170
rw_cohort->read_counter = 0; \
171
rw_cohort->read_barrier = 0; \
172
rw_cohort->wait_limit = wait_limit; \
173
ck_pr_barrier(); \
174
return; \
175
} \
176
CK_CC_INLINE static void \
177
ck_rwcohort_rp_##N##_write_lock(CK_RWCOHORT_RP_INSTANCE(N) *rw_cohort, \
178
CK_COHORT_INSTANCE(N) *cohort, void *global_context, \
179
void *local_context) \
180
{ \
181
unsigned int wait_count = 0; \
182
bool raised = false; \
183
\
184
for (;;) { \
185
CK_COHORT_LOCK(N, cohort, global_context, local_context); \
186
if (ck_pr_load_uint(&rw_cohort->read_counter) == 0) \
187
break; \
188
\
189
CK_COHORT_UNLOCK(N, cohort, global_context, local_context); \
190
while (ck_pr_load_uint(&rw_cohort->read_counter) > 0) { \
191
ck_pr_stall(); \
192
if (++wait_count > rw_cohort->wait_limit && \
193
raised == false) { \
194
ck_pr_inc_uint(&rw_cohort->read_barrier); \
195
raised = true; \
196
} \
197
} \
198
} \
199
\
200
if (raised == true) \
201
ck_pr_dec_uint(&rw_cohort->read_barrier); \
202
\
203
return; \
204
} \
205
CK_CC_INLINE static void \
206
ck_rwcohort_rp_##N##_write_unlock(CK_RWCOHORT_RP_INSTANCE(N) *rw_cohort, \
207
CK_COHORT_INSTANCE(N) *cohort, void *global_context, void *local_context) \
208
{ \
209
\
210
(void)rw_cohort; \
211
CK_COHORT_UNLOCK(N, cohort, global_context, local_context); \
212
return; \
213
} \
214
CK_CC_INLINE static void \
215
ck_rwcohort_rp_##N##_read_lock(CK_RWCOHORT_RP_INSTANCE(N) *rw_cohort, \
216
CK_COHORT_INSTANCE(N) *cohort, void *global_context, \
217
void *local_context) \
218
{ \
219
\
220
while (ck_pr_load_uint(&rw_cohort->read_barrier) > 0) \
221
ck_pr_stall(); \
222
\
223
ck_pr_inc_uint(&rw_cohort->read_counter); \
224
ck_pr_fence_atomic_load(); \
225
\
226
while (CK_COHORT_LOCKED(N, cohort, global_context, \
227
local_context) == true) \
228
ck_pr_stall(); \
229
\
230
return; \
231
} \
232
CK_CC_INLINE static void \
233
ck_rwcohort_rp_##N##_read_unlock(CK_RWCOHORT_RP_INSTANCE(N) *cohort) \
234
{ \
235
\
236
ck_pr_fence_load_atomic(); \
237
ck_pr_dec_uint(&cohort->read_counter); \
238
return; \
239
}
240
241
#define CK_RWCOHORT_RP_INITIALIZER { \
242
.read_counter = 0, \
243
.read_barrier = 0, \
244
.wait_limit = 0 \
245
}
246
247
#define CK_RWCOHORT_NEUTRAL_NAME(N) ck_rwcohort_neutral_##N
248
#define CK_RWCOHORT_NEUTRAL_INSTANCE(N) struct CK_RWCOHORT_NEUTRAL_NAME(N)
249
#define CK_RWCOHORT_NEUTRAL_INIT(N, RW) ck_rwcohort_neutral_##N##_init(RW)
250
#define CK_RWCOHORT_NEUTRAL_READ_LOCK(N, RW, C, GC, LC) \
251
ck_rwcohort_neutral_##N##_read_lock(RW, C, GC, LC)
252
#define CK_RWCOHORT_NEUTRAL_READ_UNLOCK(N, RW, C, GC, LC) \
253
ck_rwcohort_neutral_##N##_read_unlock(RW)
254
#define CK_RWCOHORT_NEUTRAL_WRITE_LOCK(N, RW, C, GC, LC) \
255
ck_rwcohort_neutral_##N##_write_lock(RW, C, GC, LC)
256
#define CK_RWCOHORT_NEUTRAL_WRITE_UNLOCK(N, RW, C, GC, LC) \
257
ck_rwcohort_neutral_##N##_write_unlock(RW, C, GC, LC)
258
#define CK_RWCOHORT_NEUTRAL_DEFAULT_WAIT_LIMIT 1000
259
260
#define CK_RWCOHORT_NEUTRAL_PROTOTYPE(N) \
261
CK_RWCOHORT_NEUTRAL_INSTANCE(N) { \
262
unsigned int read_counter; \
263
}; \
264
CK_CC_INLINE static void \
265
ck_rwcohort_neutral_##N##_init(CK_RWCOHORT_NEUTRAL_INSTANCE(N) *rw_cohort) \
266
{ \
267
\
268
rw_cohort->read_counter = 0; \
269
ck_pr_barrier(); \
270
return; \
271
} \
272
CK_CC_INLINE static void \
273
ck_rwcohort_neutral_##N##_write_lock(CK_RWCOHORT_NEUTRAL_INSTANCE(N) *rw_cohort,\
274
CK_COHORT_INSTANCE(N) *cohort, void *global_context, \
275
void *local_context) \
276
{ \
277
\
278
CK_COHORT_LOCK(N, cohort, global_context, local_context); \
279
while (ck_pr_load_uint(&rw_cohort->read_counter) > 0) { \
280
ck_pr_stall(); \
281
} \
282
return; \
283
} \
284
CK_CC_INLINE static void \
285
ck_rwcohort_neutral_##N##_write_unlock(CK_RWCOHORT_NEUTRAL_INSTANCE(N) *rw_cohort,\
286
CK_COHORT_INSTANCE(N) *cohort, void *global_context, void *local_context) \
287
{ \
288
\
289
(void)rw_cohort; \
290
CK_COHORT_UNLOCK(N, cohort, global_context, local_context); \
291
return; \
292
} \
293
CK_CC_INLINE static void \
294
ck_rwcohort_neutral_##N##_read_lock(CK_RWCOHORT_NEUTRAL_INSTANCE(N) *rw_cohort, \
295
CK_COHORT_INSTANCE(N) *cohort, void *global_context, \
296
void *local_context) \
297
{ \
298
\
299
CK_COHORT_LOCK(N, cohort, global_context, local_context); \
300
ck_pr_inc_uint(&rw_cohort->read_counter); \
301
CK_COHORT_UNLOCK(N, cohort, global_context, local_context); \
302
return; \
303
} \
304
CK_CC_INLINE static void \
305
ck_rwcohort_neutral_##N##_read_unlock(CK_RWCOHORT_NEUTRAL_INSTANCE(N) *cohort) \
306
{ \
307
\
308
ck_pr_fence_load_atomic(); \
309
ck_pr_dec_uint(&cohort->read_counter); \
310
return; \
311
}
312
313
#define CK_RWCOHORT_NEUTRAL_INITIALIZER { \
314
.read_counter = 0, \
315
}
316
317
#endif /* CK_RWCOHORT_H */
318
319