/libs/headers/gc/private/gc_locks.h

http://github.com/nddrylliog/ooc · C++ Header · 210 lines · 147 code · 14 blank · 49 comment · 36 complexity · 069cef609a8bc1a557b4ad17503e71e1 MD5 · raw file

  1. /*
  2. * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  3. * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
  4. * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
  5. * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
  6. *
  7. *
  8. * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  9. * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
  10. *
  11. * Permission is hereby granted to use or copy this program
  12. * for any purpose, provided the above notices are retained on all copies.
  13. * Permission to modify the code and to distribute modified code is granted,
  14. * provided the above notices are retained, and a notice that the code was
  15. * modified is included with the above copyright notice.
  16. */
  17. #ifndef GC_LOCKS_H
  18. #define GC_LOCKS_H
  19. /*
  20. * Mutual exclusion between allocator/collector routines.
  21. * Needed if there is more than one allocator thread.
  22. * DCL_LOCK_STATE declares any local variables needed by LOCK and UNLOCK.
  23. *
  24. * Note that I_HOLD_LOCK and I_DONT_HOLD_LOCK are used only positively
  25. * in assertions, and may return TRUE in the "dont know" case.
  26. */
  27. # ifdef THREADS
  28. # include <atomic_ops.h>
  29. void GC_noop1(word);
  30. # ifdef PCR
  31. # include <base/PCR_Base.h>
  32. # include <th/PCR_Th.h>
  33. extern PCR_Th_ML GC_allocate_ml;
  34. # define DCL_LOCK_STATE \
  35. PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask
  36. # define UNCOND_LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
  37. # define UNCOND_UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
  38. # endif
  39. # if !defined(AO_HAVE_test_and_set_acquire) && defined(GC_PTHREADS)
  40. # define USE_PTHREAD_LOCKS
  41. # endif
  42. # if defined(GC_WIN32_THREADS) && defined(GC_PTHREADS)
  43. # define USE_PTHREAD_LOCKS
  44. # endif
  45. # if defined(GC_WIN32_THREADS) && !defined(USE_PTHREAD_LOCKS)
  46. # include <windows.h>
  47. # define NO_THREAD (DWORD)(-1)
  48. extern DWORD GC_lock_holder;
  49. GC_API CRITICAL_SECTION GC_allocate_ml;
  50. # ifdef GC_ASSERTIONS
  51. # define UNCOND_LOCK() \
  52. { EnterCriticalSection(&GC_allocate_ml); \
  53. SET_LOCK_HOLDER(); }
  54. # define UNCOND_UNLOCK() \
  55. { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
  56. LeaveCriticalSection(&GC_allocate_ml); }
  57. # else
  58. # define UNCOND_LOCK() EnterCriticalSection(&GC_allocate_ml);
  59. # define UNCOND_UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
  60. # endif /* !GC_ASSERTIONS */
  61. # define SET_LOCK_HOLDER() GC_lock_holder = GetCurrentThreadId()
  62. # define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
  63. # define I_HOLD_LOCK() (!GC_need_to_lock \
  64. || GC_lock_holder == GetCurrentThreadId())
  65. # define I_DONT_HOLD_LOCK() (!GC_need_to_lock \
  66. || GC_lock_holder != GetCurrentThreadId())
  67. # elif defined(GC_PTHREADS)
  68. # include <pthread.h>
  69. /* Posix allows pthread_t to be a struct, though it rarely is. */
  70. /* Unfortunately, we need to use a pthread_t to index a data */
  71. /* structure. It also helps if comparisons don't involve a */
  72. /* function call. Hence we introduce platform-dependent macros */
  73. /* to compare pthread_t ids and to map them to integers. */
  74. /* the mapping to integers does not need to result in different */
  75. /* integers for each thread, though that should be true as much */
  76. /* as possible. */
  77. /* Refine to exclude platforms on which pthread_t is struct */
  78. # if !defined(GC_WIN32_PTHREADS)
  79. # define NUMERIC_THREAD_ID(id) ((unsigned long)(id))
  80. # define THREAD_EQUAL(id1, id2) ((id1) == (id2))
  81. # define NUMERIC_THREAD_ID_UNIQUE
  82. # else
  83. # if defined(GC_WIN32_PTHREADS)
  84. # define NUMERIC_THREAD_ID(id) ((unsigned long)(id.p))
  85. /* Using documented internal details of win32_pthread library. */
  86. /* Faster than pthread_equal(). Should not change with */
  87. /* future versions of win32_pthread library. */
  88. # define THREAD_EQUAL(id1, id2) ((id1.p == id2.p) && (id1.x == id2.x))
  89. # undef NUMERIC_THREAD_ID_UNIQUE
  90. # else
  91. /* Generic definitions that always work, but will result in */
  92. /* poor performance and weak assertion checking. */
  93. # define NUMERIC_THREAD_ID(id) 1l
  94. # define THREAD_EQUAL(id1, id2) pthread_equal(id1, id2)
  95. # undef NUMERIC_THREAD_ID_UNIQUE
  96. # endif
  97. # endif
  98. # define NO_THREAD ((unsigned long)(-1l))
  99. /* != NUMERIC_THREAD_ID(pthread_self()) for any thread */
  100. # if !defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_LOCKS)
  101. /* In the THREAD_LOCAL_ALLOC case, the allocation lock tends to */
  102. /* be held for long periods, if it is held at all. Thus spinning */
  103. /* and sleeping for fixed periods are likely to result in */
  104. /* significant wasted time. We thus rely mostly on queued locks. */
  105. # define USE_SPIN_LOCK
  106. extern volatile AO_TS_t GC_allocate_lock;
  107. extern void GC_lock(void);
  108. /* Allocation lock holder. Only set if acquired by client through */
  109. /* GC_call_with_alloc_lock. */
  110. # ifdef GC_ASSERTIONS
  111. # define UNCOND_LOCK() \
  112. { if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
  113. GC_lock(); \
  114. SET_LOCK_HOLDER(); }
  115. # define UNCOND_UNLOCK() \
  116. { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
  117. AO_CLEAR(&GC_allocate_lock); }
  118. # else
  119. # define UNCOND_LOCK() \
  120. { if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_SET) \
  121. GC_lock(); }
  122. # define UNCOND_UNLOCK() \
  123. AO_CLEAR(&GC_allocate_lock)
  124. # endif /* !GC_ASSERTIONS */
  125. # else /* THREAD_LOCAL_ALLOC || USE_PTHREAD_LOCKS */
  126. # ifndef USE_PTHREAD_LOCKS
  127. # define USE_PTHREAD_LOCKS
  128. # endif
  129. # endif /* THREAD_LOCAL_ALLOC || USE_PTHREAD_LOCK */
  130. # ifdef USE_PTHREAD_LOCKS
  131. # include <pthread.h>
  132. extern pthread_mutex_t GC_allocate_ml;
  133. # ifdef GC_ASSERTIONS
  134. # define UNCOND_LOCK() \
  135. { GC_lock(); \
  136. SET_LOCK_HOLDER(); }
  137. # define UNCOND_UNLOCK() \
  138. { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
  139. pthread_mutex_unlock(&GC_allocate_ml); }
  140. # else /* !GC_ASSERTIONS */
  141. # if defined(NO_PTHREAD_TRYLOCK)
  142. # define UNCOND_LOCK() GC_lock();
  143. # else /* !defined(NO_PTHREAD_TRYLOCK) */
  144. # define UNCOND_LOCK() \
  145. { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); }
  146. # endif
  147. # define UNCOND_UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
  148. # endif /* !GC_ASSERTIONS */
  149. # endif /* USE_PTHREAD_LOCKS */
  150. # define SET_LOCK_HOLDER() \
  151. GC_lock_holder = NUMERIC_THREAD_ID(pthread_self())
  152. # define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
  153. # define I_HOLD_LOCK() \
  154. (!GC_need_to_lock || \
  155. GC_lock_holder == NUMERIC_THREAD_ID(pthread_self()))
  156. # ifndef NUMERIC_THREAD_ID_UNIQUE
  157. # define I_DONT_HOLD_LOCK() 1 /* Conservatively say yes */
  158. # else
  159. # define I_DONT_HOLD_LOCK() \
  160. (!GC_need_to_lock \
  161. || GC_lock_holder != NUMERIC_THREAD_ID(pthread_self()))
  162. # endif
  163. extern volatile GC_bool GC_collecting;
  164. # define ENTER_GC() GC_collecting = 1;
  165. # define EXIT_GC() GC_collecting = 0;
  166. extern void GC_lock(void);
  167. extern unsigned long GC_lock_holder;
  168. # ifdef GC_ASSERTIONS
  169. extern unsigned long GC_mark_lock_holder;
  170. # endif
  171. # endif /* GC_PTHREADS with linux_threads.c implementation */
  172. # else /* !THREADS */
  173. # define LOCK()
  174. # define UNLOCK()
  175. # define SET_LOCK_HOLDER()
  176. # define UNSET_LOCK_HOLDER()
  177. # define I_HOLD_LOCK() TRUE
  178. # define I_DONT_HOLD_LOCK() TRUE
  179. /* Used only in positive assertions or to test whether */
  180. /* we still need to acaquire the lock. TRUE works in */
  181. /* either case. */
  182. # endif /* !THREADS */
  183. #if defined(UNCOND_LOCK) && !defined(LOCK)
  184. GC_API GC_bool GC_need_to_lock;
  185. /* At least two thread running; need to lock. */
  186. # define LOCK() if (GC_need_to_lock) { UNCOND_LOCK(); }
  187. # define UNLOCK() if (GC_need_to_lock) { UNCOND_UNLOCK(); }
  188. #endif
  189. # ifndef ENTER_GC
  190. # define ENTER_GC()
  191. # define EXIT_GC()
  192. # endif
  193. # ifndef DCL_LOCK_STATE
  194. # define DCL_LOCK_STATE
  195. # endif
  196. #endif /* GC_LOCKS_H */