1 2 /* Check that recycling thread slots doesn't cause new threads to 3 inherit the disablement status of the previous thread to occupy 4 that slot. 5 6 1. Create N threads, disable error reporting in them, and get them 7 all to exit (join with them). That creates N thread slots that 8 were vacated by threads with error reporting disabled. There 9 should be N complaints about threads exiting with errors 10 disabled. 11 12 2. Create N new threads and get them to wait at a barrier. 13 14 3. Let them all go past the barrier and call err(). There 15 should be N resulting error reports. 16 17 4. Join with the N threads. 18 */ 19 20 #include <stdlib.h> 21 #include <stdio.h> 22 #include <assert.h> 23 #include <pthread.h> 24 #include <semaphore.h> 25 #include <limits.h> /* PTHREAD_STACK_MIN */ 26 #include "../include/valgrind.h" 27 28 char* block = NULL; 29 # if !defined(VGO_darwin) 30 sem_t sem; 31 # else 32 sem_t *sem; 33 static const char *semname = "Semaphore1"; 34 # endif 35 36 __attribute__((noinline)) void usechar ( char c ) 37 { 38 // Spook gcc into believing mysterious bad things are 39 // happening behind its back, and that 'c' is definitely 40 // used in some (unknown) way. 41 __asm__ __volatile__("" : : "r"(c) : "memory","cc"); 42 } 43 44 __attribute__((noinline)) void err ( void ) 45 { 46 usechar( block[5] ); 47 } 48 49 void* child_fn_1 ( void* arg ) 50 { 51 // Disable error reporting, then wait to exit 52 VALGRIND_DISABLE_ERROR_REPORTING; 53 # if !defined(VGO_darwin) 54 int r = sem_wait(&sem); assert(!r); 55 # else 56 int r = sem_wait(sem); assert(!r); 57 # endif 58 return NULL; 59 } 60 61 void* child_fn_2 ( void* arg ) 62 { 63 // make an error, then wait to exit 64 err(); 65 # if !defined(VGO_darwin) 66 int r = sem_wait(&sem); assert(!r); 67 # else 68 int r = sem_wait(sem); assert(!r); 69 # endif 70 return NULL; 71 } 72 73 #define NTHREADS 498 // VG_N_THREADS - 2 74 75 int main ( void ) 76 { 77 int r, i; 78 pthread_t child[NTHREADS]; 79 80 block = malloc(10); 81 free(block); 82 83 // part 1 84 fprintf(stderr, "\n-------- Letting %d threads exit " 85 "w/ errs disabled ------\n\n", 86 NTHREADS); 87 88 // set up the semaphore 89 # if !defined(VGO_darwin) 90 r = sem_init(&sem, 0, 0); assert(!r); 91 # else 92 sem = sem_open(semname, O_CREAT, 0777, 0); assert(!(sem == SEM_FAILED)); 93 # endif 94 95 pthread_attr_t attr; 96 r = pthread_attr_init(&attr); assert(!r); 97 r = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN); 98 99 // create N threads to do child_fn_1 ... 100 for (i = 0; i < NTHREADS; i++) { 101 r = pthread_create(&child[i], &attr, child_fn_1, NULL); 102 assert(!r); 103 } 104 105 // let them all exit 106 for (i = 0; i < NTHREADS; i++) { 107 # if !defined(VGO_darwin) 108 r = sem_post(&sem); assert(!r); 109 # else 110 r = sem_post(sem); assert(!r); 111 # endif 112 } 113 114 // join 115 for (i = 0; i < NTHREADS; i++) { 116 r = pthread_join(child[i], NULL); assert(!r); 117 } 118 119 // part 2 120 121 fprintf(stderr, "\n-------- Letting %d threads make an error " 122 "------\n\n", 123 NTHREADS); 124 // semaphore is already back at zero 125 126 // create N threads to do child_fn_2 ... 127 for (i = 0; i < NTHREADS; i++) { 128 r = pthread_create(&child[i], &attr, child_fn_2, NULL); 129 assert(!r); 130 } 131 132 // let them all exit 133 for (i = 0; i < NTHREADS; i++) { 134 # if !defined(VGO_darwin) 135 r = sem_post(&sem); assert(!r); 136 # else 137 r = sem_post(sem); assert(!r); 138 # endif 139 } 140 141 // join 142 for (i = 0; i < NTHREADS; i++) { 143 r = pthread_join(child[i], NULL); assert(!r); 144 } 145 146 // Print the final error counts. There need to be 498 errors 147 // in 1 context. Anything else, and something is not right. 148 int nerrors = VALGRIND_COUNT_ERRORS; 149 fprintf(stderr, "\n-------- Got %d errors (expected %d ==> %s) ------\n\n", 150 nerrors, NTHREADS, nerrors == NTHREADS ? "PASS" : "FAIL" ); 151 152 return 0; 153 } 154