• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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