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. */
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", (long) 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              (long) 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. */
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 
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