mirror of
https://github.com/ioacademy-jikim/debugging
synced 2025-06-08 08:26:14 +00:00
126 lines
2.6 KiB
C
126 lines
2.6 KiB
C
/* Test whether all data races are detected in a multithreaded program with
|
|
* barriers.
|
|
*/
|
|
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
/***********************/
|
|
/* Include directives. */
|
|
/***********************/
|
|
|
|
#include <assert.h>
|
|
#include <limits.h>
|
|
#include <pthread.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
|
|
/*********************/
|
|
/* Type definitions. */
|
|
/*********************/
|
|
|
|
struct threadinfo
|
|
{
|
|
pthread_barrier_t* b;
|
|
pthread_t tid;
|
|
int8_t* 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;
|
|
int8_t* const array = p->array;
|
|
pthread_barrier_t* const b = p->b;
|
|
if (! s_silent)
|
|
printf("thread %lx iteration 0\n", (long) 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",
|
|
(long) 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, res;
|
|
pthread_attr_t attr;
|
|
struct threadinfo* t;
|
|
pthread_barrier_t b;
|
|
int8_t* 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);
|
|
|
|
pthread_attr_init(&attr);
|
|
res = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + 4096);
|
|
assert(res == 0);
|
|
|
|
for (i = 0; i < nthread; i++)
|
|
{
|
|
t[i].b = &b;
|
|
t[i].array = array;
|
|
t[i].iterations = iterations;
|
|
res = pthread_create(&t[i].tid, &attr, (void*(*)(void*))threadfunc, &t[i]);
|
|
if (res != 0) {
|
|
fprintf(stderr, "Could not create thread #%d (of %d): %s\n",
|
|
i, nthread, strerror(res));
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
pthread_attr_destroy(&attr);
|
|
|
|
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;
|
|
}
|