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