File: err_disable4.c

package info (click to toggle)
valgrind 1%3A3.12.0~svn20160714-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 120,428 kB
  • ctags: 70,855
  • sloc: ansic: 674,645; exp: 26,134; xml: 21,574; asm: 7,570; cpp: 7,567; makefile: 7,380; sh: 6,188; perl: 5,855; haskell: 195
file content (153 lines) | stat: -rw-r--r-- 3,763 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

/* Check that recycling thread slots doesn't cause new threads to
   inherit the disablement status of the previous thread to occupy
   that slot.

   1. Create N threads, disable error reporting in them, and get them
      all to exit (join with them).  That creates N thread slots that
      were vacated by threads with error reporting disabled.  There
      should be N complaints about threads exiting with errors
      disabled.

   2. Create N new threads and get them to wait at a barrier.

   3. Let them all go past the barrier and call err().  There
      should be N resulting error reports.

   4. Join with the N threads.
*/

#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <pthread.h>
#include <semaphore.h>
#include <limits.h>    /* PTHREAD_STACK_MIN */
#include "../include/valgrind.h"

char* block = NULL;
#  if !defined(VGO_darwin)
sem_t sem;
#  else
sem_t *sem;
static const char *semname = "Semaphore1";
#  endif

__attribute__((noinline)) void usechar ( char c )
{
   // Spook gcc into believing mysterious bad things are
   // happening behind its back, and that 'c' is definitely
   // used in some (unknown) way.
   __asm__ __volatile__("" : : "r"(c) : "memory","cc");
}

__attribute__((noinline)) void err ( void )
{
   usechar( block[5] );
}

void* child_fn_1 ( void* arg )
{
   // Disable error reporting, then wait to exit
   VALGRIND_DISABLE_ERROR_REPORTING;
#  if !defined(VGO_darwin)
   int r = sem_wait(&sem);  assert(!r);
#  else
   int r = sem_wait(sem);  assert(!r);
#  endif
   return NULL;
}

void* child_fn_2 ( void* arg )
{
   // make an error, then wait to exit
   err();
#  if !defined(VGO_darwin)
   int r = sem_wait(&sem);  assert(!r);
#  else
   int r = sem_wait(sem);  assert(!r);
#  endif
   return NULL;
}

#define NTHREADS 498 // VG_N_THREADS - 2

int main ( void )
{
  int r, i;
  pthread_t child[NTHREADS];

  block = malloc(10);
  free(block);

  // part 1
  fprintf(stderr, "\n-------- Letting %d threads exit "
                  "w/ errs disabled ------\n\n",
          NTHREADS);

  // set up the semaphore
#  if !defined(VGO_darwin)
  r = sem_init(&sem, 0, 0);  assert(!r);
#  else
  sem = sem_open(semname, O_CREAT, 0777, 0);  assert(!(sem == SEM_FAILED));
#  endif

  pthread_attr_t attr;
  r = pthread_attr_init(&attr); assert(!r);
  r = pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN);

  // create N threads to do child_fn_1 ...
  for (i = 0; i < NTHREADS; i++) {
     r = pthread_create(&child[i], &attr, child_fn_1, NULL);
     assert(!r);
  }

  // let them all exit
  for (i = 0; i < NTHREADS; i++) {
#  if !defined(VGO_darwin)
     r = sem_post(&sem);  assert(!r);
#  else
     r = sem_post(sem);  assert(!r);
#  endif
  }

  // join
  for (i = 0; i < NTHREADS; i++) {
     r = pthread_join(child[i], NULL);  assert(!r);
  }

  // part 2

  fprintf(stderr, "\n-------- Letting %d threads make an error "
                  "------\n\n",
          NTHREADS);
  // semaphore is already back at zero

  // create N threads to do child_fn_2 ...
  for (i = 0; i < NTHREADS; i++) {
     r = pthread_create(&child[i], &attr, child_fn_2, NULL);
     assert(!r);
  }

  // let them all exit
  for (i = 0; i < NTHREADS; i++) {
#  if !defined(VGO_darwin)
     r = sem_post(&sem);  assert(!r);
#  else
     r = sem_post(sem);  assert(!r);
#  endif
  }

  // join
  for (i = 0; i < NTHREADS; i++) {
     r = pthread_join(child[i], NULL);  assert(!r);
  }

  // Print the final error counts.  There need to be 498 errors
  // in 1 context.  Anything else, and something is not right.
  int nerrors = VALGRIND_COUNT_ERRORS;
  fprintf(stderr, "\n-------- Got %d errors (expected %d ==> %s) ------\n\n", 
          nerrors, NTHREADS, nerrors == NTHREADS ? "PASS" : "FAIL" );

  return 0;
}