63
63
* Note that this interface is asynchronous.
64
64
*/
65
65
66
- #include <errno.h>
67
66
#include <pthread.h>
68
67
#include <stdint.h>
69
68
#include <stdlib.h>
@@ -93,7 +92,6 @@ qsbr_t *qsbr_create(void)
93
92
qsbr_t * qs ;
94
93
int ret = posix_memalign ((void * * ) & qs , CACHE_LINE_SIZE , sizeof (qsbr_t ));
95
94
if (ret != 0 ) {
96
- errno = ret ;
97
95
return NULL ;
98
96
}
99
97
memset (qs , 0 , sizeof (qsbr_t ));
@@ -114,17 +112,15 @@ void qsbr_destroy(qsbr_t *qs)
114
112
free (qs );
115
113
}
116
114
117
- /* qsbr_register: register the current thread for QSBR. */
115
+ /* qsbr_register: register the current thread for QSBR */
118
116
int qsbr_register (qsbr_t * qs )
119
117
{
120
118
qsbr_tls_t * t = pthread_getspecific (qs -> tls_key );
121
119
if (unlikely (!t )) {
122
- int ret =
123
- posix_memalign ((void * * ) & t , CACHE_LINE_SIZE , sizeof (qsbr_tls_t ));
124
- if (ret != 0 ) {
125
- errno = ret ;
120
+ /* posix_memalign() returns zero on success */
121
+ if (posix_memalign ((void * * ) & t , CACHE_LINE_SIZE , sizeof (qsbr_tls_t )) !=
122
+ 0 )
126
123
return -1 ;
127
- }
128
124
pthread_setspecific (qs -> tls_key , t );
129
125
}
130
126
memset (t , 0 , sizeof (qsbr_tls_t ));
@@ -193,29 +189,25 @@ bool qsbr_sync(qsbr_t *qs, qsbr_epoch_t target)
193
189
#include <stdio.h>
194
190
#include <unistd.h>
195
191
196
- static unsigned nsec = 10 ; /* seconds */
197
-
198
192
static pthread_barrier_t barrier ;
199
193
static unsigned n_workers ;
200
194
static volatile bool stop ;
201
195
202
196
typedef struct {
203
197
unsigned int * ptr ;
204
198
bool visible ;
205
- char _pad [CACHE_LINE_SIZE - 8 - 4 - 4 - 8 ];
206
- } data_struct_t ;
207
-
208
- #define N_DS 4
199
+ } __attribute__((__aligned__ (CACHE_LINE_SIZE ))) data_t ;
209
200
210
201
#define MAGIC 0xDEADBEEF
211
- static unsigned magic_val = MAGIC ;
202
+ static const unsigned magic_val = MAGIC ;
212
203
213
204
static qsbr_t * qsbr ;
214
205
215
- static data_struct_t ds [N_DS ] __attribute__((__aligned__ (CACHE_LINE_SIZE )));
206
+ #define N_DATA 4
207
+ static data_t data [N_DATA ];
216
208
static uint64_t destructions ;
217
209
218
- static void access_obj (data_struct_t * obj )
210
+ static void access_obj (data_t * obj )
219
211
{
220
212
if (atomic_load_explicit (& obj -> visible , memory_order_relaxed )) {
221
213
atomic_thread_fence (memory_order_acquire );
@@ -224,21 +216,22 @@ static void access_obj(data_struct_t *obj)
224
216
}
225
217
}
226
218
227
- static void mock_insert_obj ( data_struct_t * obj )
219
+ static void insert_obj ( data_t * obj )
228
220
{
229
- obj -> ptr = & magic_val ;
221
+ obj -> ptr = ( unsigned int * ) & magic_val ;
230
222
assert (!obj -> visible );
231
223
atomic_thread_fence (memory_order_release );
232
224
atomic_store_explicit (& obj -> visible , true, memory_order_relaxed );
233
225
}
234
226
235
- static void mock_remove_obj ( data_struct_t * obj )
227
+ static void remove_obj ( data_t * obj )
236
228
{
237
229
assert (obj -> visible );
238
- obj -> visible = false;
230
+ // obj->visible = false;
231
+ atomic_store_explicit (& obj -> visible , false, memory_order_relaxed );
239
232
}
240
233
241
- static void mock_destroy_obj ( data_struct_t * obj )
234
+ static void destroy_obj ( data_t * obj )
242
235
{
243
236
obj -> ptr = NULL ;
244
237
destructions ++ ;
@@ -248,7 +241,7 @@ static void mock_destroy_obj(data_struct_t *obj)
248
241
249
242
static void qsbr_writer (unsigned target )
250
243
{
251
- data_struct_t * obj = & ds [target ];
244
+ data_t * obj = & data [target ];
252
245
253
246
if (obj -> visible ) {
254
247
/* The data structure is visible. First, ensure it is no longer
@@ -257,9 +250,9 @@ static void qsbr_writer(unsigned target)
257
250
unsigned count = SPINLOCK_BACKOFF_MIN ;
258
251
qsbr_epoch_t target_epoch ;
259
252
260
- mock_remove_obj (obj );
253
+ remove_obj (obj );
261
254
262
- /* QSBR synchronization barrier. */
255
+ /* QSBR synchronization barrier */
263
256
target_epoch = qsbr_barrier (qsbr );
264
257
while (!qsbr_sync (qsbr , target_epoch )) {
265
258
SPINLOCK_BACKOFF (count );
@@ -271,12 +264,12 @@ static void qsbr_writer(unsigned target)
271
264
}
272
265
273
266
/* It is safe to "destroy" the object now. */
274
- mock_destroy_obj (obj );
267
+ destroy_obj (obj );
275
268
} else {
276
269
/* Data structure is not globally visible. Set the value and make it
277
270
* visible (think of the "insert" semantics).
278
271
*/
279
- mock_insert_obj (obj );
272
+ insert_obj (obj );
280
273
}
281
274
}
282
275
@@ -285,7 +278,8 @@ static void *qsbr_stress(void *arg)
285
278
const unsigned id = (uintptr_t ) arg ;
286
279
unsigned n = 0 ;
287
280
288
- qsbr_register (qsbr );
281
+ if (qsbr_register (qsbr ) != 0 )
282
+ abort ();
289
283
290
284
/* There are NCPU threads concurrently reading data and a single writer
291
285
* thread (ID 0) modifying data. The writer will modify the pointer used
@@ -294,7 +288,7 @@ static void *qsbr_stress(void *arg)
294
288
*/
295
289
pthread_barrier_wait (& barrier );
296
290
while (!stop ) {
297
- n = (n + 1 ) & (N_DS - 1 );
291
+ n = (n + 1 ) & (N_DATA - 1 );
298
292
if (id == 0 ) {
299
293
qsbr_writer (n );
300
294
continue ;
@@ -308,7 +302,7 @@ static void *qsbr_stress(void *arg)
308
302
* Incorrect reclamation mechanism would lead to the crash in the
309
303
* following pointer dereference.
310
304
*/
311
- access_obj (& ds [n ]);
305
+ access_obj (& data [n ]);
312
306
qsbr_checkpoint (qsbr );
313
307
}
314
308
pthread_barrier_wait (& barrier );
@@ -325,12 +319,14 @@ static void leave(int sig)
325
319
326
320
typedef void * (* func_t )(void * );
327
321
322
+ static unsigned nsec = 10 ; /* seconds */
323
+
328
324
static void run_test (func_t func )
329
325
{
330
326
struct sigaction sigalarm ;
331
327
332
328
n_workers = sysconf (_SC_NPROCESSORS_CONF );
333
- pthread_t * thr = calloc (n_workers , sizeof (pthread_t ));
329
+ pthread_t * threads = calloc (n_workers , sizeof (pthread_t ));
334
330
pthread_barrier_init (& barrier , NULL , n_workers );
335
331
stop = false;
336
332
@@ -339,21 +335,22 @@ static void run_test(func_t func)
339
335
int ret = sigaction (SIGALRM , & sigalarm , NULL );
340
336
assert (ret == 0 );
341
337
342
- memset (& ds , 0 , sizeof (ds ));
338
+ memset (& data , 0 , sizeof (data ));
343
339
qsbr = qsbr_create ();
344
340
destructions = 0 ;
345
341
346
342
alarm (nsec ); /* Spin the test */
347
343
348
344
for (unsigned i = 0 ; i < n_workers ; i ++ ) {
349
- if (( errno = pthread_create (& thr [i ], NULL , func ,
350
- ( void * ) ( uintptr_t ) i )) != 0 ) {
345
+ if (pthread_create (& threads [i ], NULL , func , ( void * ) ( uintptr_t ) i ) !=
346
+ 0 ) {
351
347
exit (EXIT_FAILURE );
352
348
}
353
349
}
354
350
for (unsigned i = 0 ; i < n_workers ; i ++ )
355
- pthread_join (thr [i ], NULL );
351
+ pthread_join (threads [i ], NULL );
356
352
pthread_barrier_destroy (& barrier );
353
+ free (threads );
357
354
printf ("# %" PRIu64 "\n" , destructions );
358
355
359
356
qsbr_destroy (qsbr );
0 commit comments