#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)
inline static int GC_test_and_set(volatile unsigned int *addr) {
long oldval, n = 1;
__asm__ __volatile__("xchg4 %0=%1,%2"
: "=r"(oldval), "=m"(*addr)
: "r"(n), "1"(*addr) : "memory");
return oldval;
}
# define GC_TEST_AND_SET_DEFINED
inline static void GC_clear(volatile unsigned int *addr) {
__asm__ __volatile__("st4.rel %0=r0" : "=m" (*addr) : : "memory");
}
# 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)
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" "2:\t\n" : "=&r"(oldval), "=p"(addr)
: "r"(temp), "1"(addr)
: "memory");
return (int)oldval;
}
# define GC_TEST_AND_SET_DEFINED
inline static void GC_clear(volatile unsigned int *addr) {
__asm__ __volatile__("eieio" ::: "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"
" beq %0,3f\n"
" mb\n"
"2:\n"
".section .text2,\"ax\"\n"
"3: br 1b\n"
".previous"
:"=&r" (temp), "=m" (*addr), "=&r" (oldvalue)
:"Ir" (1), "m" (*addr)
:"memory");
return oldvalue;
}
# define GC_TEST_AND_SET_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)
: "r"(1), "r"(addr)
: "memory");
return oldval;
}
# define GC_TEST_AND_SET_DEFINED
# endif
# endif
# if (defined(ALPHA) && !defined(__GNUC__))
# define GC_test_and_set(addr) __cxx_test_and_set_atomic(addr, 1)
# define GC_TEST_AND_SET_DEFINED
# endif
# if defined(MSWIN32)
# define GC_test_and_set(addr) InterlockedExchange((LPLONG)addr,1)
# define GC_TEST_AND_SET_DEFINED
# endif
# ifdef MIPS
# if __mips < 3 || !(defined (_ABIN32) || defined(_ABI64)) \
|| !defined(_COMPILER_VERSION) || _COMPILER_VERSION < 700
# define GC_test_and_set(addr, v) test_and_set(addr,v)
# else
# define GC_test_and_set(addr, v) __test_and_set(addr,v)
# define GC_clear(addr) __lock_release(addr);
# define GC_CLEAR_DEFINED
# endif
# define GC_TEST_AND_SET_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_IRIX_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), "0"(*(addr)), "a"(old) : "memory");
return (GC_bool) result;
}
# endif
inline static void GC_memory_write_barrier()
{
__asm__ __volatile__("" : : : "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)
{
unsigned long oldval;
__asm__ __volatile__("mov ar.ccv=%4 ;; cmpxchg8.rel %0=%1,%2,ar.ccv"
: "=r"(oldval), "=m"(*addr)
: "r"(new_val), "1"(*addr), "r"(old) : "memory");
return (oldval == old);
}
# endif
# if 0
inline static void GC_memory_write_barrier()
{
__asm__ __volatile__("mf" : : : "memory");
}
# 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
# define LOCK() \
{ if (0 != pthread_mutex_trylock(&GC_allocate_ml)) GC_lock(); }
# 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_IRIX_THREADS)
# include <pthread.h>
# include <mutex.h>
extern unsigned long GC_allocate_lock;
extern pthread_t GC_lock_holder;
extern void GC_lock(void);
# define SET_LOCK_HOLDER() GC_lock_holder = pthread_self()
# define NO_THREAD (pthread_t)(-1)
# define UNSET_LOCK_HOLDER() GC_lock_holder = NO_THREAD
# define I_HOLD_LOCK() (pthread_equal(GC_lock_holder, pthread_self()))
# define LOCK() { if (GC_test_and_set(&GC_allocate_lock, 1)) GC_lock(); }
# define UNLOCK() GC_clear(&GC_allocate_lock);
extern VOLATILE GC_bool GC_collecting;
# define ENTER_GC() \
{ \
GC_collecting = 1; \
}
# define EXIT_GC() GC_collecting = 0;
# endif
# ifdef GC_WIN32_THREADS
# include <windows.h>
GC_API CRITICAL_SECTION GC_allocate_ml;
# define LOCK() EnterCriticalSection(&GC_allocate_ml);
# define UNLOCK() LeaveCriticalSection(&GC_allocate_ml);
# 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