threadkey.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  #define GC_NO_THREAD_REDIRECTS 1
  11  
  12  #include "gc.h"
  13  
  14  #include <stdio.h>
  15  #include <stdlib.h>
  16  
  17  #if (!defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS) \
  18       || defined(__native_client__))                       \
  19      && !defined(SKIP_THREADKEY_TEST)
  20  /*
  21   * FIXME: Skip this test on Solaris for now.  The test may fail on other
  22   * targets as well.  Currently, tested only on Linux, Cygwin and Darwin.
  23   */
  24  #  define SKIP_THREADKEY_TEST
  25  #endif
  26  
  27  #ifdef SKIP_THREADKEY_TEST
  28  
  29  int
  30  main(void)
  31  {
  32    printf("test skipped\n");
  33    return 0;
  34  }
  35  
  36  #else
  37  
  38  #  include <errno.h> /*< for `EAGAIN` */
  39  #  include <pthread.h>
  40  
  41  pthread_key_t key;
  42  
  43  /* TODO: Use `pthread_once_t` on Solaris. */
  44  pthread_once_t key_once = PTHREAD_ONCE_INIT;
  45  
  46  static void *
  47  entry(void *arg)
  48  {
  49    pthread_setspecific(key,
  50                        (void *)GC_HIDE_NZ_POINTER(GC_STRDUP("hello, world")));
  51    return arg;
  52  }
  53  
  54  static void *GC_CALLBACK
  55  on_thread_exit_inner(struct GC_stack_base *sb, void *arg)
  56  {
  57    int res = GC_register_my_thread(sb);
  58    pthread_t t;
  59    int creation_res; /*< to suppress a warning about unchecked result */
  60    pthread_attr_t attr;
  61  
  62    if (pthread_attr_init(&attr) != 0
  63        || pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED) != 0) {
  64      fprintf(stderr, "Thread attribute init or setdetachstate failed\n");
  65      exit(2);
  66    }
  67    creation_res = GC_pthread_create(&t, &attr, entry, NULL);
  68    (void)pthread_attr_destroy(&attr);
  69    if (res == GC_SUCCESS)
  70      GC_unregister_my_thread();
  71  
  72  #  if defined(CPPCHECK)
  73    GC_noop1_ptr(sb);
  74    GC_noop1_ptr(arg);
  75  #  endif
  76    return arg ? (void *)(GC_uintptr_t)creation_res : 0;
  77  }
  78  
  79  static void
  80  on_thread_exit(void *v)
  81  {
  82    (void)GC_call_with_stack_base(on_thread_exit_inner, v);
  83  }
  84  
  85  static void
  86  make_key(void)
  87  {
  88    pthread_key_create(&key, on_thread_exit);
  89  }
  90  
  91  #  ifndef NTHREADS
  92  #    define NTHREADS 5
  93  #  endif
  94  
  95  /* Number of threads to create. */
  96  #  define NTHREADS_INNER (NTHREADS * 6)
  97  
  98  int
  99  main(void)
 100  {
 101    int i;
 102  
 103    GC_INIT();
 104    if (GC_get_find_leak())
 105      printf("This test program is not designed for leak detection mode\n");
 106    /* TODO: Call `make_key()` instead on Solaris. */
 107    pthread_once(&key_once, make_key);
 108  
 109    for (i = 0; i < NTHREADS_INNER; i++) {
 110      pthread_t t;
 111      void *res;
 112      int err = GC_pthread_create(&t, NULL, entry, NULL);
 113  
 114      if (err != 0) {
 115        fprintf(stderr, "Thread #%d creation failed, errno= %d\n", i, err);
 116        if (i > 0 && EAGAIN == err)
 117          break;
 118        exit(2);
 119      }
 120  
 121      if ((i & 1) != 0) {
 122        err = GC_pthread_join(t, &res);
 123        if (err != 0) {
 124          fprintf(stderr, "Thread #%d join failed, errno= %d\n", i, err);
 125          exit(2);
 126        }
 127      } else {
 128        err = GC_pthread_detach(t);
 129        if (err != 0) {
 130          fprintf(stderr, "Thread #%d detach failed, errno= %d\n", i, err);
 131          exit(2);
 132        }
 133      }
 134    }
 135    printf("SUCCEEDED\n");
 136    return 0;
 137  }
 138  
 139  #endif /* !SKIP_THREADKEY_TEST */
 140