• 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 #  if !defined(VGO_darwin)
30 sem_t sem;
31 #  else
32 sem_t *sem;
33 static const char *semname = "Semaphore1";
34 #  endif
35 
usechar(char c)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 
err(void)44 __attribute__((noinline)) void err ( void )
45 {
46    usechar( block[5] );
47 }
48 
child_fn_1(void * arg)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 
child_fn_2(void * arg)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 
main(void)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