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 sem_t sem;
     30 
     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 
     39 __attribute__((noinline)) void err ( void )
     40 {
     41    usechar( block[5] );
     42 }
     43 
     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 
     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 
     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