Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
gc_locks.h
00001 /* 00002 * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers 00003 * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved. 00004 * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved. 00005 * Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved. 00006 * 00007 * 00008 * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED 00009 * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. 00010 * 00011 * Permission is hereby granted to use or copy this program 00012 * for any purpose, provided the above notices are retained on all copies. 00013 * Permission to modify the code and to distribute modified code is granted, 00014 * provided the above notices are retained, and a notice that the code was 00015 * modified is included with the above copyright notice. 00016 */ 00017 00018 #ifndef GC_LOCKS_H 00019 #define GC_LOCKS_H 00020 00021 /* 00022 * Mutual exclusion between allocator/collector routines. 00023 * Needed if there is more than one allocator thread. 00024 * FASTLOCK() is assumed to try to acquire the lock in a cheap and 00025 * dirty way that is acceptable for a few instructions, e.g. by 00026 * inhibiting preemption. This is assumed to have succeeded only 00027 * if a subsequent call to FASTLOCK_SUCCEEDED() returns TRUE. 00028 * FASTUNLOCK() is called whether or not FASTLOCK_SUCCEEDED(). 00029 * If signals cannot be tolerated with the FASTLOCK held, then 00030 * FASTLOCK should disable signals. The code executed under 00031 * FASTLOCK is otherwise immune to interruption, provided it is 00032 * not restarted. 00033 * DCL_LOCK_STATE declares any local variables needed by LOCK and UNLOCK 00034 * and/or DISABLE_SIGNALS and ENABLE_SIGNALS and/or FASTLOCK. 00035 * (There is currently no equivalent for FASTLOCK.) 00036 * 00037 * In the PARALLEL_MARK case, we also need to define a number of 00038 * other inline finctions here: 00039 * GC_bool GC_compare_and_exchange( volatile GC_word *addr, 00040 * GC_word old, GC_word new ) 00041 * GC_word GC_atomic_add( volatile GC_word *addr, GC_word how_much ) 00042 * void GC_memory_barrier( ) 00043 * 00044 */ 00045 # ifdef THREADS 00046 void GC_noop1 GC_PROTO((word)); 00047 # ifdef PCR_OBSOLETE /* Faster, but broken with multiple lwp's */ 00048 # include "th/PCR_Th.h" 00049 # include "th/PCR_ThCrSec.h" 00050 extern struct PCR_Th_MLRep GC_allocate_ml; 00051 # define DCL_LOCK_STATE PCR_sigset_t GC_old_sig_mask 00052 # define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml) 00053 # define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml) 00054 # define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml) 00055 # define FASTLOCK() PCR_ThCrSec_EnterSys() 00056 /* Here we cheat (a lot): */ 00057 # define FASTLOCK_SUCCEEDED() (*(int *)(&GC_allocate_ml) == 0) 00058 /* TRUE if nobody currently holds the lock */ 00059 # define FASTUNLOCK() PCR_ThCrSec_ExitSys() 00060 # endif 00061 # ifdef PCR 00062 # include <base/PCR_Base.h> 00063 # include <th/PCR_Th.h> 00064 extern PCR_Th_ML GC_allocate_ml; 00065 # define DCL_LOCK_STATE \ 00066 PCR_ERes GC_fastLockRes; PCR_sigset_t GC_old_sig_mask 00067 # define LOCK() PCR_Th_ML_Acquire(&GC_allocate_ml) 00068 # define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml) 00069 # define FASTLOCK() (GC_fastLockRes = PCR_Th_ML_Try(&GC_allocate_ml)) 00070 # define FASTLOCK_SUCCEEDED() (GC_fastLockRes == PCR_ERes_okay) 00071 # define FASTUNLOCK() {\ 00072 if( FASTLOCK_SUCCEEDED() ) PCR_Th_ML_Release(&GC_allocate_ml); } 00073 # endif 00074 # ifdef SRC_M3 00075 extern GC_word RT0u__inCritical; 00076 # define LOCK() RT0u__inCritical++ 00077 # define UNLOCK() RT0u__inCritical-- 00078 # endif 00079 # ifdef GC_SOLARIS_THREADS 00080 # include <thread.h> 00081 # include <signal.h> 00082 extern mutex_t GC_allocate_ml; 00083 # define LOCK() mutex_lock(&GC_allocate_ml); 00084 # define UNLOCK() mutex_unlock(&GC_allocate_ml); 00085 # endif 00086 00087 /* Try to define GC_TEST_AND_SET and a matching GC_CLEAR for spin lock */ 00088 /* acquisition and release. We need this for correct operation of the */ 00089 /* incremental GC. */ 00090 # ifdef __GNUC__ 00091 # if defined(I386) 00092 inline static int GC_test_and_set(volatile unsigned int *addr) { 00093 int oldval; 00094 /* Note: the "xchg" instruction does not need a "lock" prefix */ 00095 __asm__ __volatile__("xchgl %0, %1" 00096 : "=r"(oldval), "=m"(*(addr)) 00097 : "0"(1), "m"(*(addr)) : "memory"); 00098 return oldval; 00099 } 00100 # define GC_TEST_AND_SET_DEFINED 00101 # endif 00102 # if defined(IA64) 00103 # if defined(__INTEL_COMPILER) 00104 # include <ia64intrin.h> 00105 # endif 00106 inline static int GC_test_and_set(volatile unsigned int *addr) { 00107 long oldval, n = 1; 00108 # ifndef __INTEL_COMPILER 00109 __asm__ __volatile__("xchg4 %0=%1,%2" 00110 : "=r"(oldval), "=m"(*addr) 00111 : "r"(n), "1"(*addr) : "memory"); 00112 # else 00113 oldval = _InterlockedExchange(addr, n); 00114 # endif 00115 return oldval; 00116 } 00117 # define GC_TEST_AND_SET_DEFINED 00118 /* Should this handle post-increment addressing?? */ 00119 inline static void GC_clear(volatile unsigned int *addr) { 00120 # ifndef __INTEL_COMPILER 00121 __asm__ __volatile__("st4.rel %0=r0" : "=m" (*addr) : : "memory"); 00122 # else 00123 // there is no st4 but I can use xchg I hope 00124 _InterlockedExchange(addr, 0); 00125 # endif 00126 } 00127 # define GC_CLEAR_DEFINED 00128 # endif 00129 # ifdef SPARC 00130 inline static int GC_test_and_set(volatile unsigned int *addr) { 00131 int oldval; 00132 00133 __asm__ __volatile__("ldstub %1,%0" 00134 : "=r"(oldval), "=m"(*addr) 00135 : "m"(*addr) : "memory"); 00136 return oldval; 00137 } 00138 # define GC_TEST_AND_SET_DEFINED 00139 # endif 00140 # ifdef M68K 00141 /* Contributed by Tony Mantler. I'm not sure how well it was */ 00142 /* tested. */ 00143 inline static int GC_test_and_set(volatile unsigned int *addr) { 00144 char oldval; /* this must be no longer than 8 bits */ 00145 00146 /* The return value is semi-phony. */ 00147 /* 'tas' sets bit 7 while the return */ 00148 /* value pretends bit 0 was set */ 00149 __asm__ __volatile__( 00150 "tas %1@; sne %0; negb %0" 00151 : "=d" (oldval) 00152 : "a" (addr) : "memory"); 00153 return oldval; 00154 } 00155 # define GC_TEST_AND_SET_DEFINED 00156 # endif 00157 # if defined(POWERPC) 00158 # if CPP_WORDSZ == 64 00159 inline static int GC_test_and_set(volatile unsigned int *addr) { 00160 unsigned long oldval; 00161 unsigned long temp = 1; /* locked value */ 00162 00163 __asm__ __volatile__( 00164 "1:\tldarx %0,0,%3\n" /* load and reserve */ 00165 "\tcmpdi %0, 0\n" /* if load is */ 00166 "\tbne 2f\n" /* non-zero, return already set */ 00167 "\tstdcx. %2,0,%1\n" /* else store conditional */ 00168 "\tbne- 1b\n" /* retry if lost reservation */ 00169 "\tsync\n" /* import barrier */ 00170 "2:\t\n" /* oldval is zero if we set */ 00171 : "=&r"(oldval), "=p"(addr) 00172 : "r"(temp), "1"(addr) 00173 : "cr0","memory"); 00174 return (int)oldval; 00175 } 00176 # else 00177 inline static int GC_test_and_set(volatile unsigned int *addr) { 00178 int oldval; 00179 int temp = 1; /* locked value */ 00180 00181 __asm__ __volatile__( 00182 "1:\tlwarx %0,0,%3\n" /* load and reserve */ 00183 "\tcmpwi %0, 0\n" /* if load is */ 00184 "\tbne 2f\n" /* non-zero, return already set */ 00185 "\tstwcx. %2,0,%1\n" /* else store conditional */ 00186 "\tbne- 1b\n" /* retry if lost reservation */ 00187 "\tsync\n" /* import barrier */ 00188 "2:\t\n" /* oldval is zero if we set */ 00189 : "=&r"(oldval), "=p"(addr) 00190 : "r"(temp), "1"(addr) 00191 : "cr0","memory"); 00192 return oldval; 00193 } 00194 # endif 00195 # define GC_TEST_AND_SET_DEFINED 00196 inline static void GC_clear(volatile unsigned int *addr) { 00197 __asm__ __volatile__("lwsync" : : : "memory"); 00198 *(addr) = 0; 00199 } 00200 # define GC_CLEAR_DEFINED 00201 # endif 00202 # if defined(ALPHA) 00203 inline static int GC_test_and_set(volatile unsigned int * addr) 00204 { 00205 unsigned long oldvalue; 00206 unsigned long temp; 00207 00208 __asm__ __volatile__( 00209 "1: ldl_l %0,%1\n" 00210 " and %0,%3,%2\n" 00211 " bne %2,2f\n" 00212 " xor %0,%3,%0\n" 00213 " stl_c %0,%1\n" 00214 # ifdef __ELF__ 00215 " beq %0,3f\n" 00216 # else 00217 " beq %0,1b\n" 00218 # endif 00219 " mb\n" 00220 "2:\n" 00221 # ifdef __ELF__ 00222 ".section .text2,\"ax\"\n" 00223 "3: br 1b\n" 00224 ".previous" 00225 # endif 00226 :"=&r" (temp), "=m" (*addr), "=&r" (oldvalue) 00227 :"Ir" (1), "m" (*addr) 00228 :"memory"); 00229 00230 return oldvalue; 00231 } 00232 # define GC_TEST_AND_SET_DEFINED 00233 inline static void GC_clear(volatile unsigned int *addr) { 00234 __asm__ __volatile__("mb" : : : "memory"); 00235 *(addr) = 0; 00236 } 00237 # define GC_CLEAR_DEFINED 00238 # endif /* ALPHA */ 00239 # ifdef ARM32 00240 inline static int GC_test_and_set(volatile unsigned int *addr) { 00241 int oldval; 00242 /* SWP on ARM is very similar to XCHG on x86. Doesn't lock the 00243 * bus because there are no SMP ARM machines. If/when there are, 00244 * this code will likely need to be updated. */ 00245 /* See linuxthreads/sysdeps/arm/pt-machine.h in glibc-2.1 */ 00246 __asm__ __volatile__("swp %0, %1, [%2]" 00247 : "=r"(oldval) 00248 : "r"(1), "r"(addr) 00249 : "memory"); 00250 return oldval; 00251 } 00252 # define GC_TEST_AND_SET_DEFINED 00253 # endif /* ARM32 */ 00254 # ifdef CRIS 00255 inline static int GC_test_and_set(volatile unsigned int *addr) { 00256 /* Ripped from linuxthreads/sysdeps/cris/pt-machine.h. */ 00257 /* Included with Hans-Peter Nilsson's permission. */ 00258 register unsigned long int ret; 00259 00260 /* Note the use of a dummy output of *addr to expose the write. 00261 * The memory barrier is to stop *other* writes being moved past 00262 * this code. 00263 */ 00264 __asm__ __volatile__("clearf\n" 00265 "0:\n\t" 00266 "movu.b [%2],%0\n\t" 00267 "ax\n\t" 00268 "move.b %3,[%2]\n\t" 00269 "bwf 0b\n\t" 00270 "clearf" 00271 : "=&r" (ret), "=m" (*addr) 00272 : "r" (addr), "r" ((int) 1), "m" (*addr) 00273 : "memory"); 00274 return ret; 00275 } 00276 # define GC_TEST_AND_SET_DEFINED 00277 # endif /* CRIS */ 00278 # ifdef S390 00279 inline static int GC_test_and_set(volatile unsigned int *addr) { 00280 int ret; 00281 __asm__ __volatile__ ( 00282 " l %0,0(%2)\n" 00283 "0: cs %0,%1,0(%2)\n" 00284 " jl 0b" 00285 : "=&d" (ret) 00286 : "d" (1), "a" (addr) 00287 : "cc", "memory"); 00288 return ret; 00289 } 00290 # endif 00291 # endif /* __GNUC__ */ 00292 # if (defined(ALPHA) && !defined(__GNUC__)) 00293 # ifndef OSF1 00294 --> We currently assume that if gcc is not used, we are 00295 --> running under Tru64. 00296 # endif 00297 # include <machine/builtins.h> 00298 # include <c_asm.h> 00299 # define GC_test_and_set(addr) __ATOMIC_EXCH_LONG(addr, 1) 00300 # define GC_TEST_AND_SET_DEFINED 00301 # define GC_clear(addr) { asm("mb"); *(volatile unsigned *)addr = 0; } 00302 # define GC_CLEAR_DEFINED 00303 # endif 00304 # if defined(MSWIN32) 00305 # define GC_test_and_set(addr) InterlockedExchange((LPLONG)addr,1) 00306 # define GC_TEST_AND_SET_DEFINED 00307 # endif 00308 # ifdef MIPS 00309 # ifdef LINUX 00310 # include <sys/tas.h> 00311 # define GC_test_and_set(addr) _test_and_set((int *) addr,1) 00312 # define GC_TEST_AND_SET_DEFINED 00313 # elif __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \ 00314 || !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700 00315 # ifdef __GNUC__ 00316 # define GC_test_and_set(addr) _test_and_set((void *)addr,1) 00317 # else 00318 # define GC_test_and_set(addr) test_and_set((void *)addr,1) 00319 # endif 00320 # else 00321 # include <sgidefs.h> 00322 # include <mutex.h> 00323 # define GC_test_and_set(addr) __test_and_set32((void *)addr,1) 00324 # define GC_clear(addr) __lock_release(addr); 00325 # define GC_CLEAR_DEFINED 00326 # endif 00327 # define GC_TEST_AND_SET_DEFINED 00328 # endif /* MIPS */ 00329 # if defined(_AIX) 00330 # include <sys/atomic_op.h> 00331 # if (defined(_POWER) || defined(_POWERPC)) 00332 # if defined(__GNUC__) 00333 inline static void GC_memsync() { 00334 __asm__ __volatile__ ("sync" : : : "memory"); 00335 } 00336 # else 00337 # ifndef inline 00338 # define inline __inline 00339 # endif 00340 # pragma mc_func GC_memsync { \ 00341 "7c0004ac" /* sync (same opcode used for dcs)*/ \ 00342 } 00343 # endif 00344 # else 00345 # error dont know how to memsync 00346 # endif 00347 inline static int GC_test_and_set(volatile unsigned int * addr) { 00348 int oldvalue = 0; 00349 if (compare_and_swap((void *)addr, &oldvalue, 1)) { 00350 GC_memsync(); 00351 return 0; 00352 } else return 1; 00353 } 00354 # define GC_TEST_AND_SET_DEFINED 00355 inline static void GC_clear(volatile unsigned int *addr) { 00356 GC_memsync(); 00357 *(addr) = 0; 00358 } 00359 # define GC_CLEAR_DEFINED 00360 00361 # endif 00362 # if 0 /* defined(HP_PA) */ 00363 /* The official recommendation seems to be to not use ldcw from */ 00364 /* user mode. Since multithreaded incremental collection doesn't */ 00365 /* work anyway on HP_PA, this shouldn't be a major loss. */ 00366 00367 /* "set" means 0 and "clear" means 1 here. */ 00368 # define GC_test_and_set(addr) !GC_test_and_clear(addr); 00369 # define GC_TEST_AND_SET_DEFINED 00370 # define GC_clear(addr) GC_noop1((word)(addr)); *(volatile unsigned int *)addr = 1; 00371 /* The above needs a memory barrier! */ 00372 # define GC_CLEAR_DEFINED 00373 # endif 00374 # if defined(GC_TEST_AND_SET_DEFINED) && !defined(GC_CLEAR_DEFINED) 00375 # ifdef __GNUC__ 00376 inline static void GC_clear(volatile unsigned int *addr) { 00377 /* Try to discourage gcc from moving anything past this. */ 00378 __asm__ __volatile__(" " : : : "memory"); 00379 *(addr) = 0; 00380 } 00381 # else 00382 /* The function call in the following should prevent the */ 00383 /* compiler from moving assignments to below the UNLOCK. */ 00384 # define GC_clear(addr) GC_noop1((word)(addr)); \ 00385 *((volatile unsigned int *)(addr)) = 0; 00386 # endif 00387 # define GC_CLEAR_DEFINED 00388 # endif /* !GC_CLEAR_DEFINED */ 00389 00390 # if !defined(GC_TEST_AND_SET_DEFINED) 00391 # define USE_PTHREAD_LOCKS 00392 # endif 00393 00394 # if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \ 00395 && !defined(GC_WIN32_THREADS) 00396 # define NO_THREAD (pthread_t)(-1) 00397 # include <pthread.h> 00398 # if defined(PARALLEL_MARK) 00399 /* We need compare-and-swap to update mark bits, where it's */ 00400 /* performance critical. If USE_MARK_BYTES is defined, it is */ 00401 /* no longer needed for this purpose. However we use it in */ 00402 /* either case to implement atomic fetch-and-add, though that's */ 00403 /* less performance critical, and could perhaps be done with */ 00404 /* a lock. */ 00405 # if defined(GENERIC_COMPARE_AND_SWAP) 00406 /* Probably not useful, except for debugging. */ 00407 /* We do use GENERIC_COMPARE_AND_SWAP on PA_RISC, but we */ 00408 /* minimize its use. */ 00409 extern pthread_mutex_t GC_compare_and_swap_lock; 00410 00411 /* Note that if GC_word updates are not atomic, a concurrent */ 00412 /* reader should acquire GC_compare_and_swap_lock. On */ 00413 /* currently supported platforms, such updates are atomic. */ 00414 extern GC_bool GC_compare_and_exchange(volatile GC_word *addr, 00415 GC_word old, GC_word new_val); 00416 # endif /* GENERIC_COMPARE_AND_SWAP */ 00417 # if defined(I386) 00418 # if !defined(GENERIC_COMPARE_AND_SWAP) 00419 /* Returns TRUE if the comparison succeeded. */ 00420 inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr, 00421 GC_word old, 00422 GC_word new_val) 00423 { 00424 char result; 00425 __asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1" 00426 : "+m"(*(addr)), "=r"(result) 00427 : "r" (new_val), "a"(old) : "memory"); 00428 return (GC_bool) result; 00429 } 00430 # endif /* !GENERIC_COMPARE_AND_SWAP */ 00431 inline static void GC_memory_barrier() 00432 { 00433 /* We believe the processor ensures at least processor */ 00434 /* consistent ordering. Thus a compiler barrier */ 00435 /* should suffice. */ 00436 __asm__ __volatile__("" : : : "memory"); 00437 } 00438 # endif /* I386 */ 00439 00440 # if defined(POWERPC) 00441 # if !defined(GENERIC_COMPARE_AND_SWAP) 00442 # if CPP_WORDSZ == 64 00443 /* Returns TRUE if the comparison succeeded. */ 00444 inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr, 00445 GC_word old, GC_word new_val) 00446 { 00447 unsigned long result, dummy; 00448 __asm__ __volatile__( 00449 "1:\tldarx %0,0,%5\n" 00450 "\tcmpd %0,%4\n" 00451 "\tbne 2f\n" 00452 "\tstdcx. %3,0,%2\n" 00453 "\tbne- 1b\n" 00454 "\tsync\n" 00455 "\tli %1, 1\n" 00456 "\tb 3f\n" 00457 "2:\tli %1, 0\n" 00458 "3:\t\n" 00459 : "=&r" (dummy), "=r" (result), "=p" (addr) 00460 : "r" (new_val), "r" (old), "2"(addr) 00461 : "cr0","memory"); 00462 return (GC_bool) result; 00463 } 00464 # else 00465 /* Returns TRUE if the comparison succeeded. */ 00466 inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr, 00467 GC_word old, GC_word new_val) 00468 { 00469 int result, dummy; 00470 __asm__ __volatile__( 00471 "1:\tlwarx %0,0,%5\n" 00472 "\tcmpw %0,%4\n" 00473 "\tbne 2f\n" 00474 "\tstwcx. %3,0,%2\n" 00475 "\tbne- 1b\n" 00476 "\tsync\n" 00477 "\tli %1, 1\n" 00478 "\tb 3f\n" 00479 "2:\tli %1, 0\n" 00480 "3:\t\n" 00481 : "=&r" (dummy), "=r" (result), "=p" (addr) 00482 : "r" (new_val), "r" (old), "2"(addr) 00483 : "cr0","memory"); 00484 return (GC_bool) result; 00485 } 00486 # endif 00487 # endif /* !GENERIC_COMPARE_AND_SWAP */ 00488 inline static void GC_memory_barrier() 00489 { 00490 __asm__ __volatile__("sync" : : : "memory"); 00491 } 00492 # endif /* POWERPC */ 00493 00494 # if defined(IA64) 00495 # if !defined(GENERIC_COMPARE_AND_SWAP) 00496 inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr, 00497 GC_word old, GC_word new_val) 00498 { 00499 unsigned long oldval; 00500 # if CPP_WORDSZ == 32 00501 __asm__ __volatile__( 00502 "addp4 %0=0,%1\n" 00503 "mov ar.ccv=%3 ;; cmpxchg4.rel %0=[%0],%2,ar.ccv" 00504 : "=&r"(oldval) 00505 : "r"(addr), "r"(new_val), "r"(old) : "memory"); 00506 # else 00507 __asm__ __volatile__( 00508 "mov ar.ccv=%3 ;; cmpxchg8.rel %0=[%1],%2,ar.ccv" 00509 : "=r"(oldval) 00510 : "r"(addr), "r"(new_val), "r"(old) : "memory"); 00511 # endif 00512 return (oldval == old); 00513 } 00514 # endif /* !GENERIC_COMPARE_AND_SWAP */ 00515 # if 0 00516 /* Shouldn't be needed; we use volatile stores instead. */ 00517 inline static void GC_memory_barrier() 00518 { 00519 __asm__ __volatile__("mf" : : : "memory"); 00520 } 00521 # endif /* 0 */ 00522 # endif /* IA64 */ 00523 # if defined(ALPHA) 00524 # if !defined(GENERIC_COMPARE_AND_SWAP) 00525 # if defined(__GNUC__) 00526 inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr, 00527 GC_word old, GC_word new_val) 00528 { 00529 unsigned long was_equal; 00530 unsigned long temp; 00531 00532 __asm__ __volatile__( 00533 "1: ldq_l %0,%1\n" 00534 " cmpeq %0,%4,%2\n" 00535 " mov %3,%0\n" 00536 " beq %2,2f\n" 00537 " stq_c %0,%1\n" 00538 " beq %0,1b\n" 00539 "2:\n" 00540 " mb\n" 00541 :"=&r" (temp), "=m" (*addr), "=&r" (was_equal) 00542 : "r" (new_val), "Ir" (old) 00543 :"memory"); 00544 return was_equal; 00545 } 00546 # else /* !__GNUC__ */ 00547 inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr, 00548 GC_word old, GC_word new_val) 00549 { 00550 return __CMP_STORE_QUAD(addr, old, new_val, addr); 00551 } 00552 # endif /* !__GNUC__ */ 00553 # endif /* !GENERIC_COMPARE_AND_SWAP */ 00554 # ifdef __GNUC__ 00555 inline static void GC_memory_barrier() 00556 { 00557 __asm__ __volatile__("mb" : : : "memory"); 00558 } 00559 # else 00560 # define GC_memory_barrier() asm("mb") 00561 # endif /* !__GNUC__ */ 00562 # endif /* ALPHA */ 00563 # if defined(S390) 00564 # if !defined(GENERIC_COMPARE_AND_SWAP) 00565 inline static GC_bool GC_compare_and_exchange(volatile C_word *addr, 00566 GC_word old, GC_word new_val) 00567 { 00568 int retval; 00569 __asm__ __volatile__ ( 00570 # ifndef __s390x__ 00571 " cs %1,%2,0(%3)\n" 00572 # else 00573 " csg %1,%2,0(%3)\n" 00574 # endif 00575 " ipm %0\n" 00576 " srl %0,28\n" 00577 : "=&d" (retval), "+d" (old) 00578 : "d" (new_val), "a" (addr) 00579 : "cc", "memory"); 00580 return retval == 0; 00581 } 00582 # endif 00583 # endif 00584 # if !defined(GENERIC_COMPARE_AND_SWAP) 00585 /* Returns the original value of *addr. */ 00586 inline static GC_word GC_atomic_add(volatile GC_word *addr, 00587 GC_word how_much) 00588 { 00589 GC_word old; 00590 do { 00591 old = *addr; 00592 } while (!GC_compare_and_exchange(addr, old, old+how_much)); 00593 return old; 00594 } 00595 # else /* GENERIC_COMPARE_AND_SWAP */ 00596 /* So long as a GC_word can be atomically updated, it should */ 00597 /* be OK to read *addr without a lock. */ 00598 extern GC_word GC_atomic_add(volatile GC_word *addr, GC_word how_much); 00599 # endif /* GENERIC_COMPARE_AND_SWAP */ 00600 00601 # endif /* PARALLEL_MARK */ 00602 00603 # if !defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_LOCKS) 00604 /* In the THREAD_LOCAL_ALLOC case, the allocation lock tends to */ 00605 /* be held for long periods, if it is held at all. Thus spinning */ 00606 /* and sleeping for fixed periods are likely to result in */ 00607 /* significant wasted time. We thus rely mostly on queued locks. */ 00608 # define USE_SPIN_LOCK 00609 extern volatile unsigned int GC_allocate_lock; 00610 extern void GC_lock(void); 00611 /* Allocation lock holder. Only set if acquired by client through */ 00612 /* GC_call_with_alloc_lock. */ 00613 # ifdef GC_ASSERTIONS 00614 # define LOCK() \ 00615 { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); \ 00616 SET_LOCK_HOLDER(); } 00617 # define UNLOCK() \ 00618 { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \ 00619 GC_clear(&GC_allocate_lock); } 00620 # else 00621 # define LOCK() \ 00622 { if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); } 00623 # define UNLOCK() \ 00624 GC_clear(&GC_allocate_lock) 00625 # endif /* !GC_ASSERTIONS */ 00626 # if 0 00627 /* Another alternative for OSF1 might be: */ 00628 # include <sys/mman.h> 00629 extern msemaphore GC_allocate_semaphore; 00630 # define LOCK() { if (msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) \ 00631 != 0) GC_lock(); else GC_allocate_lock = 1; } 00632 /* The following is INCORRECT, since the memory model is too weak. */ 00633 /* Is this true? Presumably msem_unlock has the right semantics? */ 00634 /* - HB */ 00635 # define UNLOCK() { GC_allocate_lock = 0; \ 00636 msem_unlock(&GC_allocate_semaphore, 0); } 00637 # endif /* 0 */ 00638 # else /* THREAD_LOCAL_ALLOC || USE_PTHREAD_LOCKS */ 00639 # ifndef USE_PTHREAD_LOCKS 00640 # define USE_PTHREAD_LOCKS 00641 # endif 00642 # endif /* THREAD_LOCAL_ALLOC */ 00643 # ifdef USE_PTHREAD_LOCKS 00644 # include <pthread.h> 00645 extern pthread_mutex_t GC_allocate_ml; 00646 # ifdef GC_ASSERTIONS 00647 # define LOCK() \ 00648 { GC_lock(); \ 00649 SET_LOCK_HOLDER(); } 00650 # define UNLOCK() \ 00651 { GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \ 00652 pthread_mutex_unlock(&GC_allocate_ml); } 00653 # else /* !GC_ASSERTIONS */ 00654 # if defined(NO_PTHREAD_TRYLOCK) 00655 # define LOCK() GC_lock(); 00656 # else /* !defined(NO_PTHREAD_TRYLOCK) */ 00657 # define LOCK() \ 00658 { if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); } 00659 # endif 00660 # define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml) 00661 # endif /* !GC_ASSERTIONS */ 00662 # endif /* USE_PTHREAD_LOCKS */ 00663 # define SET_LOCK_HOLDER() GC_lock_holder = pthread_self() 00664 # define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD 00665 # define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self())) 00666 extern VOLATILE GC_bool GC_collecting; 00667 # define ENTER_GC() GC_collecting = 1; 00668 # define EXIT_GC() GC_collecting = 0; 00669 extern void GC_lock(void); 00670 extern pthread_t GC_lock_holder; 00671 # ifdef GC_ASSERTIONS 00672 extern pthread_t GC_mark_lock_holder; 00673 # endif 00674 # endif /* GC_PTHREADS with linux_threads.c implementation */ 00675 # if defined(GC_WIN32_THREADS) 00676 # if defined(GC_PTHREADS) 00677 # include <pthread.h> 00678 extern pthread_mutex_t GC_allocate_ml; 00679 # define LOCK() pthread_mutex_lock(&GC_allocate_ml) 00680 # define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml) 00681 # else 00682 # include <windows.h> 00683 GC_API CRITICAL_SECTION GC_allocate_ml; 00684 # define LOCK() EnterCriticalSection(&GC_allocate_ml); 00685 # define UNLOCK() LeaveCriticalSection(&GC_allocate_ml); 00686 # endif 00687 # endif 00688 # ifndef SET_LOCK_HOLDER 00689 # define SET_LOCK_HOLDER() 00690 # define UNSET_LOCK_HOLDER() 00691 # define I_HOLD_LOCK() FALSE 00692 /* Used on platforms were locks can be reacquired, */ 00693 /* so it doesn't matter if we lie. */ 00694 # endif 00695 # else /* !THREADS */ 00696 # define LOCK() 00697 # define UNLOCK() 00698 # endif /* !THREADS */ 00699 # ifndef SET_LOCK_HOLDER 00700 # define SET_LOCK_HOLDER() 00701 # define UNSET_LOCK_HOLDER() 00702 # define I_HOLD_LOCK() FALSE 00703 /* Used on platforms were locks can be reacquired, */ 00704 /* so it doesn't matter if we lie. */ 00705 # endif 00706 # ifndef ENTER_GC 00707 # define ENTER_GC() 00708 # define EXIT_GC() 00709 # endif 00710 00711 # ifndef DCL_LOCK_STATE 00712 # define DCL_LOCK_STATE 00713 # endif 00714 # ifndef FASTLOCK 00715 # define FASTLOCK() LOCK() 00716 # define FASTLOCK_SUCCEEDED() TRUE 00717 # define FASTUNLOCK() UNLOCK() 00718 # endif 00719 00720 #endif /* GC_LOCKS_H */
Generated on Tue Jul 12 2022 19:59:53 by
