1 /* Test whether all data races are detected in a multithreaded program with
2 * barriers.
3 */
4
5
6 #define _GNU_SOURCE
7
8 /***********************/
9 /* Include directives. */
10 /***********************/
11
12 #include <assert.h>
13 #include <limits.h>
14 #include <pthread.h>
15 #include <stdint.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20
21 /*********************/
22 /* Type definitions. */
23 /*********************/
24
25 struct threadinfo
26 {
27 pthread_barrier_t* b;
28 pthread_t tid;
29 int8_t* array;
30 int iterations;
31 };
32
33
34 /********************/
35 /* Local variables. */
36 /********************/
37
38 static int s_silent;
39
40
41 /*************************/
42 /* Function definitions. */
43 /*************************/
44
45 /** Single thread, which touches p->iterations elements of array p->array.
46 * Each modification of an element of p->array is a data race. */
threadfunc(struct threadinfo * p)47 static void* threadfunc(struct threadinfo* p)
48 {
49 int i;
50 int8_t* const array = p->array;
51 pthread_barrier_t* const b = p->b;
52 if (! s_silent)
53 printf("thread %lx iteration 0\n", pthread_self());
54 pthread_barrier_wait(b);
55 for (i = 0; i < p->iterations; i++)
56 {
57 if (! s_silent)
58 printf("thread %lx iteration %d; writing to %p\n",
59 pthread_self(), i + 1, &array[i]);
60 array[i] = i;
61 pthread_barrier_wait(b);
62 }
63 return 0;
64 }
65
66 /** Actual test, consisting of nthread threads. */
barriers_and_races(const int nthread,const int iterations)67 static void barriers_and_races(const int nthread, const int iterations)
68 {
69 int i, res;
70 pthread_attr_t attr;
71 struct threadinfo* t;
72 pthread_barrier_t b;
73 int8_t* array;
74
75 t = malloc(nthread * sizeof(struct threadinfo));
76 array = malloc(iterations * sizeof(array[0]));
77
78 if (! s_silent)
79 printf("&array[0] = %p\n", array);
80
81 pthread_barrier_init(&b, 0, nthread);
82
83 pthread_attr_init(&attr);
84 res = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + 4096);
85 assert(res == 0);
86
87 for (i = 0; i < nthread; i++)
88 {
89 t[i].b = &b;
90 t[i].array = array;
91 t[i].iterations = iterations;
92 res = pthread_create(&t[i].tid, &attr, (void*(*)(void*))threadfunc, &t[i]);
93 if (res != 0) {
94 fprintf(stderr, "Could not create thread #%d (of %d): %s\n",
95 i, nthread, strerror(res));
96 exit(1);
97 }
98 }
99
100 pthread_attr_destroy(&attr);
101
102 for (i = 0; i < nthread; i++)
103 {
104 pthread_join(t[i].tid, 0);
105 }
106
107 pthread_barrier_destroy(&b);
108
109 free(array);
110 free(t);
111 }
112
main(int argc,char ** argv)113 int main(int argc, char** argv)
114 {
115 int nthread;
116 int iterations;
117
118 nthread = (argc > 1) ? atoi(argv[1]) : 2;
119 iterations = (argc > 2) ? atoi(argv[2]) : 3;
120 s_silent = (argc > 3) ? atoi(argv[3]) : 0;
121
122 barriers_and_races(nthread, iterations);
123
124 return 0;
125 }
126