This commit is contained in:
Robert Sayre 2010-05-11 16:37:47 -04:00
Родитель 5d299c6212 d371f6cf09
Коммит ac239c8785
7 изменённых файлов: 118 добавлений и 105 удалений

Просмотреть файл

@ -5612,7 +5612,7 @@ JS_PUBLIC_API(jsword)
JS_GetContextThread(JSContext *cx)
{
#ifdef JS_THREADSAFE
return reinterpret_cast<jsword>(JS_THREAD_ID(cx));
return 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 reinterpret_cast<jsword>(cx->thread->id);
return 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));
void *old = cx->thread->id;
jsword 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 reinterpret_cast<jsword>(old);
return old;
#else
return 0;
#endif

Просмотреть файл

@ -195,7 +195,7 @@ JSThreadData::purgeGCFreeLists()
#ifdef JS_THREADSAFE
static JSThread *
NewThread(void *id)
NewThread(jsword 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)
{
void *id = js_CurrentThreadId();
jsword id = js_CurrentThreadId();
JS_LOCK_GC(rt);
/*
@ -231,11 +231,14 @@ 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;
JSThread::Map::AddPtr p = rt->threads.lookupForAdd(id);
if (p) {
thread = p->value;
if (JS_DHASH_ENTRY_IS_BUSY(&entry->base)) {
thread = entry->thread;
JS_ASSERT(thread->id == id);
} else {
JS_UNLOCK_GC(rt);
thread = NewThread(id);
@ -243,16 +246,19 @@ js_CurrentThread(JSRuntime *rt)
return NULL;
JS_LOCK_GC(rt);
js_WaitForGC(rt);
if (!rt->threads.relookupOrAdd(p, id, thread)) {
entry = (JSThreadsHashEntry *)
JS_DHashTableOperate(&rt->threads, (const void *) id,
JS_DHASH_ADD);
if (!entry) {
JS_UNLOCK_GC(rt);
DestroyThread(thread);
return NULL;
}
/* Another thread cannot add an entry for the current thread id. */
JS_ASSERT(p->value == thread);
/* Another thread cannot initialize entry->thread. */
JS_ASSERT(!entry->thread);
entry->thread = thread;
}
JS_ASSERT(thread->id == id);
return thread;
}
@ -277,6 +283,72 @@ 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 *
@ -297,8 +369,11 @@ JSBool
js_InitThreads(JSRuntime *rt)
{
#ifdef JS_THREADSAFE
if (!rt->threads.init(4))
if (!JS_DHashTableInit(&rt->threads, &threads_ops, NULL,
sizeof(JSThreadsHashEntry), 4)) {
rt->threads.ops = NULL;
return false;
}
#else
rt->threadData.init();
#endif
@ -309,14 +384,11 @@ void
js_FinishThreads(JSRuntime *rt)
{
#ifdef JS_THREADSAFE
if (!rt->threads.initialized())
if (!rt->threads.ops)
return;
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();
JS_DHashTableEnumerate(&rt->threads, thread_destroyer, NULL);
JS_DHashTableFinish(&rt->threads);
rt->threads.ops = NULL;
#else
rt->threadData.finish();
#endif
@ -326,32 +398,22 @@ void
js_PurgeThreads(JSContext *cx)
{
#ifdef JS_THREADSAFE
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;
}
}
JS_DHashTableEnumerate(&cx->runtime->threads, thread_purger, cx);
#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,17 +588,11 @@ 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(). */
void *id;
jsword id;
/* Indicates that the thread is waiting in ClaimTitle from jslock.cpp. */
JSTitle *titleToShare;
@ -631,6 +625,11 @@ 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);
@ -862,7 +861,7 @@ struct JSRuntime {
/* Lock and owning thread pointer for JS_LOCK_RUNTIME. */
PRLock *rtLock;
#ifdef DEBUG
void * rtLockOwner;
jsword rtLockOwner;
#endif
/* Used to synchronize down/up state change; protected by gcLock. */
@ -898,7 +897,7 @@ struct JSRuntime {
*/
PRLock *debuggerLock;
JSThread::Map threads;
JSDHashTable threads;
#endif /* JS_THREADSAFE */
uint32 debuggerMutations;
@ -2050,48 +2049,8 @@ js_FinishThreads(JSRuntime *rt);
extern void
js_PurgeThreads(JSContext *cx);
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 */
extern void
js_TraceThreads(JSRuntime *rt, JSTracer *trc);
/*
* Ensures the JSOPTION_XML and JSOPTION_ANONFUNFIX bits of cx->options are

Просмотреть файл

@ -2426,8 +2426,7 @@ js_TraceRuntime(JSTracer *trc)
while ((acx = js_ContextIterator(rt, JS_TRUE, &iter)) != NULL)
js_TraceContext(trc, acx);
for (ThreadDataIter i(rt); !i.empty(); i.popFront())
i.threadData()->mark(trc);
js_TraceThreads(rt, trc);
if (rt->gcExtraRootsTraceOp)
rt->gcExtraRootsTraceOp(trc, rt->gcExtraRootsData);

Просмотреть файл

@ -352,11 +352,6 @@ class HashTable : AllocPolicy
return true;
}
bool initialized() const
{
return !!table;
}
~HashTable()
{
if (table)
@ -781,7 +776,6 @@ 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.:
@ -949,7 +943,6 @@ 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 = NULL;
rt->rtLockOwner = 0;
#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() PR_GetCurrentThread()
#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)