• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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() */
14 #include <unistd.h>  /* usleep() */
15 #include "../../drd/drd.h"
16 #include "../../config.h"
17 
18 
19 #define BARRIER_SERIAL_THREAD -1
20 
21 
22 /* Local datatypes. */
23 
24 typedef 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 
40 struct threadinfo
41 {
42   int        thread_num;
43   barrier_t* b;
44   pthread_t  tid;
45   int*       array;
46   int        iterations;
47 };
48 
49 
50 /* Local variables. */
51 
52 static int s_silent;
53 
54 
55 /* Local functions. */
56 
barrier_init(barrier_t * b,unsigned count)57 static 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 
barrier_destroy(barrier_t * b)65 static void barrier_destroy(barrier_t* b)
66 {
67   ANNOTATE_BARRIER_DESTROY(b);
68   memset(b, 0, sizeof(*b));
69 }
70 
barrier_wait(barrier_t * b)71 static 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);
83     res = BARRIER_SERIAL_THREAD;
84   }
85   else
86   {
87     while (b->barrier_count == barrier_count)
88     {
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
95     }
96   }
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  */
threadfunc(struct threadinfo * p)105 static 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)
111     printf("thread %d iteration 0\n", p->thread_num);
112   barrier_wait(b);
113   for (i = 0; i < p->iterations; i++)
114   {
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);
120   }
121   return 0;
122 }
123 
124 /* Actual test, consisting of nthread threads. */
barriers_and_races(const int nthread,const int iterations)125 static void barriers_and_races(const int nthread, const int iterations)
126 {
127   const struct timespec delay = { 0, 100 * 1000 * 1000 };
128   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   {
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);
149   }
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 
main(int argc,char ** argv)160 int 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 }
175