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 sem_t sem;
30
usechar(char c)31 __attribute__((noinline)) void usechar ( char c )
32 {
33 // Spook gcc into believing mysterious bad things are
34 // happening behind its back, and that 'c' is definitely
35 // used in some (unknown) way.
36 __asm__ __volatile__("" : : "r"(c) : "memory","cc");
37 }
38
err(void)39 __attribute__((noinline)) void err ( void )
40 {
41 usechar( block[5] );
42 }
43
child_fn_1(void * arg)44 void* child_fn_1 ( void* arg )
45 {
46 // Disable error reporting, then wait to exit
47 VALGRIND_DISABLE_ERROR_REPORTING;
48 int r = sem_wait(&sem); assert(!r);
49 return NULL;
50 }
51
child_fn_2(void * arg)52 void* child_fn_2 ( void* arg )
53 {
54 // make an error, then wait to exit
55 err();
56 int r = sem_wait(&sem); assert(!r);
57 return NULL;
58 }
59
60 #define NTHREADS 498 // VG_N_THREADS - 2
61
main(void)62 int main ( void )
63 {
64 int r, i;
65 pthread_t child[NTHREADS];
66
67 block = malloc(10);
68 free(block);
69
70 // part 1
71 fprintf(stderr, "\n-------- Letting %d threads exit "
72 "w/ errs disabled ------\n\n",
73 NTHREADS);
74
75 // set up the semaphore
76 r = sem_init(&sem, 0, 0); assert(!r);
77
78 pthread_attr_t attr;
79 r = pthread_attr_init(&attr); assert(!r);
80 r = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);
81
82 // create N threads to do child_fn_1 ...
83 for (i = 0; i < NTHREADS; i++) {
84 r = pthread_create(&child[i], &attr, child_fn_1, NULL);
85 assert(!r);
86 }
87
88 // let them all exit
89 for (i = 0; i < NTHREADS; i++) {
90 r = sem_post(&sem); assert(!r);
91 }
92
93 // join
94 for (i = 0; i < NTHREADS; i++) {
95 r = pthread_join(child[i], NULL); assert(!r);
96 }
97
98 // part 2
99
100 fprintf(stderr, "\n-------- Letting %d threads make an error "
101 "------\n\n",
102 NTHREADS);
103 // semaphore is already back at zero
104
105 // create N threads to do child_fn_2 ...
106 for (i = 0; i < NTHREADS; i++) {
107 r = pthread_create(&child[i], &attr, child_fn_2, NULL);
108 assert(!r);
109 }
110
111 // let them all exit
112 for (i = 0; i < NTHREADS; i++) {
113 r = sem_post(&sem); assert(!r);
114 }
115
116 // join
117 for (i = 0; i < NTHREADS; i++) {
118 r = pthread_join(child[i], NULL); assert(!r);
119 }
120
121 // Print the final error counts. There need to be 498 errors
122 // in 1 context. Anything else, and something is not right.
123 int nerrors = VALGRIND_COUNT_ERRORS;
124 fprintf(stderr, "\n-------- Got %d errors (expected %d ==> %s) ------\n\n",
125 nerrors, NTHREADS, nerrors == NTHREADS ? "PASS" : "FAIL" );
126
127 return 0;
128 }
129