Home | History | Annotate | Download | only in tests
      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 
     25 struct 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 
     38 static 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. */
     47 static 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. */
     67 static 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 
    113 int 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