drd/tests/swapcontext: Improve the portability of this test further
[valgrind.git] / drd / tests / annotate_barrier.c
blob592254a6c730a2826db697e498763efa9a26b1bc
1 /*
2 * Test whether all data races are detected in a multithreaded program with
3 * user-annotated barriers. See also pth_barrier.c.
4 */
7 #define _GNU_SOURCE
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. */
24 typedef struct
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;
38 } barrier_t;
40 struct threadinfo
42 int thread_num;
43 barrier_t* b;
44 pthread_t tid;
45 int* array;
46 int iterations;
50 /* Local variables. */
52 static int s_silent;
55 /* Local functions. */
57 static void barrier_init(barrier_t* b, unsigned count)
59 b->thread_count = count;
60 b->wait_count = 0;
61 b->barrier_count = 0;
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)
73 int res;
74 unsigned barrier_count;
76 res = 0;
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;
85 else
87 while (b->barrier_count == barrier_count)
89 #ifndef HAVE_PTHREAD_YIELD
90 /* Darwin doesn't have an implementation of pthread_yield(). */
91 usleep(100 * 1000);
92 #else
93 pthread_yield();
94 #endif
97 ANNOTATE_BARRIER_WAIT_AFTER(b);
98 return res;
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)
107 int i;
108 int* const array = p->array;
109 barrier_t* const b = p->b;
110 if (! s_silent)
111 printf("thread %d iteration 0\n", p->thread_num);
112 barrier_wait(b);
113 for (i = 0; i < p->iterations; i++)
115 if (! s_silent)
116 printf("thread %d iteration %d; writing to %p\n",
117 p->thread_num, i + 1, &array[i]);
118 array[i] = i;
119 barrier_wait(b);
121 return 0;
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 };
128 int i;
129 struct threadinfo* t;
130 barrier_t b;
131 int* array;
133 t = malloc(nthread * sizeof(struct threadinfo));
134 array = malloc(iterations * sizeof(array[0]));
136 if (! s_silent)
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;
144 t[i].b = &b;
145 t[i].array = array;
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);
154 barrier_destroy(&b);
156 free(array);
157 free(t);
160 int main(int argc, char** argv)
162 int nthread;
163 int iterations;
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");
173 return 0;