/* Test whether all data races are detected in a multithreaded program with
* barriers.
*/
#define _GNU_SOURCE
/***********************/
/* Include directives. */
/***********************/
#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
/*********************/
/* Type definitions. */
/*********************/
struct threadinfo
{
pthread_barrier_t* b;
pthread_t tid;
int* array;
int iterations;
};
/********************/
/* Local variables. */
/********************/
static int s_silent;
/*************************/
/* Function definitions. */
/*************************/
/** Single thread, which touches p->iterations elements of array p->array.
* Each modification of an element of p->array is a data race. */
static void* threadfunc(struct threadinfo* p)
{
int i;
int* const array = p->array;
pthread_barrier_t* const b = p->b;
if (! s_silent)
printf("thread %lx iteration 0\n", pthread_self());
pthread_barrier_wait(b);
for (i = 0; i < p->iterations; i++)
{
if (! s_silent)
printf("thread %lx iteration %d; writing to %p\n",
pthread_self(), i + 1, &array[i]);
array[i] = i;
pthread_barrier_wait(b);
}
return 0;
}
/** Actual test, consisting of nthread threads. */
static void barriers_and_races(const int nthread, const int iterations)
{
int i;
struct threadinfo* t;
pthread_barrier_t b;
int* array;
t = malloc(nthread * sizeof(struct threadinfo));
array = malloc(iterations * sizeof(array[0]));
if (! s_silent)
printf("&array[0] = %p\n", array);
pthread_barrier_init(&b, 0, nthread);
for (i = 0; i < nthread; i++)
{
t[i].b = &b;
t[i].array = array;
t[i].iterations = iterations;
pthread_create(&t[i].tid, 0, (void*(*)(void*))threadfunc, &t[i]);
}
for (i = 0; i < nthread; i++)
{
pthread_join(t[i].tid, 0);
}
pthread_barrier_destroy(&b);
free(array);
free(t);
}
int main(int argc, char** argv)
{
int nthread;
int iterations;
nthread = (argc > 1) ? atoi(argv[1]) : 2;
iterations = (argc > 2) ? atoi(argv[2]) : 3;
s_silent = (argc > 3) ? atoi(argv[3]) : 0;
barriers_and_races(nthread, iterations);
return 0;
}