Home | History | Annotate | Download | only in tests
      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