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