6363 * Note that this interface is asynchronous.
6464 */
6565
66- #include <errno.h>
6766#include <pthread.h>
6867#include <stdint.h>
6968#include <stdlib.h>
@@ -93,7 +92,6 @@ qsbr_t *qsbr_create(void)
9392 qsbr_t * qs ;
9493 int ret = posix_memalign ((void * * ) & qs , CACHE_LINE_SIZE , sizeof (qsbr_t ));
9594 if (ret != 0 ) {
96- errno = ret ;
9795 return NULL ;
9896 }
9997 memset (qs , 0 , sizeof (qsbr_t ));
@@ -114,17 +112,15 @@ void qsbr_destroy(qsbr_t *qs)
114112 free (qs );
115113}
116114
117- /* qsbr_register: register the current thread for QSBR. */
115+ /* qsbr_register: register the current thread for QSBR */
118116int qsbr_register (qsbr_t * qs )
119117{
120118 qsbr_tls_t * t = pthread_getspecific (qs -> tls_key );
121119 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 )
126123 return -1 ;
127- }
128124 pthread_setspecific (qs -> tls_key , t );
129125 }
130126 memset (t , 0 , sizeof (qsbr_tls_t ));
@@ -193,29 +189,25 @@ bool qsbr_sync(qsbr_t *qs, qsbr_epoch_t target)
193189#include <stdio.h>
194190#include <unistd.h>
195191
196- static unsigned nsec = 10 ; /* seconds */
197-
198192static pthread_barrier_t barrier ;
199193static unsigned n_workers ;
200194static volatile bool stop ;
201195
202196typedef struct {
203197 unsigned int * ptr ;
204198 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 ;
209200
210201#define MAGIC 0xDEADBEEF
211- static unsigned magic_val = MAGIC ;
202+ static const unsigned magic_val = MAGIC ;
212203
213204static qsbr_t * qsbr ;
214205
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 ];
216208static uint64_t destructions ;
217209
218- static void access_obj (data_struct_t * obj )
210+ static void access_obj (data_t * obj )
219211{
220212 if (atomic_load_explicit (& obj -> visible , memory_order_relaxed )) {
221213 atomic_thread_fence (memory_order_acquire );
@@ -224,21 +216,22 @@ static void access_obj(data_struct_t *obj)
224216 }
225217}
226218
227- static void mock_insert_obj ( data_struct_t * obj )
219+ static void insert_obj ( data_t * obj )
228220{
229- obj -> ptr = & magic_val ;
221+ obj -> ptr = ( unsigned int * ) & magic_val ;
230222 assert (!obj -> visible );
231223 atomic_thread_fence (memory_order_release );
232224 atomic_store_explicit (& obj -> visible , true, memory_order_relaxed );
233225}
234226
235- static void mock_remove_obj ( data_struct_t * obj )
227+ static void remove_obj ( data_t * obj )
236228{
237229 assert (obj -> visible );
238- obj -> visible = false;
230+ // obj->visible = false;
231+ atomic_store_explicit (& obj -> visible , false, memory_order_relaxed );
239232}
240233
241- static void mock_destroy_obj ( data_struct_t * obj )
234+ static void destroy_obj ( data_t * obj )
242235{
243236 obj -> ptr = NULL ;
244237 destructions ++ ;
@@ -248,7 +241,7 @@ static void mock_destroy_obj(data_struct_t *obj)
248241
249242static void qsbr_writer (unsigned target )
250243{
251- data_struct_t * obj = & ds [target ];
244+ data_t * obj = & data [target ];
252245
253246 if (obj -> visible ) {
254247 /* The data structure is visible. First, ensure it is no longer
@@ -257,9 +250,9 @@ static void qsbr_writer(unsigned target)
257250 unsigned count = SPINLOCK_BACKOFF_MIN ;
258251 qsbr_epoch_t target_epoch ;
259252
260- mock_remove_obj (obj );
253+ remove_obj (obj );
261254
262- /* QSBR synchronization barrier. */
255+ /* QSBR synchronization barrier */
263256 target_epoch = qsbr_barrier (qsbr );
264257 while (!qsbr_sync (qsbr , target_epoch )) {
265258 SPINLOCK_BACKOFF (count );
@@ -271,12 +264,12 @@ static void qsbr_writer(unsigned target)
271264 }
272265
273266 /* It is safe to "destroy" the object now. */
274- mock_destroy_obj (obj );
267+ destroy_obj (obj );
275268 } else {
276269 /* Data structure is not globally visible. Set the value and make it
277270 * visible (think of the "insert" semantics).
278271 */
279- mock_insert_obj (obj );
272+ insert_obj (obj );
280273 }
281274}
282275
@@ -285,7 +278,8 @@ static void *qsbr_stress(void *arg)
285278 const unsigned id = (uintptr_t ) arg ;
286279 unsigned n = 0 ;
287280
288- qsbr_register (qsbr );
281+ if (qsbr_register (qsbr ) != 0 )
282+ abort ();
289283
290284 /* There are NCPU threads concurrently reading data and a single writer
291285 * thread (ID 0) modifying data. The writer will modify the pointer used
@@ -294,7 +288,7 @@ static void *qsbr_stress(void *arg)
294288 */
295289 pthread_barrier_wait (& barrier );
296290 while (!stop ) {
297- n = (n + 1 ) & (N_DS - 1 );
291+ n = (n + 1 ) & (N_DATA - 1 );
298292 if (id == 0 ) {
299293 qsbr_writer (n );
300294 continue ;
@@ -308,7 +302,7 @@ static void *qsbr_stress(void *arg)
308302 * Incorrect reclamation mechanism would lead to the crash in the
309303 * following pointer dereference.
310304 */
311- access_obj (& ds [n ]);
305+ access_obj (& data [n ]);
312306 qsbr_checkpoint (qsbr );
313307 }
314308 pthread_barrier_wait (& barrier );
@@ -325,12 +319,14 @@ static void leave(int sig)
325319
326320typedef void * (* func_t )(void * );
327321
322+ static unsigned nsec = 10 ; /* seconds */
323+
328324static void run_test (func_t func )
329325{
330326 struct sigaction sigalarm ;
331327
332328 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 ));
334330 pthread_barrier_init (& barrier , NULL , n_workers );
335331 stop = false;
336332
@@ -339,21 +335,22 @@ static void run_test(func_t func)
339335 int ret = sigaction (SIGALRM , & sigalarm , NULL );
340336 assert (ret == 0 );
341337
342- memset (& ds , 0 , sizeof (ds ));
338+ memset (& data , 0 , sizeof (data ));
343339 qsbr = qsbr_create ();
344340 destructions = 0 ;
345341
346342 alarm (nsec ); /* Spin the test */
347343
348344 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 ) {
351347 exit (EXIT_FAILURE );
352348 }
353349 }
354350 for (unsigned i = 0 ; i < n_workers ; i ++ )
355- pthread_join (thr [i ], NULL );
351+ pthread_join (threads [i ], NULL );
356352 pthread_barrier_destroy (& barrier );
353+ free (threads );
357354 printf ("# %" PRIu64 "\n" , destructions );
358355
359356 qsbr_destroy (qsbr );
0 commit comments