2 * Test whether all data races are detected in a multithreaded program with
3 * user-annotated barriers. See also pth_barrier.c.
10 #include <pthread.h> /* pthread_create() */
11 #include <stdio.h> /* fprintf() */
12 #include <stdlib.h> /* atoi() */
13 #include <string.h> /* memset() */
14 #include <unistd.h> /* usleep() */
15 #include "../../drd/drd.h"
16 #include "../../config.h"
19 #define BARRIER_SERIAL_THREAD -1
22 /* Local datatypes. */
27 * number of threads that must call barrier_wait() before any of them
28 * successfully return from the call.
30 unsigned thread_count
;
31 /* number of barrier_wait() calls since last barrier. */
32 volatile unsigned wait_count
;
34 * barrier count. Only the least significant bit matters -- a single bit
35 * counter would be sufficient.
37 volatile unsigned barrier_count
;
50 /* Local variables. */
55 /* Local functions. */
57 static void barrier_init(barrier_t
* b
, unsigned count
)
59 b
->thread_count
= count
;
62 ANNOTATE_BARRIER_INIT(b
, count
, 0);
65 static void barrier_destroy(barrier_t
* b
)
67 ANNOTATE_BARRIER_DESTROY(b
);
68 memset(b
, 0, sizeof(*b
));
71 static int barrier_wait(barrier_t
* b
)
74 unsigned barrier_count
;
77 ANNOTATE_BARRIER_WAIT_BEFORE(b
);
78 barrier_count
= b
->barrier_count
;
79 if (__sync_add_and_fetch(&b
->wait_count
, 1) == b
->thread_count
)
81 __sync_sub_and_fetch(&b
->wait_count
, b
->thread_count
);
82 __sync_add_and_fetch(&b
->barrier_count
, 1);
83 res
= BARRIER_SERIAL_THREAD
;
87 while (b
->barrier_count
== barrier_count
)
89 #ifndef HAVE_PTHREAD_YIELD
90 /* Darwin doesn't have an implementation of pthread_yield(). */
97 ANNOTATE_BARRIER_WAIT_AFTER(b
);
102 * Single thread, which touches p->iterations elements of array p->array.
103 * Each modification of an element of p->array is a data race.
105 static void* threadfunc(struct threadinfo
* p
)
108 int* const array
= p
->array
;
109 barrier_t
* const b
= p
->b
;
111 printf("thread %d iteration 0\n", p
->thread_num
);
113 for (i
= 0; i
< p
->iterations
; i
++)
116 printf("thread %d iteration %d; writing to %p\n",
117 p
->thread_num
, i
+ 1, &array
[i
]);
124 /* Actual test, consisting of nthread threads. */
125 static void barriers_and_races(const int nthread
, const int iterations
)
127 const struct timespec delay
= { 0, 100 * 1000 * 1000 };
129 struct threadinfo
* t
;
133 t
= malloc(nthread
* sizeof(struct threadinfo
));
134 array
= malloc(iterations
* sizeof(array
[0]));
137 printf("&array[0] = %p\n", array
);
139 barrier_init(&b
, nthread
);
141 for (i
= 0; i
< nthread
; i
++)
143 t
[i
].thread_num
= i
+ 1;
146 t
[i
].iterations
= iterations
;
147 pthread_create(&t
[i
].tid
, 0, (void*(*)(void*))threadfunc
, &t
[i
]);
148 nanosleep(&delay
, 0);
151 for (i
= 0; i
< nthread
; i
++)
152 pthread_join(t
[i
].tid
, 0);
160 int main(int argc
, char** argv
)
165 nthread
= (argc
> 1) ? atoi(argv
[1]) : 2;
166 iterations
= (argc
> 2) ? atoi(argv
[2]) : 3;
167 s_silent
= (argc
> 3) ? atoi(argv
[3]) : 0;
169 barriers_and_races(nthread
, iterations
);
171 fprintf(stderr
, "Done.\n");