sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 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> |
bart | 7aac06f | 2011-08-12 15:21:31 +0000 | [diff] [blame] | 13 | #include <limits.h> |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 14 | #include <pthread.h> |
bart | de60fe5 | 2011-10-05 13:10:30 +0000 | [diff] [blame] | 15 | #include <stdint.h> |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 16 | #include <stdio.h> |
| 17 | #include <stdlib.h> |
florian | 4b82d69 | 2011-08-12 15:07:10 +0000 | [diff] [blame] | 18 | #include <string.h> |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 19 | |
| 20 | |
| 21 | /*********************/ |
| 22 | /* Type definitions. */ |
| 23 | /*********************/ |
| 24 | |
| 25 | struct threadinfo |
| 26 | { |
| 27 | pthread_barrier_t* b; |
| 28 | pthread_t tid; |
bart | de60fe5 | 2011-10-05 13:10:30 +0000 | [diff] [blame] | 29 | int8_t* array; |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 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 | |
bart | 546b771 | 2008-02-24 18:18:23 +0000 | [diff] [blame] | 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. */ |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 47 | static void* threadfunc(struct threadinfo* p) |
| 48 | { |
| 49 | int i; |
florian | ad2fc77 | 2011-10-05 14:49:12 +0000 | [diff] [blame] | 50 | int8_t* const array = p->array; |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 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 | |
bart | 546b771 | 2008-02-24 18:18:23 +0000 | [diff] [blame] | 66 | /** Actual test, consisting of nthread threads. */ |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 67 | static void barriers_and_races(const int nthread, const int iterations) |
| 68 | { |
bart | 7aac06f | 2011-08-12 15:21:31 +0000 | [diff] [blame] | 69 | int i, res; |
| 70 | pthread_attr_t attr; |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 71 | struct threadinfo* t; |
| 72 | pthread_barrier_t b; |
florian | ad2fc77 | 2011-10-05 14:49:12 +0000 | [diff] [blame] | 73 | int8_t* array; |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 74 | |
| 75 | t = malloc(nthread * sizeof(struct threadinfo)); |
| 76 | array = malloc(iterations * sizeof(array[0])); |
| 77 | |
bart | 546b771 | 2008-02-24 18:18:23 +0000 | [diff] [blame] | 78 | if (! s_silent) |
| 79 | printf("&array[0] = %p\n", array); |
| 80 | |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 81 | pthread_barrier_init(&b, 0, nthread); |
| 82 | |
bart | 7aac06f | 2011-08-12 15:21:31 +0000 | [diff] [blame] | 83 | pthread_attr_init(&attr); |
| 84 | res = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN + 4096); |
| 85 | assert(res == 0); |
| 86 | |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 87 | for (i = 0; i < nthread; i++) |
| 88 | { |
| 89 | t[i].b = &b; |
| 90 | t[i].array = array; |
| 91 | t[i].iterations = iterations; |
bart | 7aac06f | 2011-08-12 15:21:31 +0000 | [diff] [blame] | 92 | res = pthread_create(&t[i].tid, &attr, (void*(*)(void*))threadfunc, &t[i]); |
| 93 | if (res != 0) { |
florian | 4b82d69 | 2011-08-12 15:07:10 +0000 | [diff] [blame] | 94 | fprintf(stderr, "Could not create thread #%d (of %d): %s\n", |
bart | 7aac06f | 2011-08-12 15:21:31 +0000 | [diff] [blame] | 95 | i, nthread, strerror(res)); |
florian | 4b82d69 | 2011-08-12 15:07:10 +0000 | [diff] [blame] | 96 | exit(1); |
| 97 | } |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 98 | } |
| 99 | |
bart | 7aac06f | 2011-08-12 15:21:31 +0000 | [diff] [blame] | 100 | pthread_attr_destroy(&attr); |
| 101 | |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 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 | |
bart | 546b771 | 2008-02-24 18:18:23 +0000 | [diff] [blame] | 118 | nthread = (argc > 1) ? atoi(argv[1]) : 2; |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 119 | iterations = (argc > 2) ? atoi(argv[2]) : 3; |
bart | 546b771 | 2008-02-24 18:18:23 +0000 | [diff] [blame] | 120 | s_silent = (argc > 3) ? atoi(argv[3]) : 0; |
sewardj | 347eeba | 2008-01-21 14:19:07 +0000 | [diff] [blame] | 121 | |
| 122 | barriers_and_races(nthread, iterations); |
| 123 | |
| 124 | return 0; |
| 125 | } |