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