summaryrefslogtreecommitdiff
path: root/tools/build/src/engine/boehm_gc/include/private/gc_locks.h
blob: d7c83b07b9129ea6ab604a456df04a83479a867c (plain)
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 LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml)
#    define 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 (-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 */