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