thread_local_alloc.h raw

   1  /*
   2   * Copyright (c) 2000-2005 by Hewlett-Packard Company.  All rights reserved.
   3   *
   4   * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
   5   * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
   6   *
   7   * Permission is hereby granted to use or copy this program
   8   * for any purpose, provided the above notices are retained on all copies.
   9   * Permission to modify the code and to distribute modified code is granted,
  10   * provided the above notices are retained, and a notice that the code was
  11   * modified is included with the above copyright notice.
  12   */
  13  
  14  /*
  15   * Included indirectly from a thread-library-specific file.
  16   * This is the interface for thread-local allocation, whose implementation
  17   * is mostly thread-library-independent.  Here we describe only the interface
  18   * that needs to be known and invoked from the thread support layer;
  19   * the actual implementation also exports `GC_malloc` and friends, which are
  20   * declared in `gc.h` file.
  21   */
  22  
  23  #ifndef GC_THREAD_LOCAL_ALLOC_H
  24  #define GC_THREAD_LOCAL_ALLOC_H
  25  
  26  #include "gc_priv.h"
  27  
  28  #ifdef THREAD_LOCAL_ALLOC
  29  
  30  #  if defined(USE_HPUX_TLS)
  31  #    error USE_HPUX_TLS macro was replaced by USE_COMPILER_TLS
  32  #  endif
  33  
  34  #  include <stdlib.h>
  35  
  36  EXTERN_C_BEGIN
  37  
  38  #  if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_WIN32_SPECIFIC)    \
  39        && !defined(USE_WIN32_COMPILER_TLS) && !defined(USE_COMPILER_TLS) \
  40        && !defined(USE_CUSTOM_SPECIFIC)
  41  #    if defined(GC_WIN32_THREADS)
  42  #      if defined(CYGWIN32) && GC_GNUC_PREREQ(4, 0)
  43  #        if defined(__clang__)
  44  /* As of Cygwin clang-3.5.2, thread-local storage is unsupported. */
  45  #          define USE_PTHREAD_SPECIFIC
  46  #        else
  47  #          define USE_COMPILER_TLS
  48  #        endif
  49  #      elif defined(__GNUC__) || defined(MSWINCE)
  50  #        define USE_WIN32_SPECIFIC
  51  #      else
  52  #        define USE_WIN32_COMPILER_TLS
  53  #      endif /* !GNU */
  54  
  55  #    elif defined(HOST_ANDROID)
  56  #      if defined(ARM32) \
  57            && (GC_GNUC_PREREQ(4, 6) || GC_CLANG_PREREQ_FULL(3, 8, 256229))
  58  #        define USE_COMPILER_TLS
  59  #      elif !defined(__clang__) && !defined(ARM32)
  60  /* TODO: Support clang/arm64. */
  61  #        define USE_COMPILER_TLS
  62  #      else
  63  #        define USE_PTHREAD_SPECIFIC
  64  #      endif
  65  
  66  #    elif defined(LINUX) && GC_GNUC_PREREQ(3, 3) /* `&& !HOST_ANDROID` */
  67  #      if defined(ARM32) || defined(AVR32)
  68  /* TODO: Change to USE_COMPILER_TLS on Linux/arm. */
  69  #        define USE_PTHREAD_SPECIFIC
  70  #      elif defined(AARCH64) && defined(__clang__) && !GC_CLANG_PREREQ(8, 0)
  71  /* To avoid "R_AARCH64_ABS64 used with TLS symbol" linker warnings. */
  72  #        define USE_PTHREAD_SPECIFIC
  73  #      else
  74  #        define USE_COMPILER_TLS
  75  #      endif
  76  
  77  #    elif (defined(COSMO) || defined(FREEBSD)                                 \
  78             || (defined(NETBSD) && __NetBSD_Version__ >= 600000000 /* 6.0 */)) \
  79          && (GC_GNUC_PREREQ(4, 4) || GC_CLANG_PREREQ(3, 9))
  80  #      define USE_COMPILER_TLS
  81  
  82  #    elif defined(HPUX)
  83  #      ifdef __GNUC__
  84  /* Empirically, as of gcc-3.3, USE_COMPILER_TLS does not work. */
  85  #        define USE_PTHREAD_SPECIFIC
  86  #      else
  87  #        define USE_COMPILER_TLS
  88  #      endif
  89  
  90  #    elif defined(IRIX5) || defined(OPENBSD) || defined(SOLARIS) \
  91          || defined(NINTENDO_SWITCH) || defined(NN_PLATFORM_CTR)
  92  /* Use our own. */
  93  #      define USE_CUSTOM_SPECIFIC
  94  
  95  #    else
  96  #      define USE_PTHREAD_SPECIFIC
  97  #    endif
  98  #  endif /* !USE_x_SPECIFIC */
  99  
 100  #  ifndef THREAD_FREELISTS_KINDS
 101  #    ifdef ENABLE_DISCLAIM
 102  #      define THREAD_FREELISTS_KINDS (NORMAL + 2)
 103  #    else
 104  #      define THREAD_FREELISTS_KINDS (NORMAL + 1)
 105  #    endif
 106  #  endif /* !THREAD_FREELISTS_KINDS */
 107  
 108  /*
 109   * The first `GC_TINY_FREELISTS` free lists correspond to the first
 110   * `GC_TINY_FREELISTS` multiples of `GC_GRANULE_BYTES`, i.e. we keep
 111   * separate free lists for each multiple of `GC_GRANULE_BYTES` up to
 112   * `(GC_TINY_FREELISTS-1) * GC_GRANULE_BYTES`.  After that they may be
 113   * spread out further.
 114   */
 115  
 116  /*
 117   * This should be used for the `tlfs` field in the structure pointed to
 118   * by a `GC_thread` entity.  Free lists contain either a pointer or
 119   * a small count reflecting the number of granules allocated at that size:
 120   *   - zero means thread-local allocation in use, free list is empty;
 121   *   - greater than zero but not greater than `DIRECT_GRANULES` means
 122   *     using global allocation, too few objects of this size have been
 123   *     allocated by this thread;
 124   *   - greater than `DIRECT_GRANULES` but less than `HBLKSIZE` means
 125   *     transition to local allocation, equivalent to zero;
 126   *   - not less than `HBLKSIZE` means pointer to nonempty free list.
 127   */
 128  
 129  struct thread_local_freelists {
 130    /* Note: preserve `*_freelists` names for some clients. */
 131    void *_freelists[THREAD_FREELISTS_KINDS][GC_TINY_FREELISTS];
 132  #  define ptrfree_freelists _freelists[PTRFREE]
 133  #  define normal_freelists _freelists[NORMAL]
 134  #  ifdef GC_GCJ_SUPPORT
 135    void *gcj_freelists[GC_TINY_FREELISTS];
 136    /* A value used for `gcj_freelists[-1]`; allocation is erroneous. */
 137  #    define ERROR_FL GC_WORD_MAX
 138  #  endif
 139  
 140    /* Do not use local free lists for up to this much allocation. */
 141  #  define DIRECT_GRANULES (HBLKSIZE / GC_GRANULE_BYTES)
 142  };
 143  typedef struct thread_local_freelists *GC_tlfs;
 144  
 145  #  if defined(USE_PTHREAD_SPECIFIC)
 146  #    define GC_getspecific pthread_getspecific
 147  #    define GC_setspecific pthread_setspecific
 148  #    define GC_key_create pthread_key_create
 149  /*
 150   * Explicitly delete the value to stop the TLS (thread-local storage)
 151   * destructor from being called repeatedly.
 152   */
 153  #    define GC_remove_specific(key) (void)pthread_setspecific(key, NULL)
 154  #    define GC_remove_specific_after_fork(key, t) \
 155        (void)0 /*< no action needed */
 156  typedef pthread_key_t GC_key_t;
 157  #  elif defined(USE_COMPILER_TLS) || defined(USE_WIN32_COMPILER_TLS)
 158  #    define GC_getspecific(x) (x)
 159  #    define GC_setspecific(key, v) ((key) = (v), 0)
 160  #    define GC_key_create(key, d) 0
 161  /* Just to clear the pointer to `tlfs`. */
 162  #    define GC_remove_specific(key) (void)GC_setspecific(key, NULL)
 163  #    define GC_remove_specific_after_fork(key, t) (void)0
 164  typedef void *GC_key_t;
 165  #  elif defined(USE_WIN32_SPECIFIC)
 166  #    define GC_getspecific TlsGetValue
 167  /* Note: we assume that zero means success, Win32 API does the opposite. */
 168  #    define GC_setspecific(key, v) !TlsSetValue(key, v)
 169  #    ifndef TLS_OUT_OF_INDEXES
 170  /* This is currently missing in WinCE. */
 171  #      define TLS_OUT_OF_INDEXES (DWORD)0xFFFFFFFF
 172  #    endif
 173  #    define GC_key_create(key, d) \
 174        ((d) != 0 || (*(key) = TlsAlloc()) == TLS_OUT_OF_INDEXES ? -1 : 0)
 175  /* TODO: Is `TlsFree` needed on process exit/detach? */
 176  #    define GC_remove_specific(key) (void)GC_setspecific(key, NULL)
 177  #    define GC_remove_specific_after_fork(key, t) (void)0
 178  typedef DWORD GC_key_t;
 179  #  elif defined(USE_CUSTOM_SPECIFIC)
 180  EXTERN_C_END
 181  #    include "specific.h"
 182  EXTERN_C_BEGIN
 183  #  else
 184  #    error implement me
 185  #  endif
 186  
 187  /*
 188   * Each thread structure must be initialized.  This call must be made from
 189   * the new thread.  Caller should hold the allocator lock.
 190   */
 191  GC_INNER void GC_init_thread_local(GC_tlfs p);
 192  
 193  /*
 194   * Called when a thread is unregistered, or exits.  Caller should hold
 195   * the allocator lock.
 196   */
 197  GC_INNER void GC_destroy_thread_local(GC_tlfs p);
 198  
 199  /*
 200   * The thread support layer must arrange to mark thread-local free lists
 201   * explicitly, since the link field is often invisible to the marker.
 202   * It knows how to find all threads; we take care of an individual thread
 203   * free-list structure.
 204   */
 205  GC_INNER void GC_mark_thread_local_fls_for(GC_tlfs p);
 206  
 207  #  ifdef GC_ASSERTIONS
 208  GC_bool GC_is_thread_tsd_valid(void *tsd);
 209  void GC_check_tls_for(GC_tlfs p);
 210  #    if defined(USE_CUSTOM_SPECIFIC)
 211  void GC_check_tsd_marks(tsd *key);
 212  #    endif
 213  #  endif /* GC_ASSERTIONS */
 214  
 215  #  ifndef GC_ATTR_TLS_FAST
 216  #    define GC_ATTR_TLS_FAST /*< empty */
 217  #  endif
 218  
 219  /*
 220   * This is set up by `GC_init_thread_local()`.  No need for cleanup
 221   * on thread exit.  But the thread support layer makes sure that
 222   * `GC_thread_key` is traced, if necessary.
 223   */
 224  extern
 225  #  if defined(USE_COMPILER_TLS)
 226      __thread GC_ATTR_TLS_FAST
 227  #  elif defined(USE_WIN32_COMPILER_TLS)
 228      __declspec(thread) GC_ATTR_TLS_FAST
 229  #  endif
 230          GC_key_t GC_thread_key;
 231  
 232  EXTERN_C_END
 233  
 234  #endif /* THREAD_LOCAL_ALLOC */
 235  
 236  #endif /* GC_THREAD_LOCAL_ALLOC_H */
 237