Home | History | Annotate | Download | only in tests
      1 /*
      2  * Test whether all data races are detected in a multithreaded program with
      3  * user-annotated barriers. See also pth_barrier.c.
      4  */
      5 
      6 
      7 #define _GNU_SOURCE
      8 
      9 
     10 #include <pthread.h> /* pthread_create() */
     11 #include <stdio.h>   /* fprintf() */
     12 #include <stdlib.h>  /* atoi() */
     13 #include <string.h>  /* memset() */
     14 #include <unistd.h>  /* usleep() */
     15 #include "../../drd/drd.h"
     16 #include "../../config.h"
     17 
     18 
     19 #define BARRIER_SERIAL_THREAD -1
     20 
     21 
     22 /* Local datatypes. */
     23 
     24 typedef struct
     25 {
     26   /*
     27    * number of threads that must call barrier_wait() before any of them
     28    * successfully return from the call.
     29    */
     30   unsigned thread_count;
     31   /* number of barrier_wait() calls since last barrier. */
     32   volatile unsigned wait_count;
     33   /*
     34    * barrier count. Only the least significant bit matters -- a single bit
     35    * counter would be sufficient.
     36    */
     37   volatile unsigned barrier_count;
     38 } barrier_t;
     39 
     40 struct threadinfo
     41 {
     42   int        thread_num;
     43   barrier_t* b;
     44   pthread_t  tid;
     45   int*       array;
     46   int        iterations;
     47 };
     48 
     49 
     50 /* Local variables. */
     51 
     52 static int s_silent;
     53 
     54 
     55 /* Local functions. */
     56 
     57 static void barrier_init(barrier_t* b, unsigned count)
     58 {
     59   b->thread_count = count;
     60   b->wait_count = 0;
     61   b->barrier_count = 0;
     62   ANNOTATE_BARRIER_INIT(b, count, 0);
     63 }
     64 
     65 static void barrier_destroy(barrier_t* b)
     66 {
     67   ANNOTATE_BARRIER_DESTROY(b);
     68   memset(b, 0, sizeof(*b));
     69 }
     70 
     71 static int barrier_wait(barrier_t* b)
     72 {
     73   int res;
     74   unsigned barrier_count;
     75 
     76   res = 0;
     77   ANNOTATE_BARRIER_WAIT_BEFORE(b);
     78   barrier_count = b->barrier_count;
     79   if (__sync_add_and_fetch(&b->wait_count, 1) == b->thread_count)
     80   {
     81     __sync_sub_and_fetch(&b->wait_count, b->thread_count);
     82     __sync_add_and_fetch(&b->barrier_count, 1);
     83     res = BARRIER_SERIAL_THREAD;
     84   }
     85   else
     86   {
     87     while (b->barrier_count == barrier_count)
     88     {
     89 #ifndef HAVE_PTHREAD_YIELD
     90       /* Darwin doesn't have an implementation of pthread_yield(). */
     91       usleep(100 * 1000);
     92 #else
     93       pthread_yield();
     94 #endif
     95     }
     96   }
     97   ANNOTATE_BARRIER_WAIT_AFTER(b);
     98   return res;
     99 }
    100 
    101 /*
    102  * Single thread, which touches p->iterations elements of array p->array.
    103  * Each modification of an element of p->array is a data race.
    104  */
    105 static void* threadfunc(struct threadinfo* p)
    106 {
    107   int i;
    108   int* const array = p->array;
    109   barrier_t* const b = p->b;
    110   if (! s_silent)
    111     printf("thread %d iteration 0\n", p->thread_num);
    112   barrier_wait(b);
    113   for (i = 0; i < p->iterations; i++)
    114   {
    115     if (! s_silent)
    116       printf("thread %d iteration %d; writing to %p\n",
    117              p->thread_num, i + 1, &array[i]);
    118     array[i] = i;
    119     barrier_wait(b);
    120   }
    121   return 0;
    122 }
    123 
    124 /* Actual test, consisting of nthread threads. */
    125 static void barriers_and_races(const int nthread, const int iterations)
    126 {
    127   const struct timespec delay = { 0, 100 * 1000 * 1000 };
    128   int i;
    129   struct threadinfo* t;
    130   barrier_t b;
    131   int* array;
    132 
    133   t = malloc(nthread * sizeof(struct threadinfo));
    134   array = malloc(iterations * sizeof(array[0]));
    135 
    136   if (! s_silent)
    137     printf("&array[0] = %p\n", array);
    138 
    139   barrier_init(&b, nthread);
    140 
    141   for (i = 0; i < nthread; i++)
    142   {
    143     t[i].thread_num = i + 1;
    144     t[i].b = &b;
    145     t[i].array = array;
    146     t[i].iterations = iterations;
    147     pthread_create(&t[i].tid, 0, (void*(*)(void*))threadfunc, &t[i]);
    148     nanosleep(&delay, 0);
    149   }
    150 
    151   for (i = 0; i < nthread; i++)
    152     pthread_join(t[i].tid, 0);
    153 
    154   barrier_destroy(&b);
    155 
    156   free(array);
    157   free(t);
    158 }
    159 
    160 int main(int argc, char** argv)
    161 {
    162   int nthread;
    163   int iterations;
    164 
    165   nthread    = (argc > 1) ? atoi(argv[1]) : 2;
    166   iterations = (argc > 2) ? atoi(argv[2]) : 3;
    167   s_silent   = (argc > 3) ? atoi(argv[3]) : 0;
    168 
    169   barriers_and_races(nthread, iterations);
    170 
    171   fprintf(stderr, "Done.\n");
    172 
    173   return 0;
    174 }
    175