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
25struct 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
38static 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. */
47static 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. */
67static 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
113int 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