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