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
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{
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
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);
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 */
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)
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. */
125static 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
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}
175