Patch from Feng Qian <feng.qian.moz@gmail.com> with assist from Igor, based on ancient patch from me, to factor per-thread state from JSContext into JSThread to support per-thread lock-free GC allocation (312238, r=me).

This commit is contained in:
brendan%mozilla.org 2006-04-18 01:41:54 +00:00
parent 2d7096065f
commit 10cbbda3cf
10 changed files with 233 additions and 78 deletions

View File

@ -63,11 +63,11 @@ INCLUDES += -I$(OBJDIR)
ifdef JS_THREADSAFE
DEFINES += -DJS_THREADSAFE
INCLUDES += -I../../dist/$(OBJDIR)/include
INCLUDES += -I$(DIST)/include/nspr
ifdef USE_MSVC
OTHER_LIBS += ../../dist/$(OBJDIR)/lib/libnspr${NSPR_LIBSUFFIX}.lib
OTHER_LIBS += $(DIST)/lib/libnspr$(NSPR_LIBSUFFIX).lib
else
OTHER_LIBS += -L../../dist/$(OBJDIR)/lib -lnspr${NSPR_LIBSUFFIX}
OTHER_LIBS += -L$(DIST)/lib -lnspr$(NSPR_LIBSUFFIX)
endif
endif
@ -92,7 +92,7 @@ endif
# Prevent floating point errors caused by VC++ optimizations
ifeq ($(OS_ARCH),WINNT)
CFLAGS += -Op
#CFLAGS += -Op
endif # WINNT
#

View File

@ -40,7 +40,7 @@
ifdef JS_DIST
DIST = $(JS_DIST)
else
DIST = $(DEPTH)/../../dist/$(OBJDIR)
DIST = $(DEPTH)/../../dist
endif
# Set os+release dependent make variables
@ -112,13 +112,13 @@ ifeq ($(OS_ARCH), WINNT)
INSTALL = nsinstall
CP = cp
else
INSTALL = $(DEPTH)/../../dist/$(OBJDIR)/bin/nsinstall
INSTALL = $(DIST)/bin/nsinstall
CP = cp
endif
ifdef BUILD_OPT
OPTIMIZER = -O
DEFINES += -UDEBUG -DNDEBUG -UDEBUG_$(shell whoami)
DEFINES += -UDEBUG -DNDEBUG -UDEBUG_$(USERNAME)
OBJDIR_TAG = _OPT
else
ifdef USE_MSVC
@ -126,7 +126,7 @@ OPTIMIZER = -Zi
else
OPTIMIZER = -g
endif
DEFINES += -DDEBUG -DDEBUG_$(shell whoami)
DEFINES += -DDEBUG -DDEBUG_$(USERNAME)
OBJDIR_TAG = _DBG
endif

View File

@ -2533,6 +2533,10 @@ main(int argc, char **argv, char **envp)
return 1;
JS_SetErrorReporter(cx, my_ErrorReporter);
#ifdef JS_THREADSAFE
JS_BeginRequest(cx);
#endif
glob = JS_NewObject(cx, &global_class, NULL, NULL);
if (!glob)
return 1;
@ -2628,6 +2632,10 @@ main(int argc, char **argv, char **envp)
JSD_DebuggerOff(_jsdc);
#endif /* JSDEBUGGER */
#ifdef JS_THREADSAFE
JS_EndRequest(cx);
#endif
JS_DestroyContext(cx);
JS_DestroyRuntime(rt);
JS_ShutDown();

View File

@ -676,6 +676,10 @@ JS_NewRuntime(uint32 maxbytes)
if (!js_InitGC(rt, maxbytes))
goto bad;
#ifdef JS_THREADSAFE
if (PR_FAILURE == PR_NewThreadPrivateIndex(&rt->threadTPIndex,
js_ThreadDestructorCB)) {
goto bad;
}
rt->gcLock = JS_NEW_LOCK();
if (!rt->gcLock)
goto bad;
@ -786,13 +790,13 @@ JS_BeginRequest(JSContext *cx)
{
JSRuntime *rt;
JS_ASSERT(cx->thread == js_CurrentThreadId());
JS_ASSERT(cx->thread->id == js_CurrentThreadId());
if (!cx->requestDepth) {
/* Wait until the GC is finished. */
rt = cx->runtime;
JS_LOCK_GC(rt);
/* NB: we use cx->thread here, not js_CurrentThreadId(). */
/* NB: we use cx->thread here, not js_GetCurrentThread(). */
if (rt->gcThread != cx->thread) {
while (rt->gcLevel > 0)
JS_AWAIT_GC_DONE(rt);
@ -1822,7 +1826,7 @@ JS_MarkGCThing(JSContext *cx, void *thing, const char *name, void *arg)
{
JS_ASSERT(cx->runtime->gcLevel > 0);
#ifdef JS_THREADSAFE
JS_ASSERT(cx->runtime->gcThread == js_CurrentThreadId());
JS_ASSERT(cx->runtime->gcThread->id == js_CurrentThreadId());
#endif
GC_MARK(cx, thing, name);
@ -4786,25 +4790,34 @@ JS_ThrowReportedError(JSContext *cx, const char *message,
}
#ifdef JS_THREADSAFE
/*
* Get the owning thread id of a context. Returns 0 if the context is not
* owned by any thread.
*/
JS_PUBLIC_API(jsword)
JS_GetContextThread(JSContext *cx)
{
return cx->thread;
return JS_THREAD_ID(cx);
}
/*
* Set the current thread as the owning thread of a context. Returns the
* old owning thread id, or -1 if the operation failed.
*/
JS_PUBLIC_API(jsword)
JS_SetContextThread(JSContext *cx)
{
jsword old = cx->thread;
cx->thread = js_CurrentThreadId();
jsword old = JS_THREAD_ID(cx);
if (!js_SetContextThread(cx))
return -1;
return old;
}
JS_PUBLIC_API(jsword)
JS_ClearContextThread(JSContext *cx)
{
jsword old = cx->thread;
cx->thread = 0;
jsword old = JS_THREAD_ID(cx);
js_ClearContextThread(cx);
return old;
}
#endif

View File

@ -64,6 +64,88 @@
#include "jsscript.h"
#include "jsstr.h"
#ifdef JS_THREADSAFE
/*
* Callback function to delete a JSThread info when the thread that owns it
* is destroyed.
*/
void JS_DLL_CALLBACK
js_ThreadDestructorCB(void *ptr)
{
JSThread *thread = (JSThread *)ptr;
if (!thread)
return;
while (!JS_CLIST_IS_EMPTY(&thread->contextList))
JS_REMOVE_AND_INIT_LINK(thread->contextList.next);
free(thread);
}
/*
* Get current thread-local JSThread info, creating one if it doesn't exist.
* Each thread has a unique JSThread pointer.
*
* Since we are dealing with thread-local data, no lock is needed.
*
* Return a pointer to the thread local info, NULL if the system runs out
* of memory, or it failed to set thread private data (neither case is very
* likely; both are probably due to out-of-memory). It is up to the caller
* to report an error, if possible.
*/
JSThread *
js_GetCurrentThread(JSRuntime *rt)
{
JSThread *thread;
thread = (JSThread *)PR_GetThreadPrivate(rt->threadTPIndex);
if (!thread) {
/* New memory is set to 0 so that elements in gcFreeLists are NULL. */
thread = (JSThread *) calloc(1, sizeof(JSThread));
if (!thread)
return NULL;
if (PR_FAILURE == PR_SetThreadPrivate(rt->threadTPIndex, thread)) {
free(thread);
return NULL;
}
JS_INIT_CLIST(&thread->contextList);
thread->id = js_CurrentThreadId();
}
return thread;
}
/*
* Sets current thread as owning thread of a context by assigning the
* thread-private info to the context. If the current thread doesn't have
* private JSThread info, create one.
*/
JSBool
js_SetContextThread(JSContext *cx)
{
JSThread *thread = js_GetCurrentThread(cx->runtime);
if (!thread) {
JS_ReportOutOfMemory(cx);
return JS_FALSE;
}
cx->thread = thread;
JS_REMOVE_LINK(&cx->threadLinks);
JS_APPEND_LINK(&cx->threadLinks, &thread->contextList);
return JS_TRUE;
}
/* Remove the owning thread info of a context. */
void
js_ClearContextThread(JSContext *cx)
{
cx->thread = NULL;
JS_REMOVE_LINK(&cx->threadLinks);
}
#endif /* JS_THREADSAFE */
void
js_OnVersionChange(JSContext *cx)
{
@ -101,7 +183,8 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
cx->stackLimit = (jsuword)-1;
#endif
#ifdef JS_THREADSAFE
js_InitContextForLocking(cx);
JS_INIT_CLIST(&cx->threadLinks);
js_SetContextThread(cx);
#endif
JS_LOCK_GC(rt);
@ -140,9 +223,6 @@ js_NewContext(JSRuntime *rt, size_t stackChunkSize)
return NULL;
}
#endif
#if JS_HAS_EXCEPTIONS
cx->throwing = JS_FALSE;
#endif
/*
* If cx is the first context on this runtime, initialize well-known atoms,
@ -320,6 +400,10 @@ js_DestroyContext(JSContext *cx, JSGCMode gcmode)
JS_free(cx, lrs);
}
#ifdef JS_THREADSAFE
js_ClearContextThread(cx);
#endif
/* Finally, free cx itself. */
free(cx);
}
@ -700,7 +784,7 @@ ReportError(JSContext *cx, const char *message, JSErrorReport *reportp)
* exception is thrown, then the JSREPORT_EXCEPTION flag will be set
* on the error report, and exception-aware hosts should ignore it.
*/
JS_ASSERT(reportp);
JS_ASSERT(reportp);
if (reportp->errorNumber == JSMSG_UNCAUGHT_EXCEPTION)
reportp->flags |= JSREPORT_EXCEPTION;
@ -741,7 +825,7 @@ js_ReportOutOfMemory(JSContext *cx)
JSErrorReporter onError = cx->errorReporter;
/* Get the message for this error, but we won't expand any arguments. */
const JSErrorFormatString *efs =
const JSErrorFormatString *efs =
js_GetLocalizedErrorMessage(cx, NULL, NULL, JSMSG_OUT_OF_MEMORY);
const char *msg = efs ? efs->format : "Out of memory";

View File

@ -57,6 +57,39 @@
JS_BEGIN_EXTERN_C
#ifdef JS_THREADSAFE
/*
* Structure uniquely representing a thread. It holds thread-private data
* that can be accessed without a global lock.
*/
struct JSThread {
/* Linked list of all contexts active on this thread. */
JSCList contextList;
/* Opaque thread-id, from NSPR's PR_GetCurrentThread(). */
jsword id;
#if 0
/* Thread-local gc free lists array. */
JSGCThing *gcFreeLists[GC_NUM_FREELISTS];
#endif
};
extern void JS_DLL_CALLBACK
js_ThreadDestructorCB(void *ptr);
extern JSBool
js_SetContextThread(JSContext *cx);
extern void
js_ClearContextThread(JSContext *cx);
extern JSThread *
js_GetCurrentThread(JSRuntime *rt);
#endif /* JS_THREADSAFE */
typedef enum JSGCMode { JS_NO_GC, JS_MAYBE_GC, JS_FORCE_GC } JSGCMode;
typedef enum JSRuntimeState {
@ -187,7 +220,7 @@ struct JSRuntime {
PRCondVar *gcDone;
PRCondVar *requestDone;
uint32 requestCount;
jsword gcThread;
JSThread *gcThread;
/* Lock and owning thread pointer for JS_LOCK_RUNTIME. */
PRLock *rtLock;
@ -225,6 +258,13 @@ struct JSRuntime {
* value.
*/
#define NO_SCOPE_SHARING_TODO ((JSScope *) 0xfeedbeef)
/*
* The index for JSThread info, returned by PR_NewThreadPrivateIndex.
* The value is visible and shared by all threads, but the data is
* private to each thread.
*/
PRUintn threadTPIndex;
#endif /* JS_THREADSAFE */
/*
@ -431,6 +471,7 @@ struct JSTempValueRooter {
JS_END_MACRO
struct JSContext {
/* JSRuntime contextList linkage. */
JSCList links;
/* Interpreter activation count. */
@ -491,11 +532,15 @@ struct JSContext {
/* GC and thread-safe state. */
JSStackFrame *dormantFrameChain; /* dormant stack frame to scan */
#ifdef JS_THREADSAFE
jsword thread;
JSThread *thread;
jsrefcount requestDepth;
JSScope *scopeToShare; /* weak reference, see jslock.c */
JSScope *lockedSealedScope; /* weak ref, for low-cost sealed
scope locking */
JSCList threadLinks; /* JSThread contextList linkage */
#define CX_FROM_THREAD_LINKS(tl) \
((JSContext *)((char *)(tl) - offsetof(JSContext, threadLinks)))
#endif
#if JS_HAS_LVALUE_RETURN
@ -564,6 +609,8 @@ struct JSContext {
#endif
};
#define JS_THREAD_ID(cx) ((cx)->thread ? (cx)->thread->id : 0)
/*
* Slightly more readable macros for testing per-context option settings (also
* to hide bitset implementation detail).
@ -584,7 +631,7 @@ struct JSContext {
*
* Note that JS_SetVersion API calls never pass JSVERSION_HAS_XML or'd into
* that API's version parameter.
*
*
* Note also that script->version must contain this XML option flag in order
* for XDR'ed scripts to serialize and deserialize with that option preserved
* for detection at run-time. We can't copy other compile-time options into

View File

@ -270,7 +270,7 @@ DestroyGCArena(JSGCArenaList *arenaList, JSGCArena **ap)
JS_ASSERT(a);
METER(--arenaList->stats.narenas);
if (a == arenaList->last)
arenaList->lastLimit = a->prev ? GC_THINGS_SIZE : 0;
arenaList->lastLimit = (uint16)(a->prev ? GC_THINGS_SIZE : 0);
*ap = a->prev;
#ifdef DEBUG
@ -485,6 +485,9 @@ js_DumpGCStats(JSRuntime *rt, FILE *fp)
fprintf(fp, " public bytes allocated: %lu\n", UL(rt->gcBytes));
fprintf(fp, " private bytes allocated: %lu\n", UL(rt->gcPrivateBytes));
fprintf(fp, " alloc attempts: %lu\n", ULSTAT(alloc));
#ifdef JS_THREADSAFE
fprintf(fp, " alloc without locks: %1u\n", ULSTAT(localalloc));
#endif
fprintf(fp, " total GC things: %lu\n", UL(totalThings));
fprintf(fp, " max total GC things: %lu\n", UL(totalMaxThings));
fprintf(fp, " GC things size: %lu\n", UL(totalBytes));
@ -609,7 +612,7 @@ js_AddRootRT(JSRuntime *rt, void *rp, const char *name)
JS_LOCK_GC(rt);
#ifdef JS_THREADSAFE
JS_ASSERT(!rt->gcRunning || rt->gcLevel > 0);
if (rt->gcRunning && rt->gcThread != js_CurrentThreadId()) {
if (rt->gcRunning && rt->gcThread->id != js_CurrentThreadId()) {
do {
JS_AWAIT_GC_DONE(rt);
} while (rt->gcLevel > 0);
@ -638,7 +641,7 @@ js_RemoveRoot(JSRuntime *rt, void *rp)
JS_LOCK_GC(rt);
#ifdef JS_THREADSAFE
JS_ASSERT(!rt->gcRunning || rt->gcLevel > 0);
if (rt->gcRunning && rt->gcThread != js_CurrentThreadId()) {
if (rt->gcRunning && rt->gcThread->id != js_CurrentThreadId()) {
do {
JS_AWAIT_GC_DONE(rt);
} while (rt->gcLevel > 0);
@ -1425,8 +1428,8 @@ MarkGCThingChildren(JSContext *cx, void *thing, uint8 *flagp,
}
/*
* Not using PAGE_THING_GAP inside this macro to optimize
* thingsPerUnscannedChunk calculation when thingSize == 2^power.
* Avoid using PAGE_THING_GAP inside this macro to optimize the
* thingsPerUnscannedChunk calculation when thingSize is a power of two.
*/
#define GET_GAP_AND_CHUNK_SPAN(thingSize, thingsPerUnscannedChunk, pageGap) \
JS_BEGIN_MACRO \
@ -1807,7 +1810,6 @@ js_GC(JSContext *cx, uintN gcflags)
uint32 *bytesptr;
JSBool all_clear;
#ifdef JS_THREADSAFE
jsword currentThread;
uint32 requestDebit;
#endif
@ -1851,8 +1853,7 @@ js_GC(JSContext *cx, uintN gcflags)
#ifdef JS_THREADSAFE
/* Bump gcLevel and return rather than nest on this thread. */
currentThread = js_CurrentThreadId();
if (rt->gcThread == currentThread) {
if (rt->gcThread && rt->gcThread->id == js_CurrentThreadId()) {
JS_ASSERT(rt->gcLevel > 0);
rt->gcLevel++;
METER(if (rt->gcLevel > rt->gcStats.maxlevel)
@ -1865,25 +1866,29 @@ js_GC(JSContext *cx, uintN gcflags)
/*
* If we're in one or more requests (possibly on more than one context)
* running on the current thread, indicate, temporarily, that all these
* requests are inactive. NB: if cx->thread is 0, then cx is not using
* requests are inactive. If cx->thread is NULL, then cx is not using
* the request model, and does not contribute to rt->requestCount.
*/
requestDebit = 0;
if (cx->thread) {
JSCList *head, *link;
/*
* Check all contexts for any with the same thread-id. XXX should we
* keep a sub-list of contexts having the same id?
* Check all contexts on cx->thread->contextList for active requests,
* counting each such context against requestDebit.
*/
iter = NULL;
while ((acx = js_ContextIterator(rt, JS_FALSE, &iter)) != NULL) {
if (acx->thread == cx->thread && acx->requestDepth)
head = &cx->thread->contextList;
for (link = head->next; link != head; link = link->next) {
acx = CX_FROM_THREAD_LINKS(link);
JS_ASSERT(acx->thread == cx->thread);
if (acx->requestDepth)
requestDebit++;
}
} else {
/*
* We assert, but check anyway, in case someone is misusing the API.
* Avoiding the loop over all of rt's contexts is a win in the event
* that the GC runs only on request-less contexts with 0 thread-ids,
* that the GC runs only on request-less contexts with null threads,
* in a special thread such as might be used by the UI/DOM/Layout
* "mozilla" or "main" thread in Mozilla-the-browser.
*/
@ -1917,7 +1922,8 @@ js_GC(JSContext *cx, uintN gcflags)
/* No other thread is in GC, so indicate that we're now in GC. */
rt->gcLevel = 1;
rt->gcThread = currentThread;
rt->gcThread = js_GetCurrentThread(rt);
JS_ASSERT(rt->gcThread);
/* Wait for all other requests to finish. */
while (rt->requestCount > 0)
@ -2259,7 +2265,7 @@ restart:
/* If we were invoked during a request, pay back the temporary debit. */
if (requestDebit)
rt->requestCount += requestDebit;
rt->gcThread = 0;
rt->gcThread = NULL;
JS_NOTIFY_GC_DONE(rt);
if (!(gcflags & GC_ALREADY_LOCKED))
JS_UNLOCK_GC(rt);

View File

@ -45,7 +45,6 @@
#include "jsstddef.h"
#include <stdlib.h>
#include "jspubtd.h"
#include "prthread.h"
#include "jsutil.h" /* Added by JSIFY */
#include "jstypes.h"
#include "jsbit.h"
@ -201,12 +200,6 @@ js_CompareAndSwap(jsword *w, jsword ov, jsword nv)
#endif /* !NSPR_LOCK */
jsword
js_CurrentThreadId()
{
return CurrentThreadId();
}
void
js_InitLock(JSThinLock *tl)
{
@ -354,7 +347,7 @@ ShareScope(JSRuntime *rt, JSScope *scope)
* scope->ownercx's transition to null against tests of that member
* in ClaimScope.
*/
scope->lock.owner = scope->ownercx->thread;
scope->lock.owner = CX_THINLOCK_ID(scope->ownercx);
#ifdef NSPR_LOCK
JS_ACQUIRE_LOCK((JSLock*)scope->lock.fat);
#endif
@ -613,8 +606,8 @@ js_GetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot)
#ifndef NSPR_LOCK
tl = &scope->lock;
me = cx->thread;
JS_ASSERT(me == CurrentThreadId());
me = CX_THINLOCK_ID(cx);
JS_ASSERT(CURRENT_THREAD_IS_ME(me));
if (js_CompareAndSwap(&tl->owner, 0, me)) {
/*
* Got the lock with one compare-and-swap. Even so, someone else may
@ -704,8 +697,8 @@ js_SetSlotThreadSafe(JSContext *cx, JSObject *obj, uint32 slot, jsval v)
#ifndef NSPR_LOCK
tl = &scope->lock;
me = cx->thread;
JS_ASSERT(me == CurrentThreadId());
me = CX_THINLOCK_ID(cx);
JS_ASSERT(CURRENT_THREAD_IS_ME(me));
if (js_CompareAndSwap(&tl->owner, 0, me)) {
if (scope == OBJ_SCOPE(obj)) {
obj->slots[slot] = v;
@ -909,13 +902,6 @@ js_CleanupLocks()
#endif /* !NSPR_LOCK */
}
void
js_InitContextForLocking(JSContext *cx)
{
cx->thread = CurrentThreadId();
JS_ASSERT(Thin_GetWait(cx->thread) == 0);
}
#ifndef NSPR_LOCK
/*
@ -1036,7 +1022,7 @@ js_Dequeue(JSThinLock *tl)
JS_INLINE void
js_Lock(JSThinLock *tl, jsword me)
{
JS_ASSERT(me == CurrentThreadId());
JS_ASSERT(CURRENT_THREAD_IS_ME(me));
if (js_CompareAndSwap(&tl->owner, 0, me))
return;
if (Thin_RemoveWait(ReadWord(tl->owner)) != me)
@ -1050,14 +1036,22 @@ js_Lock(JSThinLock *tl, jsword me)
JS_INLINE void
js_Unlock(JSThinLock *tl, jsword me)
{
JS_ASSERT(me == CurrentThreadId());
if (js_CompareAndSwap(&tl->owner, me, 0))
JS_ASSERT(CURRENT_THREAD_IS_ME(me));
/*
* Only me can hold the lock, no need to use compare and swap atomic
* operation for this common case.
*/
if (tl->owner == me) {
tl->owner = 0;
return;
}
JS_ASSERT(Thin_GetWait(tl->owner));
if (Thin_RemoveWait(ReadWord(tl->owner)) == me)
js_Dequeue(tl);
#ifdef DEBUG
else
JS_ASSERT(0);
JS_ASSERT(0); /* unbalanced unlock */
#endif
}
@ -1068,7 +1062,7 @@ js_LockRuntime(JSRuntime *rt)
{
PR_Lock(rt->rtLock);
#ifdef DEBUG
rt->rtLockOwner = CurrentThreadId();
rt->rtLockOwner = js_CurrentThreadId();
#endif
}
@ -1084,9 +1078,9 @@ js_UnlockRuntime(JSRuntime *rt)
void
js_LockScope(JSContext *cx, JSScope *scope)
{
jsword me = cx->thread;
jsword me = CX_THINLOCK_ID(cx);
JS_ASSERT(me == CurrentThreadId());
JS_ASSERT(CURRENT_THREAD_IS_ME(me));
JS_ASSERT(scope->ownercx != cx);
if (CX_THREAD_IS_RUNNING_GC(cx))
return;
@ -1109,7 +1103,7 @@ js_LockScope(JSContext *cx, JSScope *scope)
void
js_UnlockScope(JSContext *cx, JSScope *scope)
{
jsword me = cx->thread;
jsword me = CX_THINLOCK_ID(cx);
/* We hope compilers use me instead of reloading cx->thread in the macro. */
if (CX_THREAD_IS_RUNNING_GC(cx))
@ -1221,7 +1215,7 @@ js_TransferScopeLock(JSContext *cx, JSScope *oldscope, JSScope *newscope)
LOGIT(oldscope, '0');
oldscope->u.count = 0;
tl = &oldscope->lock;
me = cx->thread;
me = CX_THINLOCK_ID(cx);
JS_UNLOCK0(tl, me);
}
@ -1262,7 +1256,7 @@ js_UnlockObj(JSContext *cx, JSObject *obj)
JSBool
js_IsRuntimeLocked(JSRuntime *rt)
{
return CurrentThreadId() == rt->rtLockOwner;
return js_CurrentThreadId() == rt->rtLockOwner;
}
JSBool
@ -1292,7 +1286,8 @@ js_IsScopeLocked(JSContext *cx, JSScope *scope)
JS_ASSERT(scope->ownercx == cx);
return JS_TRUE;
}
return CurrentThreadId() == Thin_RemoveWait(ReadWord(scope->lock.owner));
return js_CurrentThreadId() ==
((JSThread *)Thin_RemoveWait(ReadWord(scope->lock.owner)))->id;
}
#endif /* DEBUG */

View File

@ -45,6 +45,7 @@
#include "pratom.h"
#include "prlock.h"
#include "prcvar.h"
#include "prthread.h"
#include "jsprvtd.h" /* for JSScope, etc. */
#include "jspubtd.h" /* for JSRuntime, etc. */
@ -68,6 +69,9 @@ typedef struct JSThinLock {
JSFatLock *fat;
} JSThinLock;
#define CX_THINLOCK_ID(cx) ((jsword)(cx)->thread)
#define CURRENT_THREAD_IS_ME(me) (((JSThread *)me)->id == js_CurrentThreadId())
typedef PRLock JSLock;
typedef struct JSFatLockTable {
@ -83,8 +87,7 @@ typedef struct JSFatLockTable {
#define JS_ATOMIC_DECREMENT(p) PR_AtomicDecrement((PRInt32 *)(p))
#define JS_ATOMIC_ADD(p,v) PR_AtomicAdd((PRInt32 *)(p), (PRInt32)(v))
#define CurrentThreadId() (jsword)PR_GetCurrentThread()
#define JS_CurrentThreadId() js_CurrentThreadId()
#define js_CurrentThreadId() (jsword)PR_GetCurrentThread()
#define JS_NEW_LOCK() PR_NewLock()
#define JS_DESTROY_LOCK(l) PR_DestroyLock(l)
#define JS_ACQUIRE_LOCK(l) PR_Lock(l)
@ -132,7 +135,6 @@ typedef struct JSFatLockTable {
#define JS_TRANSFER_SCOPE_LOCK(cx, scope, newscope) \
js_TransferScopeLock(cx, scope, newscope)
extern jsword js_CurrentThreadId();
extern void js_LockRuntime(JSRuntime *rt);
extern void js_UnlockRuntime(JSRuntime *rt);
extern void js_LockObj(JSContext *cx, JSObject *obj);
@ -141,7 +143,6 @@ extern void js_LockScope(JSContext *cx, JSScope *scope);
extern void js_UnlockScope(JSContext *cx, JSScope *scope);
extern int js_SetupLocks(int,int);
extern void js_CleanupLocks();
extern void js_InitContextForLocking(JSContext *);
extern void js_TransferScopeLock(JSContext *, JSScope *, JSScope *);
extern JS_FRIEND_API(jsval)
js_GetSlotThreadSafe(JSContext *, JSObject *, uint32);
@ -256,7 +257,7 @@ extern JS_INLINE void js_Unlock(JSThinLock *tl, jsword me);
JS_NO_TIMEOUT)
#define JS_NOTIFY_REQUEST_DONE(rt) JS_NOTIFY_CONDVAR((rt)->requestDone)
#define JS_LOCK(P,CX) JS_LOCK0(P,(CX)->thread)
#define JS_UNLOCK(P,CX) JS_UNLOCK0(P,(CX)->thread)
#define JS_LOCK(P,CX) JS_LOCK0(P, CX_THINLOCK_ID(CX))
#define JS_UNLOCK(P,CX) JS_UNLOCK0(P, CX_THINLOCK_ID(CX))
#endif /* jslock_h___ */

View File

@ -96,6 +96,7 @@ typedef struct JSGCRootHashEntry JSGCRootHashEntry;
typedef struct JSGCThing JSGCThing;
typedef struct JSParseNode JSParseNode;
typedef struct JSSharpObjectMap JSSharpObjectMap;
typedef struct JSThread JSThread;
typedef struct JSToken JSToken;
typedef struct JSTokenPos JSTokenPos;
typedef struct JSTokenPtr JSTokenPtr;