[Bug 444076] implementing compare-and-swap for 64-bit Linux. r=brendan

This commit is contained in:
Igor Bukanov 2008-07-16 17:58:37 +02:00
parent d8f4877b29
commit 742acfc30a
2 changed files with 78 additions and 62 deletions

View File

@ -61,30 +61,8 @@
#ifndef NSPR_LOCK
#include <memory.h>
/* Implement NativeCompareAndSwap. */
static PRLock **global_locks;
static uint32 global_lock_count = 1;
static uint32 global_locks_log2 = 0;
static uint32 global_locks_mask = 0;
#define GLOBAL_LOCK_INDEX(id) (((uint32)(id) >> 2) & global_locks_mask)
static void
js_LockGlobal(void *id)
{
uint32 i = GLOBAL_LOCK_INDEX(id);
PR_Lock(global_locks[i]);
}
static void
js_UnlockGlobal(void *id)
{
uint32 i = GLOBAL_LOCK_INDEX(id);
PR_Unlock(global_locks[i]);
}
/* Exclude Alpha NT. */
#if defined(_WIN32) && defined(_M_IX86)
#pragma warning( disable : 4035 )
JS_BEGIN_EXTERN_C
@ -94,7 +72,7 @@ JS_END_EXTERN_C
#pragma intrinsic(_InterlockedCompareExchange)
static JS_INLINE int
js_CompareAndSwapHelper(jsword *w, jsword ov, jsword nv)
NativeCompareAndSwapHelper(jsword *w, jsword ov, jsword nv)
{
_InterlockedCompareExchange(w, nv, ov);
__asm {
@ -103,9 +81,9 @@ js_CompareAndSwapHelper(jsword *w, jsword ov, jsword nv)
}
static JS_INLINE int
js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
NativeCompareAndSwap(jsword *w, jsword ov, jsword nv)
{
return (js_CompareAndSwapHelper(w, ov, nv) & 1);
return (NativeCompareAndSwapHelper(w, ov, nv) & 1);
}
#elif defined(XP_MACOSX) || defined(DARWIN)
@ -113,7 +91,7 @@ js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
#include <libkern/OSAtomic.h>
static JS_INLINE int
js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
NativeCompareAndSwap(jsword *w, jsword ov, jsword nv)
{
/* Details on these functions available in the manpage for atomic */
#if JS_BYTES_PER_WORD == 8 && JS_BYTES_PER_LONG != 8
@ -127,7 +105,7 @@ js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
/* Note: This fails on 386 cpus, cmpxchgl is a >= 486 instruction */
static JS_INLINE int
js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
NativeCompareAndSwap(jsword *w, jsword ov, jsword nv)
{
unsigned int res;
@ -145,7 +123,7 @@ js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
#elif defined(SOLARIS) && defined(sparc) && defined(ULTRA_SPARC)
static JS_INLINE int
js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
NativeCompareAndSwap(jsword *w, jsword ov, jsword nv)
{
#if defined(__GNUC__)
unsigned int res;
@ -173,7 +151,7 @@ mov 0,%0\n\
#include <sys/atomic_op.h>
static JS_INLINE int
js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
NativeCompareAndSwap(jsword *w, jsword ov, jsword nv)
{
return !_check_lock((atomic_p)w, ov, nv);
}
@ -190,18 +168,48 @@ typedef int (__kernel_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
JS_STATIC_ASSERT(sizeof(jsword) == sizeof(int));
static JS_INLINE int
js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
NativeCompareAndSwap(jsword *w, jsword ov, jsword nv)
{
volatile int *vp = (volatile int*)w;
return !__kernel_cmpxchg(ov, nv, vp);
}
#elif defined(__GNUC__) && \
(__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1))
static JS_INLINE int
NativeCompareAndSwap(jsword *w, jsword ov, jsword nv)
{
return __sync_bool_compare_and_swap(w, ov, nv);
}
#else
#error "Define NSPR_LOCK if your platform lacks a compare-and-swap instruction."
#error "JS_HAS_NATIVE_COMPARE_AND_SWAP should be 0 if your platform lacks a compare-and-swap instruction."
#endif /* arch-tests */
static PRLock **global_locks;
static uint32 global_lock_count = 1;
static uint32 global_locks_log2 = 0;
static uint32 global_locks_mask = 0;
#define GLOBAL_LOCK_INDEX(id) (((uint32)(jsuword)(id)>>2) & global_locks_mask)
static void
js_LockGlobal(void *id)
{
uint32 i = GLOBAL_LOCK_INDEX(id);
PR_Lock(global_locks[i]);
}
static void
js_UnlockGlobal(void *id)
{
uint32 i = GLOBAL_LOCK_INDEX(id);
PR_Unlock(global_locks[i]);
}
#endif /* !NSPR_LOCK */
void
@ -585,7 +593,7 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot)
tl = &title->lock;
me = CX_THINLOCK_ID(cx);
JS_ASSERT(CURRENT_THREAD_IS_ME(me));
if (js_CompareAndSwap(&tl->owner, 0, me)) {
if (NativeCompareAndSwap(&tl->owner, 0, me)) {
/*
* Got the lock with one compare-and-swap. Even so, someone else may
* have mutated obj so it now has its own scope and lock, which would
@ -594,7 +602,7 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot)
*/
if (scope == OBJ_SCOPE(obj)) {
v = STOBJ_GET_SLOT(obj, slot);
if (!js_CompareAndSwap(&tl->owner, me, 0)) {
if (!NativeCompareAndSwap(&tl->owner, me, 0)) {
/* Assert that scope locks never revert to flyweight. */
JS_ASSERT(title->ownercx != cx);
LOGIT(scope, '1');
@ -603,7 +611,7 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot)
}
return v;
}
if (!js_CompareAndSwap(&tl->owner, me, 0))
if (!NativeCompareAndSwap(&tl->owner, me, 0))
js_Dequeue(tl);
}
else if (Thin_RemoveWait(ReadWord(tl->owner)) == me) {
@ -681,10 +689,10 @@ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
tl = &title->lock;
me = CX_THINLOCK_ID(cx);
JS_ASSERT(CURRENT_THREAD_IS_ME(me));
if (js_CompareAndSwap(&tl->owner, 0, me)) {
if (NativeCompareAndSwap(&tl->owner, 0, me)) {
if (scope == OBJ_SCOPE(obj)) {
LOCKED_OBJ_WRITE_BARRIER(cx, obj, slot, v);
if (!js_CompareAndSwap(&tl->owner, me, 0)) {
if (!NativeCompareAndSwap(&tl->owner, me, 0)) {
/* Assert that scope locks never revert to flyweight. */
JS_ASSERT(title->ownercx != cx);
LOGIT(scope, '1');
@ -693,7 +701,7 @@ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
}
return;
}
if (!js_CompareAndSwap(&tl->owner, me, 0))
if (!NativeCompareAndSwap(&tl->owner, me, 0))
js_Dequeue(tl);
}
else if (Thin_RemoveWait(ReadWord(tl->owner)) == me) {
@ -970,13 +978,13 @@ js_Enqueue(JSThinLock *tl, jsword me)
for (;;) {
o = ReadWord(tl->owner);
n = Thin_SetWait(o);
if (o != 0 && js_CompareAndSwap(&tl->owner, o, n)) {
if (o != 0 && NativeCompareAndSwap(&tl->owner, o, n)) {
if (js_SuspendThread(tl))
me = Thin_RemoveWait(me);
else
me = Thin_SetWait(me);
}
else if (js_CompareAndSwap(&tl->owner, 0, me)) {
else if (NativeCompareAndSwap(&tl->owner, 0, me)) {
js_UnlockGlobal(tl);
return;
}
@ -992,7 +1000,7 @@ js_Dequeue(JSThinLock *tl)
o = ReadWord(tl->owner);
JS_ASSERT(Thin_GetWait(o) != 0);
JS_ASSERT(tl->fat != NULL);
if (!js_CompareAndSwap(&tl->owner, o, 0)) /* release it */
if (!NativeCompareAndSwap(&tl->owner, o, 0)) /* release it */
JS_ASSERT(0);
js_ResumeThread(tl);
}
@ -1001,7 +1009,7 @@ JS_INLINE void
js_Lock(JSThinLock *tl, jsword me)
{
JS_ASSERT(CURRENT_THREAD_IS_ME(me));
if (js_CompareAndSwap(&tl->owner, 0, me))
if (NativeCompareAndSwap(&tl->owner, 0, me))
return;
if (Thin_RemoveWait(ReadWord(tl->owner)) != me)
js_Enqueue(tl, me);
@ -1017,10 +1025,10 @@ js_Unlock(JSThinLock *tl, jsword me)
JS_ASSERT(CURRENT_THREAD_IS_ME(me));
/*
* Since we can race with the CompareAndSwap in js_Enqueue, we need
* Since we can race with the NativeCompareAndSwap in js_Enqueue, we need
* to use a C_A_S here as well -- Arjan van de Ven 30/1/08
*/
if (js_CompareAndSwap(&tl->owner, me, 0))
if (NativeCompareAndSwap(&tl->owner, me, 0))
return;
JS_ASSERT(Thin_GetWait(tl->owner));

View File

@ -39,19 +39,33 @@
#ifndef jslock_h__
#define jslock_h__
#ifdef JS_THREADSAFE
#include "jstypes.h"
#include "pratom.h"
#include "prlock.h"
#include "prcvar.h"
#include "prthread.h"
#include "jsprvtd.h" /* for JSScope, etc. */
#include "jspubtd.h" /* for JSRuntime, etc. */
#ifdef JS_THREADSAFE
# include "pratom.h"
# include "prlock.h"
# include "prcvar.h"
# include "prthread.h"
#endif
JS_BEGIN_EXTERN_C
#ifdef JS_THREADSAFE
#if (defined(_WIN32) && defined(_M_IX86)) || \
(defined(__GNUC__) && defined(__i386__)) || \
(defined(SOLARIS) && defined(sparc) && defined(ULTRA_SPARC)) || \
defined(AIX) || \
defined(USE_ARM_KUSER) || \
(defined(__GNUC__) && \
(__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1)))
# define JS_HAS_NATIVE_COMPARE_AND_SWAP 1
#else
# define JS_HAS_NATIVE_COMPARE_AND_SWAP 0
#endif
#define Thin_GetWait(W) ((jsword)(W) & 0x1)
#define Thin_SetWait(W) ((jsword)(W) | 0x1)
#define Thin_RemoveWait(W) ((jsword)(W) & ~0x1)
@ -94,7 +108,7 @@ struct JSTitle {
const char *file[4]; /* file where lock was (re-)taken */
unsigned int line[4]; /* line where lock was (re-)taken */
#endif
};
};
/*
* Title structures must be immediately preceded by JSObjectMap structures for
@ -222,11 +236,7 @@ extern void js_SetScopeInfo(JSScope *scope, const char *file, int line);
JS_LOCK_RUNTIME_VOID(_rt, e); \
JS_END_MACRO
#if defined(JS_USE_ONLY_NSPR_LOCKS) || \
!( (defined(_WIN32) && defined(_M_IX86)) || \
(defined(__GNUC__) && defined(__i386__)) || \
(defined(SOLARIS) && defined(sparc) && defined(ULTRA_SPARC)) || \
defined(AIX) || defined(USE_ARM_KUSER))
#if defined(JS_USE_ONLY_NSPR_LOCKS) || !JS_HAS_NATIVE_COMPARE_AND_SWAP
#define NSPR_LOCK 1
@ -235,19 +245,17 @@ extern void js_SetScopeInfo(JSScope *scope, const char *file, int line);
#define JS_LOCK0(P,M) (JS_ACQUIRE_LOCK(((JSLock*)(P)->fat)), (P)->owner = (M))
#define JS_UNLOCK0(P,M) ((P)->owner = 0, JS_RELEASE_LOCK(((JSLock*)(P)->fat)))
#else /* arch-tests */
#else
#undef NSPR_LOCK
extern void js_Lock(JSThinLock *tl, jsword me);
extern void js_Unlock(JSThinLock *tl, jsword me);
#endif /* arch-tests */
#endif
#else /* !JS_THREADSAFE */
JS_BEGIN_EXTERN_C
#define JS_ATOMIC_INCREMENT(p) (++*(p))
#define JS_ATOMIC_DECREMENT(p) (--*(p))
#define JS_ATOMIC_ADD(p,v) (*(p) += (v))
@ -300,7 +308,7 @@ JS_BEGIN_EXTERN_C
#define JS_LOCK(P,CX) JS_LOCK0(P, CX_THINLOCK_ID(CX))
#define JS_UNLOCK(P,CX) JS_UNLOCK0(P, CX_THINLOCK_ID(CX))
#ifndef SET_OBJ_INFO
#define SET_OBJ_INFO(obj,f,l) ((void)0)
#endif