threadleak.c raw

   1  
   2  #ifdef HAVE_CONFIG_H
   3  #  include "config.h"
   4  #endif
   5  
   6  #ifndef GC_THREADS
   7  #  define GC_THREADS
   8  #endif
   9  
  10  #undef GC_NO_THREAD_REDIRECTS
  11  #include "gc/leak_detector.h"
  12  
  13  #ifdef GC_PTHREADS
  14  #  include <errno.h> /*< for `EAGAIN` */
  15  #  include <pthread.h>
  16  #else
  17  #  ifndef WIN32_LEAN_AND_MEAN
  18  #    define WIN32_LEAN_AND_MEAN 1
  19  #  endif
  20  #  define NOSERVICE
  21  #  include <windows.h>
  22  #endif /* !GC_PTHREADS */
  23  
  24  #include <stdio.h>
  25  #include <stdlib.h>
  26  
  27  #define N_TESTS 100
  28  
  29  #define CHECK_OUT_OF_MEMORY(p)            \
  30    do {                                    \
  31      if (NULL == (p)) {                    \
  32        fprintf(stderr, "Out of memory\n"); \
  33        exit(69);                           \
  34      }                                     \
  35    } while (0)
  36  
  37  #ifdef GC_PTHREADS
  38  static void *
  39  test(void *arg)
  40  #else
  41  static DWORD WINAPI
  42  test(LPVOID arg)
  43  #endif
  44  {
  45    int *p[N_TESTS];
  46    int i;
  47    for (i = 0; i < N_TESTS; ++i) {
  48      p[i] = (int *)malloc(sizeof(int) + i);
  49      CHECK_OUT_OF_MEMORY(p[i]);
  50    }
  51    CHECK_LEAKS();
  52    for (i = 1; i < N_TESTS; ++i) {
  53      free(p[i]);
  54    }
  55  #ifdef GC_PTHREADS
  56    return arg;
  57  #else
  58    return (DWORD)(GC_uintptr_t)arg;
  59  #endif
  60  }
  61  
  62  #ifndef NTHREADS
  63  #  define NTHREADS 5
  64  #endif
  65  
  66  int
  67  main(void)
  68  {
  69  #if NTHREADS > 0
  70    int i, n;
  71  #  ifdef GC_PTHREADS
  72    pthread_t t[NTHREADS];
  73  #  else
  74    HANDLE t[NTHREADS];
  75  #  endif
  76  #endif
  77  
  78  #ifndef NO_FIND_LEAK
  79    /* Just in case the code is compiled without `FIND_LEAK` macro defined. */
  80    GC_set_find_leak(1);
  81  #endif
  82    GC_INIT();
  83    /* This is optional if `pthread_create()` is redirected. */
  84    GC_allow_register_threads();
  85  
  86  #if NTHREADS > 0
  87    for (i = 0; i < NTHREADS; ++i) {
  88  #  ifdef GC_PTHREADS
  89      int err = pthread_create(t + i, 0, test, 0);
  90  
  91      if (err != 0) {
  92        fprintf(stderr, "Thread #%d creation failed, errno= %d\n", i, err);
  93        if (i > 1 && EAGAIN == err)
  94          break;
  95        exit(2);
  96      }
  97  #  else
  98      DWORD thread_id;
  99  
 100      t[i] = CreateThread(NULL, 0, test, 0, 0, &thread_id);
 101      if (NULL == t[i]) {
 102        fprintf(stderr, "Thread #%d creation failed, errcode= %d\n", i,
 103                (int)GetLastError());
 104        exit(2);
 105      }
 106  #  endif
 107    }
 108    n = i;
 109    for (i = 0; i < n; ++i) {
 110      int err;
 111  
 112  #  ifdef GC_PTHREADS
 113      err = pthread_join(t[i], 0);
 114  #  else
 115      err = WaitForSingleObject(t[i], INFINITE) == WAIT_OBJECT_0
 116                ? 0
 117                : (int)GetLastError();
 118  #  endif
 119      if (err != 0) {
 120        fprintf(stderr, "Thread #%d join failed, errcode= %d\n", i, err);
 121        exit(2);
 122      }
 123    }
 124  #else
 125    (void)test(NULL);
 126  #endif
 127  
 128    CHECK_LEAKS();
 129    CHECK_LEAKS();
 130    CHECK_LEAKS();
 131    printf("SUCCEEDED\n");
 132    return 0;
 133  }
 134