#ifndef GC_LOCKS_H
#define GC_LOCKS_H
# ifdef THREADS
void GC_noop1 GC_PROTO((word));
# ifdef PCR_OBSOLETE
# include "th/PCR_Th.h"
# include "th/PCR_ThCrSec.h"
extern struct PCR_Th_MLRep GC_allocate_ml;
# define DCL_LOCK_STATE 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)
# define UNLOCK() PCR_Th_ML_Release(&GC_allocate_ml)
# define FASTLOCK() PCR_ThCrSec_EnterSys()
# define FASTLOCK_SUCCEEDED() (*(int *)(&GC_allocate_ml) == 0)
# define FASTUNLOCK() PCR_ThCrSec_ExitSys()
# endif
# 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)
# define FASTLOCK() (GC_fastLockRes = PCR_Th_ML_Try(&GC_allocate_ml))
# define FASTLOCK_SUCCEEDED() (GC_fastLockRes == PCR_ERes_okay)
# define FASTUNLOCK() {\
if( FASTLOCK_SUCCEEDED() ) PCR_Th_ML_Release(&GC_allocate_ml); }
# endif
# ifdef SRC_M3
extern GC_word RT0u__inCritical;
# define LOCK() RT0u__inCritical++
# define UNLOCK() RT0u__inCritical--
# endif
# ifdef GC_SOLARIS_THREADS
# include <thread.h>
# include <signal.h>
extern mutex_t GC_allocate_ml;
# define LOCK() mutex_lock(&GC_allocate_ml);
# define UNLOCK() mutex_unlock(&GC_allocate_ml);
# endif
# ifdef __GNUC__
# if defined(I386)
inline static int GC_test_and_set(volatile unsigned int *addr) {
int oldval;
__asm__ __volatile__("xchgl %0, %1"
: "=r"(oldval), "=m"(*(addr))
: "0"(1), "m"(*(addr)) : "memory");
return oldval;
}
# define GC_TEST_AND_SET_DEFINED
# endif
# if defined(IA64)
# include <ia64intrin.h>
inline static int GC_test_and_set(volatile unsigned int *addr) {
return __sync_lock_test_and_set(addr, 1);
}
# define GC_TEST_AND_SET_DEFINED
inline static void GC_clear(volatile unsigned int *addr) {
*addr = 0;
}
# define GC_CLEAR_DEFINED
# endif
# ifdef SPARC
inline static int GC_test_and_set(volatile unsigned int *addr) {
int oldval;
__asm__ __volatile__("ldstub %1,%0"
: "=r"(oldval), "=m"(*addr)
: "m"(*addr) : "memory");
return oldval;
}
# define GC_TEST_AND_SET_DEFINED
# endif
# ifdef M68K
inline static int GC_test_and_set(volatile unsigned int *addr) {
char oldval;
__asm__ __volatile__(
"tas %1@; sne %0; negb %0"
: "=d" (oldval)
: "a" (addr) : "memory");
return oldval;
}
# define GC_TEST_AND_SET_DEFINED
# endif
# if defined(POWERPC)
# if 0
inline static int GC_test_and_set(volatile unsigned int *addr) {
unsigned long oldval;
unsigned long temp = 1;
__asm__ __volatile__(
"1:\tldarx %0,0,%3\n"
"\tcmpdi %0, 0\n"
"\tbne 2f\n"
"\tstdcx. %2,0,%1\n"
"\tbne- 1b\n"
"\tsync\n"
"2:\t\n"
: "=&r"(oldval), "=p"(addr)
: "r"(temp), "1"(addr)
: "cr0","memory");
return (int)oldval;
}
# else
inline static int GC_test_and_set(volatile unsigned int *addr) {
int oldval;
int temp = 1;
__asm__ __volatile__(
"1:\tlwarx %0,0,%3\n"
"\tcmpwi %0, 0\n"
"\tbne 2f\n"
"\tstwcx. %2,0,%1\n"
"\tbne- 1b\n"
"\tsync\n"
"2:\t\n"
: "=&r"(oldval), "=p"(addr)
: "r"(temp), "1"(addr)
: "cr0","memory");
return oldval;
}
# endif
# define GC_TEST_AND_SET_DEFINED
inline static void GC_clear(volatile unsigned int *addr) {
__asm__ __volatile__("lwsync" : : : "memory");
*(addr) = 0;
}
# define GC_CLEAR_DEFINED
# endif
# if defined(ALPHA)
inline static int GC_test_and_set(volatile unsigned int * addr)
{
unsigned long oldvalue;
unsigned long temp;
__asm__ __volatile__(
"1: ldl_l %0,%1\n"
" and %0,%3,%2\n"
" bne %2,2f\n"
" xor %0,%3,%0\n"
" stl_c %0,%1\n"
# ifdef __ELF__
" beq %0,3f\n"
# else
" beq %0,1b\n"
# endif
" mb\n"
"2:\n"
# ifdef __ELF__
".section .text2,\"ax\"\n"
"3: br 1b\n"
".previous"
# endif
:"=&r" (temp), "=m" (*addr), "=&r" (oldvalue)
:"Ir" (1), "m" (*addr)
:"memory");
return oldvalue;
}
# define GC_TEST_AND_SET_DEFINED
inline static void GC_clear(volatile unsigned int *addr) {
__asm__ __volatile__("mb" : : : "memory");
*(addr) = 0;
}
# define GC_CLEAR_DEFINED
# endif
# ifdef ARM32
inline static int GC_test_and_set(volatile unsigned int *addr) {
int oldval;
__asm__ __volatile__("swp %0, %1, [%2]"
: "=r"(oldval)
: "0"(1), "r"(addr)
: "memory");
return oldval;
}
# define GC_TEST_AND_SET_DEFINED
# endif
# ifdef CRIS
inline static int GC_test_and_set(volatile unsigned int *addr) {
register unsigned long int ret;
__asm__ __volatile__("clearf\n"
"0:\n\t"
"movu.b [%2],%0\n\t"
"ax\n\t"
"move.b %3,[%2]\n\t"
"bwf 0b\n\t"
"clearf"
: "=&r" (ret), "=m" (*addr)
: "r" (addr), "r" ((int) 1), "m" (*addr)
: "memory");
return ret;
}
# define GC_TEST_AND_SET_DEFINED
# endif
# ifdef S390
inline static int GC_test_and_set(volatile unsigned int *addr) {
int ret;
__asm__ __volatile__ (
" l %0,0(%2)\n"
"0: cs %0,%1,0(%2)\n"
" jl 0b"
: "=&d" (ret)
: "d" (1), "a" (addr)
: "cc", "memory");
return ret;
}
# endif
# endif
# if (defined(ALPHA) && !defined(__GNUC__))
# ifndef OSF1
--> We currently assume that if gcc is not used, we are
--> running under Tru64.
# endif
# include <machine/builtins.h>
# include <c_asm.h>
# define GC_test_and_set(addr) __ATOMIC_EXCH_LONG(addr, 1)
# define GC_TEST_AND_SET_DEFINED
# define GC_clear(addr) { asm("mb"); *(volatile unsigned *)addr = 0; }
# define GC_CLEAR_DEFINED
# endif
# if defined(MSWIN32)
# define GC_test_and_set(addr) InterlockedExchange((LPLONG)addr,1)
# define GC_TEST_AND_SET_DEFINED
# endif
# ifdef MIPS
# ifdef LINUX
# include <sys/tas.h>
# define GC_test_and_set(addr) _test_and_set((int *) addr,1)
# define GC_TEST_AND_SET_DEFINED
# elif __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
|| !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700
# ifdef __GNUC__
# define GC_test_and_set(addr) _test_and_set((void *)addr,1)
# else
# define GC_test_and_set(addr) test_and_set((void *)addr,1)
# endif
# else
# include <sgidefs.h>
# include <mutex.h>
# define GC_test_and_set(addr) __test_and_set32((void *)addr,1)
# define GC_clear(addr) __lock_release(addr);
# define GC_CLEAR_DEFINED
# endif
# define GC_TEST_AND_SET_DEFINED
# endif
# if defined(_AIX)
# include <sys/atomic_op.h>
# if (defined(_POWER) || defined(_POWERPC))
# if defined(__GNUC__)
inline static void GC_memsync() {
__asm__ __volatile__ ("sync" : : : "memory");
}
# else
# ifndef inline
# define inline __inline
# endif
# pragma mc_func GC_memsync { \
"7c0004ac" \
}
# endif
# else
# error dont know how to memsync
# endif
inline static int GC_test_and_set(volatile unsigned int * addr) {
int oldvalue = 0;
if (compare_and_swap((void *)addr, &oldvalue, 1)) {
GC_memsync();
return 0;
} else return 1;
}
# define GC_TEST_AND_SET_DEFINED
inline static void GC_clear(volatile unsigned int *addr) {
GC_memsync();
*(addr) = 0;
}
# define GC_CLEAR_DEFINED
# endif
# if 0
# define GC_test_and_set(addr) !GC_test_and_clear(addr);
# define GC_TEST_AND_SET_DEFINED
# define GC_clear(addr) GC_noop1((word)(addr)); *(volatile unsigned int *)addr = 1;
# define GC_CLEAR_DEFINED
# endif
# if defined(GC_TEST_AND_SET_DEFINED) && !defined(GC_CLEAR_DEFINED)
# ifdef __GNUC__
inline static void GC_clear(volatile unsigned int *addr) {
__asm__ __volatile__(" " : : : "memory");
*(addr) = 0;
}
# else
# define GC_clear(addr) GC_noop1((word)(addr)); \
*((volatile unsigned int *)(addr)) = 0;
# endif
# define GC_CLEAR_DEFINED
# endif
# if !defined(GC_TEST_AND_SET_DEFINED)
# define USE_PTHREAD_LOCKS
# endif
# if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
&& !defined(GC_WIN32_THREADS)
# define NO_THREAD (pthread_t)(-1)
# include <pthread.h>
# if defined(PARALLEL_MARK)
# if defined(GENERIC_COMPARE_AND_SWAP)
extern pthread_mutex_t GC_compare_and_swap_lock;
extern GC_bool GC_compare_and_exchange(volatile GC_word *addr,
GC_word old, GC_word new_val);
# endif
# if defined(I386)
# if !defined(GENERIC_COMPARE_AND_SWAP)
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
GC_word old,
GC_word new_val)
{
char result;
__asm__ __volatile__("lock; cmpxchgl %2, %0; setz %1"
: "+m"(*(addr)), "=r"(result)
: "r" (new_val), "a"(old) : "memory");
return (GC_bool) result;
}
# endif
inline static void GC_memory_barrier()
{
__asm__ __volatile__("" : : : "memory");
}
# endif
# if defined(POWERPC)
# if !defined(GENERIC_COMPARE_AND_SWAP)
# if CPP_WORDSZ == 64
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
GC_word old, GC_word new_val)
{
unsigned long result, dummy;
__asm__ __volatile__(
"1:\tldarx %0,0,%5\n"
"\tcmpd %0,%4\n"
"\tbne 2f\n"
"\tstdcx. %3,0,%2\n"
"\tbne- 1b\n"
"\tsync\n"
"\tli %1, 1\n"
"\tb 3f\n"
"2:\tli %1, 0\n"
"3:\t\n"
: "=&r" (dummy), "=r" (result), "=p" (addr)
: "r" (new_val), "r" (old), "2"(addr)
: "cr0","memory");
return (GC_bool) result;
}
# else
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
GC_word old, GC_word new_val)
{
int result, dummy;
__asm__ __volatile__(
"1:\tlwarx %0,0,%5\n"
"\tcmpw %0,%4\n"
"\tbne 2f\n"
"\tstwcx. %3,0,%2\n"
"\tbne- 1b\n"
"\tsync\n"
"\tli %1, 1\n"
"\tb 3f\n"
"2:\tli %1, 0\n"
"3:\t\n"
: "=&r" (dummy), "=r" (result), "=p" (addr)
: "r" (new_val), "r" (old), "2"(addr)
: "cr0","memory");
return (GC_bool) result;
}
# endif
# endif
inline static void GC_memory_barrier()
{
__asm__ __volatile__("sync" : : : "memory");
}
# endif
# if defined(IA64)
# if !defined(GENERIC_COMPARE_AND_SWAP)
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
GC_word old,
GC_word new_val)
{
return __sync_bool_compare_and_swap (addr, old, new_val);
}
# endif
# if 0
inline static void GC_memory_barrier()
{
__sync_synchronize ();
}
# endif
# endif
# if defined(ALPHA)
# if !defined(GENERIC_COMPARE_AND_SWAP)
# if defined(__GNUC__)
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
GC_word old, GC_word new_val)
{
unsigned long was_equal;
unsigned long temp;
__asm__ __volatile__(
"1: ldq_l %0,%1\n"
" cmpeq %0,%4,%2\n"
" mov %3,%0\n"
" beq %2,2f\n"
" stq_c %0,%1\n"
" beq %0,1b\n"
"2:\n"
" mb\n"
:"=&r" (temp), "=m" (*addr), "=&r" (was_equal)
: "r" (new_val), "Ir" (old)
:"memory");
return was_equal;
}
# else
inline static GC_bool GC_compare_and_exchange(volatile GC_word *addr,
GC_word old, GC_word new_val)
{
return __CMP_STORE_QUAD(addr, old, new_val, addr);
}
# endif
# endif
# ifdef __GNUC__
inline static void GC_memory_barrier()
{
__asm__ __volatile__("mb" : : : "memory");
}
# else
# define GC_memory_barrier() asm("mb")
# endif
# endif
# if defined(S390)
# if !defined(GENERIC_COMPARE_AND_SWAP)
inline static GC_bool GC_compare_and_exchange(volatile C_word *addr,
GC_word old, GC_word new_val)
{
int retval;
__asm__ __volatile__ (
# ifndef __s390x__
" cs %1,%2,0(%3)\n"
# else
" csg %1,%2,0(%3)\n"
# endif
" ipm %0\n"
" srl %0,28\n"
: "=&d" (retval), "+d" (old)
: "d" (new_val), "a" (addr)
: "cc", "memory");
return retval == 0;
}
# endif
# endif
# if !defined(GENERIC_COMPARE_AND_SWAP)
inline static GC_word GC_atomic_add(volatile GC_word *addr,
GC_word how_much)
{
GC_word old;
do {
old = *addr;
} while (!GC_compare_and_exchange(addr, old, old+how_much));
return old;
}
# else
extern GC_word GC_atomic_add(volatile GC_word *addr, GC_word how_much);
# endif
# endif
# if !defined(THREAD_LOCAL_ALLOC) && !defined(USE_PTHREAD_LOCKS)
# define USE_SPIN_LOCK
extern volatile unsigned int GC_allocate_lock;
extern void GC_lock(void);
# ifdef GC_ASSERTIONS
# define LOCK() \
{ if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); \
SET_LOCK_HOLDER(); }
# define UNLOCK() \
{ GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
GC_clear(&GC_allocate_lock); }
# else
# define LOCK() \
{ if (GC_test_and_set(&GC_allocate_lock)) GC_lock(); }
# define UNLOCK() \
GC_clear(&GC_allocate_lock)
# endif
# if 0
# include <sys/mman.h>
extern msemaphore GC_allocate_semaphore;
# define LOCK() { if (msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) \
!= 0) GC_lock(); else GC_allocate_lock = 1; }
# define UNLOCK() { GC_allocate_lock = 0; \
msem_unlock(&GC_allocate_semaphore, 0); }
# endif
# else
# ifndef USE_PTHREAD_LOCKS
# define USE_PTHREAD_LOCKS
# endif
# endif
# ifdef USE_PTHREAD_LOCKS
# include <pthread.h>
extern pthread_mutex_t GC_allocate_ml;
# ifdef GC_ASSERTIONS
# define LOCK() \
{ GC_lock(); \
SET_LOCK_HOLDER(); }
# define UNLOCK() \
{ GC_ASSERT(I_HOLD_LOCK()); UNSET_LOCK_HOLDER(); \
pthread_mutex_unlock(&GC_allocate_ml); }
# else
# if defined(NO_PTHREAD_TRYLOCK)
# define LOCK() GC_lock();
# else
# define LOCK() \
{ if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); }
# endif
# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
# endif
# endif
# define SET_LOCK_HOLDER() GC_lock_holder = pthread_self()
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self()))
extern VOLATILE GC_bool GC_collecting;
# define ENTER_GC() GC_collecting = 1;
# define EXIT_GC() GC_collecting = 0;
extern void GC_lock(void);
extern pthread_t GC_lock_holder;
# ifdef GC_ASSERTIONS
extern pthread_t GC_mark_lock_holder;
# endif
# endif
# if defined(GC_WIN32_THREADS)
# if defined(GC_PTHREADS)
# include <pthread.h>
extern pthread_mutex_t GC_allocate_ml;
# define LOCK() pthread_mutex_lock(&GC_allocate_ml)
# define UNLOCK() pthread_mutex_unlock(&GC_allocate_ml)
# else
# include <windows.h>
GC_API CRITICAL_SECTION GC_allocate_ml;
# define LOCK() EnterCriticalSection(&GC_allocate_ml);
# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
# endif
# endif
# ifndef SET_LOCK_HOLDER
# define SET_LOCK_HOLDER()
# define UNSET_LOCK_HOLDER()
# define I_HOLD_LOCK() FALSE
# endif
# else
# define LOCK()
# define UNLOCK()
# endif
# ifndef SET_LOCK_HOLDER
# define SET_LOCK_HOLDER()
# define UNSET_LOCK_HOLDER()
# define I_HOLD_LOCK() FALSE
# endif
# ifndef ENTER_GC
# define ENTER_GC()
# define EXIT_GC()
# endif
# ifndef DCL_LOCK_STATE
# define DCL_LOCK_STATE
# endif
# ifndef FASTLOCK
# define FASTLOCK() LOCK()
# define FASTLOCK_SUCCEEDED() TRUE
# define FASTUNLOCK() UNLOCK()
# endif
#endif