зеркало из https://github.com/mozilla/gecko-dev.git
bug 563345 - using js::HashMap for JSRuntime::threads. r=lw
This commit is contained in:
Родитель
b2f96b0ac7
Коммит
4c7a1014cf
|
@ -5612,7 +5612,7 @@ JS_PUBLIC_API(jsword)
|
|||
JS_GetContextThread(JSContext *cx)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
return JS_THREAD_ID(cx);
|
||||
return reinterpret_cast<jsword>(JS_THREAD_ID(cx));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
@ -5629,7 +5629,7 @@ JS_SetContextThread(JSContext *cx)
|
|||
JS_ASSERT(cx->requestDepth == 0);
|
||||
if (cx->thread) {
|
||||
JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
|
||||
return cx->thread->id;
|
||||
return reinterpret_cast<jsword>(cx->thread->id);
|
||||
}
|
||||
|
||||
if (!js_InitContextThread(cx)) {
|
||||
|
@ -5656,7 +5656,7 @@ JS_ClearContextThread(JSContext *cx)
|
|||
if (!cx->thread)
|
||||
return 0;
|
||||
JS_ASSERT(CURRENT_THREAD_IS_ME(cx->thread));
|
||||
jsword old = cx->thread->id;
|
||||
void *old = cx->thread->id;
|
||||
|
||||
/*
|
||||
* We must not race with a GC that accesses cx->thread for all threads,
|
||||
|
@ -5666,7 +5666,7 @@ JS_ClearContextThread(JSContext *cx)
|
|||
AutoLockGC lock(rt);
|
||||
js_WaitForGC(rt);
|
||||
js_ClearContextThread(cx);
|
||||
return old;
|
||||
return reinterpret_cast<jsword>(old);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
|
|
|
@ -195,7 +195,7 @@ JSThreadData::purgeGCFreeLists()
|
|||
#ifdef JS_THREADSAFE
|
||||
|
||||
static JSThread *
|
||||
NewThread(jsword id)
|
||||
NewThread(void *id)
|
||||
{
|
||||
JS_ASSERT(js_CurrentThreadId() == id);
|
||||
JSThread *thread = (JSThread *) js_calloc(sizeof(JSThread));
|
||||
|
@ -223,7 +223,7 @@ DestroyThread(JSThread *thread)
|
|||
JSThread *
|
||||
js_CurrentThread(JSRuntime *rt)
|
||||
{
|
||||
jsword id = js_CurrentThreadId();
|
||||
void *id = js_CurrentThreadId();
|
||||
JS_LOCK_GC(rt);
|
||||
|
||||
/*
|
||||
|
@ -231,14 +231,11 @@ js_CurrentThread(JSRuntime *rt)
|
|||
* instances on all threads, see bug 476934.
|
||||
*/
|
||||
js_WaitForGC(rt);
|
||||
JSThreadsHashEntry *entry = (JSThreadsHashEntry *)
|
||||
JS_DHashTableOperate(&rt->threads,
|
||||
(const void *) id,
|
||||
JS_DHASH_LOOKUP);
|
||||
|
||||
JSThread *thread;
|
||||
if (JS_DHASH_ENTRY_IS_BUSY(&entry->base)) {
|
||||
thread = entry->thread;
|
||||
JS_ASSERT(thread->id == id);
|
||||
JSThread::Map::AddPtr p = rt->threads.lookupForAdd(id);
|
||||
if (p) {
|
||||
thread = p->value;
|
||||
} else {
|
||||
JS_UNLOCK_GC(rt);
|
||||
thread = NewThread(id);
|
||||
|
@ -246,19 +243,16 @@ js_CurrentThread(JSRuntime *rt)
|
|||
return NULL;
|
||||
JS_LOCK_GC(rt);
|
||||
js_WaitForGC(rt);
|
||||
entry = (JSThreadsHashEntry *)
|
||||
JS_DHashTableOperate(&rt->threads, (const void *) id,
|
||||
JS_DHASH_ADD);
|
||||
if (!entry) {
|
||||
if (!rt->threads.relookupOrAdd(p, id, thread)) {
|
||||
JS_UNLOCK_GC(rt);
|
||||
DestroyThread(thread);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Another thread cannot initialize entry->thread. */
|
||||
JS_ASSERT(!entry->thread);
|
||||
entry->thread = thread;
|
||||
/* Another thread cannot add an entry for the current thread id. */
|
||||
JS_ASSERT(p->value == thread);
|
||||
}
|
||||
JS_ASSERT(thread->id == id);
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
@ -283,72 +277,6 @@ js_ClearContextThread(JSContext *cx)
|
|||
cx->thread = NULL;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
thread_matchEntry(JSDHashTable *table,
|
||||
const JSDHashEntryHdr *hdr,
|
||||
const void *key)
|
||||
{
|
||||
const JSThreadsHashEntry *entry = (const JSThreadsHashEntry *) hdr;
|
||||
|
||||
return entry->thread->id == (jsword) key;
|
||||
}
|
||||
|
||||
static const JSDHashTableOps threads_ops = {
|
||||
JS_DHashAllocTable,
|
||||
JS_DHashFreeTable,
|
||||
JS_DHashVoidPtrKeyStub,
|
||||
thread_matchEntry,
|
||||
JS_DHashMoveEntryStub,
|
||||
JS_DHashClearEntryStub,
|
||||
JS_DHashFinalizeStub,
|
||||
NULL
|
||||
};
|
||||
|
||||
static JSDHashOperator
|
||||
thread_destroyer(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 /* index */,
|
||||
void * /* arg */)
|
||||
{
|
||||
JSThreadsHashEntry *entry = (JSThreadsHashEntry *) hdr;
|
||||
JSThread *thread = entry->thread;
|
||||
|
||||
JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList));
|
||||
DestroyThread(thread);
|
||||
return JS_DHASH_REMOVE;
|
||||
}
|
||||
|
||||
static JSDHashOperator
|
||||
thread_purger(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 /* index */,
|
||||
void *arg)
|
||||
{
|
||||
JSContext* cx = (JSContext *) arg;
|
||||
JSThread *thread = ((JSThreadsHashEntry *) hdr)->thread;
|
||||
|
||||
if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
|
||||
JS_ASSERT(cx->thread != thread);
|
||||
js_DestroyScriptsToGC(cx, &thread->data);
|
||||
|
||||
/*
|
||||
* The following is potentially suboptimal as it also zeros the caches
|
||||
* in data, but the code simplicity wins here.
|
||||
*/
|
||||
thread->data.purgeGCFreeLists();
|
||||
DestroyThread(thread);
|
||||
return JS_DHASH_REMOVE;
|
||||
}
|
||||
thread->data.purge(cx);
|
||||
thread->gcThreadMallocBytes = JS_GC_THREAD_MALLOC_LIMIT;
|
||||
return JS_DHASH_NEXT;
|
||||
}
|
||||
|
||||
static JSDHashOperator
|
||||
thread_marker(JSDHashTable *table, JSDHashEntryHdr *hdr, uint32 /* index */,
|
||||
void *arg)
|
||||
{
|
||||
JSThread *thread = ((JSThreadsHashEntry *) hdr)->thread;
|
||||
thread->data.mark((JSTracer *) arg);
|
||||
return JS_DHASH_NEXT;
|
||||
}
|
||||
|
||||
#endif /* JS_THREADSAFE */
|
||||
|
||||
JSThreadData *
|
||||
|
@ -369,11 +297,8 @@ JSBool
|
|||
js_InitThreads(JSRuntime *rt)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
if (!JS_DHashTableInit(&rt->threads, &threads_ops, NULL,
|
||||
sizeof(JSThreadsHashEntry), 4)) {
|
||||
rt->threads.ops = NULL;
|
||||
if (!rt->threads.init(4))
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
rt->threadData.init();
|
||||
#endif
|
||||
|
@ -384,11 +309,14 @@ void
|
|||
js_FinishThreads(JSRuntime *rt)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
if (!rt->threads.ops)
|
||||
if (!rt->threads.initialized())
|
||||
return;
|
||||
JS_DHashTableEnumerate(&rt->threads, thread_destroyer, NULL);
|
||||
JS_DHashTableFinish(&rt->threads);
|
||||
rt->threads.ops = NULL;
|
||||
for (JSThread::Map::Range r = rt->threads.all(); !r.empty(); r.popFront()) {
|
||||
JSThread *thread = r.front().value;
|
||||
JS_ASSERT(JS_CLIST_IS_EMPTY(&thread->contextList));
|
||||
DestroyThread(thread);
|
||||
}
|
||||
rt->threads.clear();
|
||||
#else
|
||||
rt->threadData.finish();
|
||||
#endif
|
||||
|
@ -398,22 +326,32 @@ void
|
|||
js_PurgeThreads(JSContext *cx)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_DHashTableEnumerate(&cx->runtime->threads, thread_purger, cx);
|
||||
for (JSThread::Map::Enum e(cx->runtime->threads);
|
||||
!e.empty();
|
||||
e.popFront()) {
|
||||
JSThread *thread = e.front().value;
|
||||
|
||||
if (JS_CLIST_IS_EMPTY(&thread->contextList)) {
|
||||
JS_ASSERT(cx->thread != thread);
|
||||
js_DestroyScriptsToGC(cx, &thread->data);
|
||||
|
||||
/*
|
||||
* The following is potentially suboptimal as it also zeros the
|
||||
* caches in data, but the code simplicity wins here.
|
||||
*/
|
||||
thread->data.purgeGCFreeLists();
|
||||
DestroyThread(thread);
|
||||
e.removeFront();
|
||||
} else {
|
||||
thread->data.purge(cx);
|
||||
thread->gcThreadMallocBytes = JS_GC_THREAD_MALLOC_LIMIT;
|
||||
}
|
||||
}
|
||||
#else
|
||||
cx->runtime->threadData.purge(cx);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
js_TraceThreads(JSRuntime *rt, JSTracer *trc)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_DHashTableEnumerate(&rt->threads, thread_marker, trc);
|
||||
#else
|
||||
rt->threadData.mark(trc);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* JSOPTION_XML and JSOPTION_ANONFUNFIX must be part of the JS version
|
||||
* associated with scripts, so in addition to storing them in cx->options we
|
||||
|
|
|
@ -588,11 +588,17 @@ struct JSThreadData {
|
|||
* that can be accessed without a global lock.
|
||||
*/
|
||||
struct JSThread {
|
||||
typedef js::HashMap<void *,
|
||||
JSThread *,
|
||||
js::DefaultHasher<void *>,
|
||||
js::SystemAllocPolicy> Map;
|
||||
|
||||
|
||||
/* Linked list of all contexts in use on this thread. */
|
||||
JSCList contextList;
|
||||
|
||||
/* Opaque thread-id, from NSPR's PR_GetCurrentThread(). */
|
||||
jsword id;
|
||||
void *id;
|
||||
|
||||
/* Indicates that the thread is waiting in ClaimTitle from jslock.cpp. */
|
||||
JSTitle *titleToShare;
|
||||
|
@ -625,11 +631,6 @@ const size_t JS_GC_THREAD_MALLOC_LIMIT = 1 << 19;
|
|||
|
||||
#define JS_THREAD_DATA(cx) (&(cx)->thread->data)
|
||||
|
||||
struct JSThreadsHashEntry {
|
||||
JSDHashEntryHdr base;
|
||||
JSThread *thread;
|
||||
};
|
||||
|
||||
extern JSThread *
|
||||
js_CurrentThread(JSRuntime *rt);
|
||||
|
||||
|
@ -861,7 +862,7 @@ struct JSRuntime {
|
|||
/* Lock and owning thread pointer for JS_LOCK_RUNTIME. */
|
||||
PRLock *rtLock;
|
||||
#ifdef DEBUG
|
||||
jsword rtLockOwner;
|
||||
void * rtLockOwner;
|
||||
#endif
|
||||
|
||||
/* Used to synchronize down/up state change; protected by gcLock. */
|
||||
|
@ -897,7 +898,7 @@ struct JSRuntime {
|
|||
*/
|
||||
PRLock *debuggerLock;
|
||||
|
||||
JSDHashTable threads;
|
||||
JSThread::Map threads;
|
||||
#endif /* JS_THREADSAFE */
|
||||
uint32 debuggerMutations;
|
||||
|
||||
|
@ -2049,8 +2050,48 @@ js_FinishThreads(JSRuntime *rt);
|
|||
extern void
|
||||
js_PurgeThreads(JSContext *cx);
|
||||
|
||||
extern void
|
||||
js_TraceThreads(JSRuntime *rt, JSTracer *trc);
|
||||
namespace js {
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
||||
/* Iterator over JSThreadData from all JSThread instances. */
|
||||
class ThreadDataIter : public JSThread::Map::Range
|
||||
{
|
||||
public:
|
||||
ThreadDataIter(JSRuntime *rt) : JSThread::Map::Range(rt->threads.all()) {}
|
||||
|
||||
JSThreadData *threadData() const {
|
||||
return &front().value->data;
|
||||
}
|
||||
};
|
||||
|
||||
#else /* !JS_THREADSAFE */
|
||||
|
||||
class ThreadDataIter
|
||||
{
|
||||
JSRuntime *runtime;
|
||||
bool done;
|
||||
public:
|
||||
ThreadDataIter(JSRuntime *rt) : runtime(rt), done(false) {}
|
||||
|
||||
bool empty() const {
|
||||
return done;
|
||||
}
|
||||
|
||||
void popFront() {
|
||||
JS_ASSERT(!done);
|
||||
done = true;
|
||||
}
|
||||
|
||||
JSThreadData *threadData() const {
|
||||
JS_ASSERT(!done);
|
||||
return &runtime->threadData;
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* !JS_THREADSAFE */
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
* Ensures the JSOPTION_XML and JSOPTION_ANONFUNFIX bits of cx->options are
|
||||
|
|
|
@ -2426,7 +2426,8 @@ js_TraceRuntime(JSTracer *trc)
|
|||
while ((acx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)
|
||||
js_TraceContext(trc, acx);
|
||||
|
||||
js_TraceThreads(rt, trc);
|
||||
for (ThreadDataIter i(rt); !i.empty(); i.popFront())
|
||||
i.threadData()->mark(trc);
|
||||
|
||||
if (rt->gcExtraRootsTraceOp)
|
||||
rt->gcExtraRootsTraceOp(trc, rt->gcExtraRootsData);
|
||||
|
|
|
@ -354,6 +354,11 @@ class HashTable : AllocPolicy
|
|||
return true;
|
||||
}
|
||||
|
||||
bool initialized() const
|
||||
{
|
||||
return !!table;
|
||||
}
|
||||
|
||||
~HashTable()
|
||||
{
|
||||
if (table)
|
||||
|
@ -780,6 +785,7 @@ class HashMap
|
|||
*/
|
||||
HashMap(AllocPolicy a = AllocPolicy()) : impl(a) {}
|
||||
bool init(uint32 len = 0) { return impl.init(len); }
|
||||
bool initialized() const { return impl.initialized(); }
|
||||
|
||||
/*
|
||||
* Return whether the given lookup value is present in the map. E.g.:
|
||||
|
@ -947,6 +953,7 @@ class HashSet
|
|||
*/
|
||||
HashSet(AllocPolicy a = AllocPolicy()) : impl(a) {}
|
||||
bool init(uint32 len = 0) { return impl.init(len); }
|
||||
bool initialized() const { return impl.initialized(); }
|
||||
|
||||
/*
|
||||
* Return whether the given lookup value is present in the map. E.g.:
|
||||
|
|
|
@ -1199,7 +1199,7 @@ void
|
|||
js_UnlockRuntime(JSRuntime *rt)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
rt->rtLockOwner = 0;
|
||||
rt->rtLockOwner = NULL;
|
||||
#endif
|
||||
PR_Unlock(rt->rtLock);
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ struct JSTitle {
|
|||
#define JS_ATOMIC_ADD(p,v) PR_AtomicAdd((PRInt32 *)(p), (PRInt32)(v))
|
||||
#define JS_ATOMIC_SET(p,v) PR_AtomicSet((PRInt32 *)(p), (PRInt32)(v))
|
||||
|
||||
#define js_CurrentThreadId() (jsword)PR_GetCurrentThread()
|
||||
#define js_CurrentThreadId() PR_GetCurrentThread()
|
||||
#define JS_NEW_LOCK() PR_NewLock()
|
||||
#define JS_DESTROY_LOCK(l) PR_DestroyLock(l)
|
||||
#define JS_ACQUIRE_LOCK(l) PR_Lock(l)
|
||||
|
|
Загрузка…
Ссылка в новой задаче