blob: 592254a6c730a2826db697e498763efa9a26b1bc [file] [log] [blame]
bartea2a03c2010-03-21 17:24:47 +00001/*
2 * Test whether all data races are detected in a multithreaded program with
3 * user-annotated barriers. See also pth_barrier.c.
4 */
5
6
7#define _GNU_SOURCE
8
9
10#include <pthread.h> /* pthread_create() */
11#include <stdio.h> /* fprintf() */
12#include <stdlib.h> /* atoi() */
13#include <string.h> /* memset() */
bart422b7792010-04-29 16:05:54 +000014#include <unistd.h> /* usleep() */
bartea2a03c2010-03-21 17:24:47 +000015#include "../../drd/drd.h"
bart0ccdc4a2010-04-29 06:28:43 +000016#include "../../config.h"
bartea2a03c2010-03-21 17:24:47 +000017
18
bartec2e1462010-04-01 10:20:02 +000019#define BARRIER_SERIAL_THREAD -1
20
21
bartea2a03c2010-03-21 17:24:47 +000022/* Local datatypes. */
23
24typedef struct
25{
26 /*
27 * number of threads that must call barrier_wait() before any of them
28 * successfully return from the call.
29 */
30 unsigned thread_count;
31 /* number of barrier_wait() calls since last barrier. */
32 volatile unsigned wait_count;
33 /*
34 * barrier count. Only the least significant bit matters -- a single bit
35 * counter would be sufficient.
36 */
37 volatile unsigned barrier_count;
38} barrier_t;
39
40struct threadinfo
41{
bart422b7792010-04-29 16:05:54 +000042 int thread_num;
bartea2a03c2010-03-21 17:24:47 +000043 barrier_t* b;
44 pthread_t tid;
45 int* array;
46 int iterations;
47};
48
49
50/* Local variables. */
51
52static int s_silent;
53
54
55/* Local functions. */
56
57static void barrier_init(barrier_t* b, unsigned count)
58{
59 b->thread_count = count;
60 b->wait_count = 0;
61 b->barrier_count = 0;
62 ANNOTATE_BARRIER_INIT(b, count, 0);
63}
64
65static void barrier_destroy(barrier_t* b)
66{
67 ANNOTATE_BARRIER_DESTROY(b);
68 memset(b, 0, sizeof(*b));
69}
70
71static int barrier_wait(barrier_t* b)
72{
73 int res;
74 unsigned barrier_count;
75
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)
80 {
81 __sync_sub_and_fetch(&b->wait_count, b->thread_count);
82 __sync_add_and_fetch(&b->barrier_count, 1);
bartec2e1462010-04-01 10:20:02 +000083 res = BARRIER_SERIAL_THREAD;
bartea2a03c2010-03-21 17:24:47 +000084 }
85 else
86 {
87 while (b->barrier_count == barrier_count)
bart9ec8b072010-04-02 10:27:35 +000088 {
bart0ccdc4a2010-04-29 06:28:43 +000089#ifndef HAVE_PTHREAD_YIELD
bart9ec8b072010-04-02 10:27:35 +000090 /* Darwin doesn't have an implementation of pthread_yield(). */
91 usleep(100 * 1000);
92#else
bartea2a03c2010-03-21 17:24:47 +000093 pthread_yield();
bart9ec8b072010-04-02 10:27:35 +000094#endif
95 }
bartea2a03c2010-03-21 17:24:47 +000096 }
97 ANNOTATE_BARRIER_WAIT_AFTER(b);
98 return res;
99}
100
101/*
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.
104 */
105static void* threadfunc(struct threadinfo* p)
106{
107 int i;
108 int* const array = p->array;
109 barrier_t* const b = p->b;
110 if (! s_silent)
bart422b7792010-04-29 16:05:54 +0000111 printf("thread %d iteration 0\n", p->thread_num);
bartea2a03c2010-03-21 17:24:47 +0000112 barrier_wait(b);
113 for (i = 0; i < p->iterations; i++)
114 {
115 if (! s_silent)
bart422b7792010-04-29 16:05:54 +0000116 printf("thread %d iteration %d; writing to %p\n",
117 p->thread_num, i + 1, &array[i]);
bartea2a03c2010-03-21 17:24:47 +0000118 array[i] = i;
119 barrier_wait(b);
120 }
121 return 0;
122}
123
124/* Actual test, consisting of nthread threads. */
125static void barriers_and_races(const int nthread, const int iterations)
126{
bart9e718852011-07-29 06:12:51 +0000127 const struct timespec delay = { 0, 100 * 1000 * 1000 };
bartea2a03c2010-03-21 17:24:47 +0000128 int i;
129 struct threadinfo* t;
130 barrier_t b;
131 int* array;
132
133 t = malloc(nthread * sizeof(struct threadinfo));
134 array = malloc(iterations * sizeof(array[0]));
135
136 if (! s_silent)
137 printf("&array[0] = %p\n", array);
138
139 barrier_init(&b, nthread);
140
141 for (i = 0; i < nthread; i++)
142 {
bart422b7792010-04-29 16:05:54 +0000143 t[i].thread_num = i + 1;
bartea2a03c2010-03-21 17:24:47 +0000144 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]);
bart9e718852011-07-29 06:12:51 +0000148 nanosleep(&delay, 0);
bartea2a03c2010-03-21 17:24:47 +0000149 }
150
151 for (i = 0; i < nthread; i++)
152 pthread_join(t[i].tid, 0);
153
154 barrier_destroy(&b);
155
156 free(array);
157 free(t);
158}
159
160int main(int argc, char** argv)
161{
162 int nthread;
163 int iterations;
164
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;
168
169 barriers_and_races(nthread, iterations);
170
171 fprintf(stderr, "Done.\n");
172
173 return 0;
174}