mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge backout.
This commit is contained in:
commit
da659f8bfe
@ -163,6 +163,7 @@ CPPSRCS = \
|
||||
jsscope.cpp \
|
||||
jsscript.cpp \
|
||||
jsstr.cpp \
|
||||
jstask.cpp \
|
||||
jstypedarray.cpp \
|
||||
jsutil.cpp \
|
||||
jswrapper.cpp \
|
||||
@ -230,6 +231,7 @@ INSTALLED_HEADERS = \
|
||||
jsstaticcheck.h \
|
||||
jsstdint.h \
|
||||
jsstr.h \
|
||||
jstask.h \
|
||||
jstracer.h \
|
||||
jstypedarray.h \
|
||||
jstypes.h \
|
||||
|
@ -80,6 +80,7 @@
|
||||
#include "jsscope.h"
|
||||
#include "jsscript.h"
|
||||
#include "jsstr.h"
|
||||
#include "jstask.h"
|
||||
#include "jstracer.h"
|
||||
#include "jsdbgapi.h"
|
||||
#include "prmjtime.h"
|
||||
@ -606,6 +607,15 @@ JSRuntime::init(uint32 maxbytes)
|
||||
wrapObjectCallback = js::TransparentObjectWrapper;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
gcLock = JS_NEW_LOCK();
|
||||
if (!gcLock)
|
||||
return false;
|
||||
gcDone = JS_NEW_CONDVAR(gcLock);
|
||||
if (!gcDone)
|
||||
return false;
|
||||
requestDone = JS_NEW_CONDVAR(gcLock);
|
||||
if (!requestDone)
|
||||
return false;
|
||||
/* this is asymmetric with JS_ShutDown: */
|
||||
if (!js_SetupLocks(8, 16))
|
||||
return false;
|
||||
@ -1836,7 +1846,7 @@ JS_free(JSContext *cx, void *p)
|
||||
JS_PUBLIC_API(void)
|
||||
JS_updateMallocCounter(JSContext *cx, size_t nbytes)
|
||||
{
|
||||
return cx->runtime->updateMallocCounter(nbytes);
|
||||
return cx->updateMallocCounter(nbytes);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(char *)
|
||||
@ -2604,7 +2614,7 @@ JS_NewExternalString(JSContext *cx, jschar *chars, size_t length, intN type)
|
||||
if (!str)
|
||||
return NULL;
|
||||
str->initFlat(chars, length);
|
||||
cx->runtime->updateMallocCounter((length + 1) * sizeof(jschar));
|
||||
cx->updateMallocCounter((length + 1) * sizeof(jschar));
|
||||
return str;
|
||||
}
|
||||
|
||||
@ -4861,10 +4871,7 @@ JS_TriggerOperationCallback(JSContext *cx)
|
||||
JS_PUBLIC_API(void)
|
||||
JS_TriggerAllOperationCallbacks(JSRuntime *rt)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
AutoLockGC lock(rt);
|
||||
#endif
|
||||
TriggerAllOperationCallbacks(rt);
|
||||
js_TriggerAllOperationCallbacks(rt, JS_FALSE);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
|
@ -707,6 +707,7 @@ js_PurgeThreads(JSContext *cx)
|
||||
e.removeFront();
|
||||
} else {
|
||||
thread->data.purge(cx);
|
||||
thread->gcThreadMallocBytes = JS_GC_THREAD_MALLOC_LIMIT;
|
||||
}
|
||||
}
|
||||
#else
|
||||
@ -1931,17 +1932,16 @@ js_HandleExecutionInterrupt(JSContext *cx)
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace js {
|
||||
|
||||
void
|
||||
TriggerAllOperationCallbacks(JSRuntime *rt)
|
||||
js_TriggerAllOperationCallbacks(JSRuntime *rt, JSBool gcLocked)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
Conditionally<AutoLockGC> lockIf(!gcLocked, rt);
|
||||
#endif
|
||||
for (ThreadDataIter i(rt); !i.empty(); i.popFront())
|
||||
i.threadData()->triggerOperationCallback();
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
JSStackFrame *
|
||||
js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp)
|
||||
{
|
||||
@ -2154,38 +2154,45 @@ JSContext::containingSegment(const JSStackFrame *target)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
JSRuntime::onTooMuchMalloc()
|
||||
void
|
||||
JSContext::checkMallocGCPressure(void *p)
|
||||
{
|
||||
if (!p) {
|
||||
js_ReportOutOfMemory(this);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
AutoLockGC lock(this);
|
||||
JS_ASSERT(thread);
|
||||
JS_ASSERT(thread->gcThreadMallocBytes <= 0);
|
||||
ptrdiff_t n = JS_GC_THREAD_MALLOC_LIMIT - thread->gcThreadMallocBytes;
|
||||
thread->gcThreadMallocBytes = JS_GC_THREAD_MALLOC_LIMIT;
|
||||
|
||||
AutoLockGC lock(runtime);
|
||||
runtime->gcMallocBytes -= n;
|
||||
|
||||
/*
|
||||
* We can be called outside a request and can race against a GC that
|
||||
* mutates the JSThread set during the sweeping phase.
|
||||
* Trigger the GC on memory pressure but only if we are inside a request
|
||||
* and not inside a GC.
|
||||
*/
|
||||
js_WaitForGC(this);
|
||||
if (runtime->isGCMallocLimitReached() && thread->requestDepth != 0)
|
||||
#endif
|
||||
TriggerGC(this);
|
||||
}
|
||||
{
|
||||
if (!runtime->gcRunning) {
|
||||
JS_ASSERT(runtime->isGCMallocLimitReached());
|
||||
runtime->gcMallocBytes = -1;
|
||||
|
||||
JS_FRIEND_API(void *)
|
||||
JSRuntime::onOutOfMemory(void *p, size_t nbytes, JSContext *cx)
|
||||
{
|
||||
#ifdef JS_THREADSAFE
|
||||
gcHelperThread.waitBackgroundSweepEnd(this);
|
||||
if (!p)
|
||||
p = ::js_malloc(nbytes);
|
||||
else if (p == reinterpret_cast<void *>(1))
|
||||
p = ::js_calloc(nbytes);
|
||||
else
|
||||
p = ::js_realloc(p, nbytes);
|
||||
if (p)
|
||||
return p;
|
||||
#endif
|
||||
if (cx)
|
||||
js_ReportOutOfMemory(cx);
|
||||
return NULL;
|
||||
/*
|
||||
* Empty the GC free lists to trigger a last-ditch GC when any GC
|
||||
* thing is allocated later on this thread. This makes unnecessary
|
||||
* to check for the memory pressure on the fast path of the GC
|
||||
* allocator. We cannot touch the free lists on other threads as
|
||||
* their manipulation is not thread-safe.
|
||||
*/
|
||||
JS_THREAD_DATA(this)->gcFreeLists.purge();
|
||||
js_TriggerGC(this, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
187
js/src/jscntxt.h
187
js/src/jscntxt.h
@ -70,6 +70,7 @@
|
||||
#include "jsregexp.h"
|
||||
#include "jsutil.h"
|
||||
#include "jsarray.h"
|
||||
#include "jstask.h"
|
||||
#include "jsvector.h"
|
||||
#include "prmjtime.h"
|
||||
|
||||
@ -186,7 +187,7 @@ class ContextAllocPolicy
|
||||
};
|
||||
|
||||
/* Holds the execution state during trace execution. */
|
||||
struct TracerState
|
||||
struct TracerState
|
||||
{
|
||||
JSContext* cx; // current VM context handle
|
||||
double* stackBase; // native stack base
|
||||
@ -1120,7 +1121,7 @@ struct JSThreadData {
|
||||
/* State used by dtoa.c. */
|
||||
DtoaState *dtoaState;
|
||||
|
||||
/*
|
||||
/*
|
||||
* State used to cache some double-to-string conversions. A stupid
|
||||
* optimization aimed directly at v8-splay.js, which stupidly converts
|
||||
* many doubles multiple times in a row.
|
||||
@ -1184,6 +1185,12 @@ struct JSThread {
|
||||
/* Indicates that the thread is waiting in ClaimTitle from jslock.cpp. */
|
||||
JSTitle *titleToShare;
|
||||
|
||||
/*
|
||||
* Thread-local version of JSRuntime.gcMallocBytes to avoid taking
|
||||
* locks on each JS_malloc.
|
||||
*/
|
||||
ptrdiff_t gcThreadMallocBytes;
|
||||
|
||||
/*
|
||||
* This thread is inside js_GC, either waiting until it can start GC, or
|
||||
* waiting for GC to finish on another thread. This thread holds no locks;
|
||||
@ -1201,7 +1208,7 @@ struct JSThread {
|
||||
|
||||
# ifdef DEBUG
|
||||
unsigned checkRequestDepth;
|
||||
# endif
|
||||
# endif
|
||||
|
||||
/* Weak ref, for low-cost sealed title locking */
|
||||
JSTitle *lockedSealedTitle;
|
||||
@ -1210,6 +1217,13 @@ struct JSThread {
|
||||
JSThreadData data;
|
||||
};
|
||||
|
||||
/*
|
||||
* Only when JSThread::gcThreadMallocBytes exhausts the following limit we
|
||||
* update JSRuntime::gcMallocBytes.
|
||||
* .
|
||||
*/
|
||||
const size_t JS_GC_THREAD_MALLOC_LIMIT = 1 << 19;
|
||||
|
||||
#define JS_THREAD_DATA(cx) (&(cx)->thread->data)
|
||||
|
||||
extern JSThread *
|
||||
@ -1256,7 +1270,7 @@ namespace js {
|
||||
struct GCPtrHasher
|
||||
{
|
||||
typedef void *Lookup;
|
||||
|
||||
|
||||
static HashNumber hash(void *key) {
|
||||
return HashNumber(uintptr_t(key) >> JS_GCTHING_ZEROBITS);
|
||||
}
|
||||
@ -1282,7 +1296,7 @@ typedef js::HashMap<void *,
|
||||
|
||||
/* If HashNumber grows, need to change WrapperHasher. */
|
||||
JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
|
||||
|
||||
|
||||
struct WrapperHasher
|
||||
{
|
||||
typedef Value Lookup;
|
||||
@ -1427,16 +1441,18 @@ struct JSRuntime {
|
||||
|
||||
JSGCCallback gcCallback;
|
||||
|
||||
private:
|
||||
/*
|
||||
* Malloc counter to measure memory pressure for GC scheduling. It runs
|
||||
* from gcMaxMallocBytes down to zero.
|
||||
*/
|
||||
volatile ptrdiff_t gcMallocBytes;
|
||||
ptrdiff_t gcMallocBytes;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JSBackgroundThread gcHelperThread;
|
||||
#endif
|
||||
|
||||
public:
|
||||
js::GCChunkAllocator *gcChunkAllocator;
|
||||
|
||||
|
||||
void setCustomGCChunkAllocator(js::GCChunkAllocator *allocator) {
|
||||
JS_ASSERT(allocator);
|
||||
JS_ASSERT(state == JSRTS_DOWN);
|
||||
@ -1488,8 +1504,6 @@ struct JSRuntime {
|
||||
uint32 requestCount;
|
||||
JSThread *gcThread;
|
||||
|
||||
js::GCHelperThread gcHelperThread;
|
||||
|
||||
/* Lock and owning thread pointer for JS_LOCK_RUNTIME. */
|
||||
PRLock *rtLock;
|
||||
#ifdef DEBUG
|
||||
@ -1740,36 +1754,11 @@ struct JSRuntime {
|
||||
void setGCTriggerFactor(uint32 factor);
|
||||
void setGCLastBytes(size_t lastBytes);
|
||||
|
||||
/*
|
||||
* Call the system malloc while checking for GC memory pressure and
|
||||
* reporting OOM error when cx is not null.
|
||||
*/
|
||||
void* malloc(size_t bytes, JSContext *cx = NULL) {
|
||||
updateMallocCounter(bytes);
|
||||
void *p = ::js_malloc(bytes);
|
||||
return JS_LIKELY(!!p) ? p : onOutOfMemory(NULL, bytes, cx);
|
||||
}
|
||||
void* malloc(size_t bytes) { return ::js_malloc(bytes); }
|
||||
|
||||
/*
|
||||
* Call the system calloc while checking for GC memory pressure and
|
||||
* reporting OOM error when cx is not null.
|
||||
*/
|
||||
void* calloc(size_t bytes, JSContext *cx = NULL) {
|
||||
updateMallocCounter(bytes);
|
||||
void *p = ::js_calloc(bytes);
|
||||
return JS_LIKELY(!!p) ? p : onOutOfMemory(reinterpret_cast<void *>(1), bytes, cx);
|
||||
}
|
||||
void* calloc(size_t bytes) { return ::js_calloc(bytes); }
|
||||
|
||||
void* realloc(void* p, size_t bytes, JSContext *cx = NULL) {
|
||||
/*
|
||||
* For compatibility we do not account for realloc that increases
|
||||
* previously allocated memory.
|
||||
*/
|
||||
if (!p)
|
||||
updateMallocCounter(bytes);
|
||||
void *p2 = ::js_realloc(p, bytes);
|
||||
return JS_LIKELY(!!p2) ? p2 : onOutOfMemory(p, bytes, cx);
|
||||
}
|
||||
void* realloc(void* p, size_t bytes) { return ::js_realloc(p, bytes); }
|
||||
|
||||
void free(void* p) { ::js_free(p); }
|
||||
|
||||
@ -1785,38 +1774,6 @@ struct JSRuntime {
|
||||
gcMaxMallocBytes = (ptrdiff_t(value) >= 0) ? value : size_t(-1) >> 1;
|
||||
resetGCMallocBytes();
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this after allocating memory held by GC things, to update memory
|
||||
* pressure counters or report the OOM error if necessary. If oomError and
|
||||
* cx is not null the function also reports OOM error.
|
||||
*
|
||||
* The function must be called outside the GC lock and in case of OOM error
|
||||
* the caller must ensure that no deadlock possible during OOM reporting.
|
||||
*/
|
||||
void updateMallocCounter(size_t nbytes) {
|
||||
/* We tolerate any thread races when updating gcMallocBytes. */
|
||||
ptrdiff_t newCount = gcMallocBytes - ptrdiff_t(nbytes);
|
||||
gcMallocBytes = newCount;
|
||||
if (JS_UNLIKELY(newCount <= 0))
|
||||
onTooMuchMalloc();
|
||||
}
|
||||
|
||||
private:
|
||||
/*
|
||||
* The function must be called outside the GC lock.
|
||||
*/
|
||||
JS_FRIEND_API(void) onTooMuchMalloc();
|
||||
|
||||
/*
|
||||
* This should be called after system malloc/realloc returns NULL to try
|
||||
* to recove some memory or to report an error. Failures in malloc and
|
||||
* calloc are signaled by p == null and p == reinterpret_cast<void *>(1).
|
||||
* Other values of p mean a realloc failure.
|
||||
*
|
||||
* The function must be called outside the GC lock.
|
||||
*/
|
||||
JS_FRIEND_API(void *) onOutOfMemory(void *p, size_t nbytes, JSContext *cx);
|
||||
};
|
||||
|
||||
/* Common macros to access thread-local caches in JSThread or JSRuntime. */
|
||||
@ -2172,7 +2129,7 @@ struct JSContext
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JSThread *thread;
|
||||
unsigned outstandingRequests;/* number of JS_BeginRequest calls
|
||||
@ -2279,34 +2236,87 @@ struct JSContext
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
/*
|
||||
* When non-null JSContext::free delegates the job to the background
|
||||
* thread.
|
||||
* The sweep task for this context.
|
||||
*/
|
||||
js::GCHelperThread *gcBackgroundFree;
|
||||
js::BackgroundSweepTask *gcSweepTask;
|
||||
#endif
|
||||
|
||||
ptrdiff_t &getMallocCounter() {
|
||||
#ifdef JS_THREADSAFE
|
||||
return thread->gcThreadMallocBytes;
|
||||
#else
|
||||
return runtime->gcMallocBytes;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this after allocating memory held by GC things, to update memory
|
||||
* pressure counters or report the OOM error if necessary.
|
||||
*/
|
||||
inline void updateMallocCounter(void *p, size_t nbytes) {
|
||||
JS_ASSERT(ptrdiff_t(nbytes) >= 0);
|
||||
ptrdiff_t &counter = getMallocCounter();
|
||||
counter -= ptrdiff_t(nbytes);
|
||||
if (!p || counter <= 0)
|
||||
checkMallocGCPressure(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call this after successfully allocating memory held by GC things, to
|
||||
* update memory pressure counters.
|
||||
*/
|
||||
inline void updateMallocCounter(size_t nbytes) {
|
||||
JS_ASSERT(ptrdiff_t(nbytes) >= 0);
|
||||
ptrdiff_t &counter = getMallocCounter();
|
||||
counter -= ptrdiff_t(nbytes);
|
||||
if (counter <= 0) {
|
||||
/*
|
||||
* Use 1 as an arbitrary non-null pointer indicating successful
|
||||
* allocation.
|
||||
*/
|
||||
checkMallocGCPressure(reinterpret_cast<void *>(jsuword(1)));
|
||||
}
|
||||
}
|
||||
|
||||
inline void* malloc(size_t bytes) {
|
||||
return runtime->malloc(bytes, this);
|
||||
JS_ASSERT(bytes != 0);
|
||||
void *p = runtime->malloc(bytes);
|
||||
updateMallocCounter(p, bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
inline void* mallocNoReport(size_t bytes) {
|
||||
JS_ASSERT(bytes != 0);
|
||||
return runtime->malloc(bytes, NULL);
|
||||
void *p = runtime->malloc(bytes);
|
||||
if (!p)
|
||||
return NULL;
|
||||
updateMallocCounter(bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
inline void* calloc(size_t bytes) {
|
||||
JS_ASSERT(bytes != 0);
|
||||
return runtime->calloc(bytes, this);
|
||||
void *p = runtime->calloc(bytes);
|
||||
updateMallocCounter(p, bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
inline void* realloc(void* p, size_t bytes) {
|
||||
return runtime->realloc(p, bytes, this);
|
||||
void *orig = p;
|
||||
p = runtime->realloc(p, bytes);
|
||||
|
||||
/*
|
||||
* For compatibility we do not account for realloc that increases
|
||||
* previously allocated memory.
|
||||
*/
|
||||
updateMallocCounter(p, orig ? 0 : bytes);
|
||||
return p;
|
||||
}
|
||||
|
||||
inline void free(void* p) {
|
||||
#ifdef JS_THREADSAFE
|
||||
if (gcBackgroundFree) {
|
||||
gcBackgroundFree->freeLater(p);
|
||||
if (gcSweepTask) {
|
||||
gcSweepTask->freeLater(p);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
@ -3249,13 +3259,14 @@ js_InvokeOperationCallback(JSContext *cx);
|
||||
extern JSBool
|
||||
js_HandleExecutionInterrupt(JSContext *cx);
|
||||
|
||||
namespace js {
|
||||
|
||||
/* Must be called with GC lock taken. */
|
||||
#ifndef JS_THREADSAFE
|
||||
# define js_TriggerAllOperationCallbacks(rt, gcLocked) \
|
||||
js_TriggerAllOperationCallbacks (rt)
|
||||
#endif
|
||||
|
||||
void
|
||||
TriggerAllOperationCallbacks(JSRuntime *rt);
|
||||
|
||||
} /* namespace js */
|
||||
js_TriggerAllOperationCallbacks(JSRuntime *rt, JSBool gcLocked);
|
||||
|
||||
extern JSStackFrame *
|
||||
js_GetScriptedCaller(JSContext *cx, JSStackFrame *fp);
|
||||
@ -3434,7 +3445,7 @@ class AutoValueVector : private AutoGCRooter
|
||||
const Value &back() const { return vector.back(); }
|
||||
|
||||
friend void AutoGCRooter::trace(JSTracer *trc);
|
||||
|
||||
|
||||
private:
|
||||
Vector<Value, 8> vector;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
@ -3494,7 +3505,7 @@ class AutoIdVector : private AutoGCRooter
|
||||
const jsid &back() const { return vector.back(); }
|
||||
|
||||
friend void AutoGCRooter::trace(JSTracer *trc);
|
||||
|
||||
|
||||
private:
|
||||
Vector<jsid, 8> vector;
|
||||
JS_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
|
164
js/src/jsgc.cpp
164
js/src/jsgc.cpp
@ -78,6 +78,7 @@
|
||||
#include "jsscript.h"
|
||||
#include "jsstaticcheck.h"
|
||||
#include "jsstr.h"
|
||||
#include "jstask.h"
|
||||
#include "jstracer.h"
|
||||
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
@ -642,7 +643,7 @@ NewGCArena(JSContext *cx)
|
||||
*/
|
||||
if (!JS_ON_TRACE(cx))
|
||||
return NULL;
|
||||
TriggerGC(rt);
|
||||
js_TriggerGC(cx, true);
|
||||
}
|
||||
|
||||
if (rt->gcFreeArenaChunks.empty()) {
|
||||
@ -802,7 +803,7 @@ GetFinalizableTraceKind(size_t thingKind)
|
||||
JSTRACE_OBJECT, /* FINALIZE_FUNCTION */
|
||||
#if JS_HAS_XML_SUPPORT /* FINALIZE_XML */
|
||||
JSTRACE_XML,
|
||||
#endif
|
||||
#endif
|
||||
JSTRACE_STRING, /* FINALIZE_SHORT_STRING */
|
||||
JSTRACE_STRING, /* FINALIZE_STRING */
|
||||
JSTRACE_STRING, /* FINALIZE_EXTERNAL_STRING0 */
|
||||
@ -929,16 +930,7 @@ js_InitGC(JSRuntime *rt, uint32 maxbytes)
|
||||
return false;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
rt->gcLock = JS_NEW_LOCK();
|
||||
if (!rt->gcLock)
|
||||
return false;
|
||||
rt->gcDone = JS_NEW_CONDVAR(rt->gcLock);
|
||||
if (!rt->gcDone)
|
||||
return false;
|
||||
rt->requestDone = JS_NEW_CONDVAR(rt->gcLock);
|
||||
if (!rt->requestDone)
|
||||
return false;
|
||||
if (!rt->gcHelperThread.init(rt))
|
||||
if (!rt->gcHelperThread.init())
|
||||
return false;
|
||||
#endif
|
||||
|
||||
@ -1109,7 +1101,7 @@ MarkWordConservatively(JSTracer *trc, jsuword w)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if defined JS_DUMP_CONSERVATIVE_GC_ROOTS || defined JS_GCMETER
|
||||
if (IS_GC_MARKING_TRACER(trc))
|
||||
static_cast<GCMarker *>(trc)->conservativeStats.counter[test]++;
|
||||
@ -1179,7 +1171,7 @@ MarkConservativeStackRoots(JSTracer *trc)
|
||||
}
|
||||
#else
|
||||
MarkThreadDataConservatively(trc, &trc->context->runtime->threadData);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_NEVER_INLINE void
|
||||
@ -1205,7 +1197,7 @@ static inline void
|
||||
RecordNativeStackTopForGC(JSContext *cx)
|
||||
{
|
||||
ConservativeGCThreadData *ctd = &JS_THREAD_DATA(cx)->conservativeGC;
|
||||
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
/* Record the stack top here only if we are called from a request. */
|
||||
JS_ASSERT(cx->thread->requestDepth >= ctd->requestThreshold);
|
||||
@ -1234,7 +1226,7 @@ js_FinishGC(JSRuntime *rt)
|
||||
#endif
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
rt->gcHelperThread.finish(rt);
|
||||
rt->gcHelperThread.cancel();
|
||||
#endif
|
||||
FinishGCArenaLists(rt);
|
||||
|
||||
@ -1930,7 +1922,7 @@ Mark(JSTracer *trc, void *thing, uint32 kind)
|
||||
}
|
||||
str = iter.next();
|
||||
} while (str);
|
||||
|
||||
|
||||
} else if (MarkIfUnmarkedGCThing(thing, gcmarker->getMarkColor())) {
|
||||
/*
|
||||
* With JS_GC_ASSUME_LOW_C_STACK defined the mark phase of GC
|
||||
@ -1960,7 +1952,7 @@ void
|
||||
MarkGCThing(JSTracer *trc, void *thing)
|
||||
{
|
||||
JS_ASSERT(size_t(thing) % JS_GCTHING_ALIGN == 0);
|
||||
|
||||
|
||||
if (!thing)
|
||||
return;
|
||||
|
||||
@ -2307,9 +2299,16 @@ MarkRuntime(JSTracer *trc)
|
||||
#endif
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
void
|
||||
TriggerGC(JSRuntime *rt)
|
||||
js_TriggerGC(JSContext *cx, JSBool gcLocked)
|
||||
{
|
||||
JSRuntime *rt = cx->runtime;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(cx->thread->requestDepth > 0);
|
||||
#endif
|
||||
JS_ASSERT(!rt->gcRunning);
|
||||
if (rt->gcIsNeeded)
|
||||
return;
|
||||
@ -2318,12 +2317,10 @@ TriggerGC(JSRuntime *rt)
|
||||
* Trigger the GC when it is safe to call an operation callback on any
|
||||
* thread.
|
||||
*/
|
||||
rt->gcIsNeeded = true;
|
||||
TriggerAllOperationCallbacks(rt);
|
||||
rt->gcIsNeeded = JS_TRUE;
|
||||
js_TriggerAllOperationCallbacks(rt, gcLocked);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
void
|
||||
js_DestroyScriptsToGC(JSContext *cx, JSThreadData *data)
|
||||
{
|
||||
@ -2593,84 +2590,8 @@ FinalizeArenaList(JSContext *cx, unsigned thingKind)
|
||||
|
||||
namespace js {
|
||||
|
||||
bool
|
||||
GCHelperThread::init(JSRuntime *rt)
|
||||
{
|
||||
if (!(wakeup = PR_NewCondVar(rt->gcLock)))
|
||||
return false;
|
||||
if (!(sweepingDone = PR_NewCondVar(rt->gcLock)))
|
||||
return false;
|
||||
|
||||
thread = PR_CreateThread(PR_USER_THREAD, threadMain, rt, PR_PRIORITY_NORMAL,
|
||||
PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
|
||||
return !!thread;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperThread::finish(JSRuntime *rt)
|
||||
{
|
||||
PRThread *join = NULL;
|
||||
{
|
||||
AutoLockGC lock(rt);
|
||||
if (thread && !shutdown) {
|
||||
shutdown = true;
|
||||
PR_NotifyCondVar(wakeup);
|
||||
join = thread;
|
||||
}
|
||||
}
|
||||
if (join) {
|
||||
/* PR_DestroyThread is not necessary. */
|
||||
PR_JoinThread(join);
|
||||
}
|
||||
if (wakeup)
|
||||
PR_DestroyCondVar(wakeup);
|
||||
if (sweepingDone)
|
||||
PR_DestroyCondVar(sweepingDone);
|
||||
}
|
||||
|
||||
/* static */
|
||||
void
|
||||
GCHelperThread::threadMain(void *arg)
|
||||
{
|
||||
JSRuntime *rt = static_cast<JSRuntime *>(arg);
|
||||
rt->gcHelperThread.threadLoop(rt);
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperThread::threadLoop(JSRuntime *rt)
|
||||
{
|
||||
AutoLockGC lock(rt);
|
||||
while (!shutdown) {
|
||||
PR_WaitCondVar(wakeup, PR_INTERVAL_NO_TIMEOUT);
|
||||
if (sweeping) {
|
||||
AutoUnlockGC unlock(rt);
|
||||
doSweep();
|
||||
}
|
||||
sweeping = false;
|
||||
PR_NotifyAllCondVar(sweepingDone);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperThread::startBackgroundSweep(JSRuntime *rt)
|
||||
{
|
||||
/* The caller takes the GC lock. */
|
||||
JS_ASSERT(!sweeping);
|
||||
sweeping = true;
|
||||
PR_NotifyCondVar(wakeup);
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperThread::waitBackgroundSweepEnd(JSRuntime *rt)
|
||||
{
|
||||
AutoLockGC lock(rt);
|
||||
while (sweeping)
|
||||
PR_WaitCondVar(sweepingDone, PR_INTERVAL_NO_TIMEOUT);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(void)
|
||||
GCHelperThread::replenishAndFreeLater(void *ptr)
|
||||
BackgroundSweepTask::replenishAndFreeLater(void *ptr)
|
||||
{
|
||||
JS_ASSERT(freeCursor == freeCursorEnd);
|
||||
do {
|
||||
@ -2689,7 +2610,7 @@ GCHelperThread::replenishAndFreeLater(void *ptr)
|
||||
}
|
||||
|
||||
void
|
||||
GCHelperThread::doSweep()
|
||||
BackgroundSweepTask::run()
|
||||
{
|
||||
if (freeCursor) {
|
||||
void **array = freeCursorEnd - FREE_ARRAY_LENGTH;
|
||||
@ -2702,7 +2623,6 @@ GCHelperThread::doSweep()
|
||||
void **array = *iter;
|
||||
freeElementsAndArray(array, array + FREE_ARRAY_LENGTH);
|
||||
}
|
||||
freeVector.resize(0);
|
||||
}
|
||||
|
||||
}
|
||||
@ -2717,10 +2637,10 @@ SweepCompartments(JSContext *cx)
|
||||
JSCompartment **read = rt->compartments.begin();
|
||||
JSCompartment **end = rt->compartments.end();
|
||||
JSCompartment **write = read;
|
||||
|
||||
|
||||
/* Delete defaultCompartment only during runtime shutdown */
|
||||
rt->defaultCompartment->marked = true;
|
||||
|
||||
|
||||
while (read < end) {
|
||||
JSCompartment *compartment = (*read++);
|
||||
if (compartment->marked) {
|
||||
@ -2804,10 +2724,10 @@ MarkAndSweep(JSContext *cx GCTIMER_PARAM)
|
||||
JS_ASSERT(IS_GC_MARKING_TRACER(&gcmarker));
|
||||
JS_ASSERT(gcmarker.getMarkColor() == BLACK);
|
||||
rt->gcMarkingTracer = &gcmarker;
|
||||
|
||||
|
||||
for (GCChunkSet::Range r(rt->gcChunkSet.all()); !r.empty(); r.popFront())
|
||||
GCChunkInfo::fromChunk(r.front())->clearMarkBitmap();
|
||||
|
||||
|
||||
MarkRuntime(&gcmarker);
|
||||
js_MarkScriptFilenames(rt);
|
||||
|
||||
@ -2823,15 +2743,9 @@ MarkAndSweep(JSContext *cx GCTIMER_PARAM)
|
||||
(void) rt->gcCallback(cx, JSGC_MARK_END);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
/*
|
||||
* cx->gcBackgroundFree is set if we need several mark-and-sweep loops to
|
||||
* finish the GC.
|
||||
*/
|
||||
if(!cx->gcBackgroundFree) {
|
||||
/* Wait until the sweeping from the previois GC finishes. */
|
||||
rt->gcHelperThread.waitBackgroundSweepEnd(rt);
|
||||
cx->gcBackgroundFree = &rt->gcHelperThread;
|
||||
}
|
||||
JS_ASSERT(!cx->gcSweepTask);
|
||||
if (!rt->gcHelperThread.busy())
|
||||
cx->gcSweepTask = new js::BackgroundSweepTask();
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -2919,6 +2833,13 @@ MarkAndSweep(JSContext *cx GCTIMER_PARAM)
|
||||
FreeGCChunks(rt);
|
||||
TIMESTAMP(sweepDestroyEnd);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
if (cx->gcSweepTask) {
|
||||
rt->gcHelperThread.schedule(cx->gcSweepTask);
|
||||
cx->gcSweepTask = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (rt->gcCallback)
|
||||
(void) rt->gcCallback(cx, JSGC_FINALIZE_END);
|
||||
#ifdef DEBUG_srcnotesize
|
||||
@ -3140,16 +3061,13 @@ GCUntilDone(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM)
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
AutoGCSession gcsession(cx);
|
||||
|
||||
METER(rt->gcStats.poke++);
|
||||
|
||||
bool firstRun = true;
|
||||
rt->gcMarkAndSweep = true;
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(!cx->gcBackgroundFree);
|
||||
#endif
|
||||
do {
|
||||
rt->gcPoke = false;
|
||||
|
||||
@ -3167,12 +3085,6 @@ GCUntilDone(JSContext *cx, JSGCInvocationKind gckind GCTIMER_PARAM)
|
||||
// - a finalizer called js_RemoveRoot or js_UnlockGCThingRT.
|
||||
} while (rt->gcPoke);
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(cx->gcBackgroundFree == &rt->gcHelperThread);
|
||||
cx->gcBackgroundFree = NULL;
|
||||
rt->gcHelperThread.startBackgroundSweep(rt);
|
||||
#endif
|
||||
|
||||
rt->gcMarkAndSweep = false;
|
||||
rt->gcRegenShapes = false;
|
||||
rt->setGCLastBytes(rt->gcBytes);
|
||||
@ -3286,7 +3198,7 @@ TraceRuntime(JSTracer *trc)
|
||||
JSContext *cx = trc->context;
|
||||
JSRuntime *rt = cx->runtime;
|
||||
AutoLockGC lock(rt);
|
||||
|
||||
|
||||
if (rt->gcThread != cx->thread) {
|
||||
AutoGCSession gcsession(cx);
|
||||
AutoUnlockGC unlock(rt);
|
||||
|
@ -51,6 +51,7 @@
|
||||
#include "jsbit.h"
|
||||
#include "jsgcchunk.h"
|
||||
#include "jsutil.h"
|
||||
#include "jstask.h"
|
||||
#include "jsvector.h"
|
||||
#include "jsversion.h"
|
||||
#include "jsobj.h"
|
||||
@ -187,12 +188,18 @@ TraceRuntime(JSTracer *trc);
|
||||
extern JS_REQUIRES_STACK JS_FRIEND_API(void)
|
||||
MarkContext(JSTracer *trc, JSContext *acx);
|
||||
|
||||
/* Must be called with GC lock taken. */
|
||||
extern void
|
||||
TriggerGC(JSRuntime *rt);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
/*
|
||||
* Schedule the GC call at a later safe point.
|
||||
*/
|
||||
#ifndef JS_THREADSAFE
|
||||
# define js_TriggerGC(cx, gcLocked) js_TriggerGC (cx)
|
||||
#endif
|
||||
|
||||
extern void
|
||||
js_TriggerGC(JSContext *cx, JSBool gcLocked);
|
||||
|
||||
/*
|
||||
* Kinds of js_GC invocation.
|
||||
*/
|
||||
@ -358,24 +365,18 @@ namespace js {
|
||||
|
||||
/*
|
||||
* During the finalization we do not free immediately. Rather we add the
|
||||
* corresponding pointers to a buffer which we later release on a separated
|
||||
* thread.
|
||||
* corresponding pointers to a buffer which we later release on the
|
||||
* background thread.
|
||||
*
|
||||
* The buffer is implemented as a vector of 64K arrays of pointers, not as a
|
||||
* simple vector, to avoid realloc calls during the vector growth and to not
|
||||
* bloat the binary size of the inlined freeLater method. Any OOM during
|
||||
* buffer growth results in the pointer being freed immediately.
|
||||
*/
|
||||
class GCHelperThread {
|
||||
class BackgroundSweepTask : public JSBackgroundTask {
|
||||
static const size_t FREE_ARRAY_SIZE = size_t(1) << 16;
|
||||
static const size_t FREE_ARRAY_LENGTH = FREE_ARRAY_SIZE / sizeof(void *);
|
||||
|
||||
PRThread* thread;
|
||||
PRCondVar* wakeup;
|
||||
PRCondVar* sweepingDone;
|
||||
bool shutdown;
|
||||
bool sweeping;
|
||||
|
||||
Vector<void **, 16, js::SystemAllocPolicy> freeVector;
|
||||
void **freeCursor;
|
||||
void **freeCursorEnd;
|
||||
@ -390,37 +391,18 @@ class GCHelperThread {
|
||||
js_free(array);
|
||||
}
|
||||
|
||||
static void threadMain(void* arg);
|
||||
|
||||
void threadLoop(JSRuntime *rt);
|
||||
void doSweep();
|
||||
|
||||
public:
|
||||
GCHelperThread()
|
||||
: thread(NULL),
|
||||
wakeup(NULL),
|
||||
sweepingDone(NULL),
|
||||
shutdown(false),
|
||||
sweeping(false),
|
||||
freeCursor(NULL),
|
||||
freeCursorEnd(NULL) { }
|
||||
|
||||
bool init(JSRuntime *rt);
|
||||
void finish(JSRuntime *rt);
|
||||
|
||||
/* Must be called with GC lock taken. */
|
||||
void startBackgroundSweep(JSRuntime *rt);
|
||||
|
||||
/* Must be called outside the GC lock. */
|
||||
void waitBackgroundSweepEnd(JSRuntime *rt);
|
||||
|
||||
BackgroundSweepTask()
|
||||
: freeCursor(NULL), freeCursorEnd(NULL) { }
|
||||
|
||||
void freeLater(void *ptr) {
|
||||
JS_ASSERT(!sweeping);
|
||||
if (freeCursor != freeCursorEnd)
|
||||
*freeCursor++ = ptr;
|
||||
else
|
||||
replenishAndFreeLater(ptr);
|
||||
}
|
||||
|
||||
virtual void run();
|
||||
};
|
||||
|
||||
#endif /* JS_THREADSAFE */
|
||||
@ -480,7 +462,7 @@ struct ConservativeGCThreadData {
|
||||
nativeStackTop = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool hasStackToScan() const {
|
||||
return !!nativeStackTop;
|
||||
}
|
||||
@ -501,7 +483,7 @@ struct GCMarker : public JSTracer {
|
||||
#if defined(JS_DUMP_CONSERVATIVE_GC_ROOTS) || defined(JS_GCMETER)
|
||||
ConservativeGCStats conservativeStats;
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef JS_DUMP_CONSERVATIVE_GC_ROOTS
|
||||
struct ConservativeRoot { void *thing; uint32 traceKind; };
|
||||
Vector<ConservativeRoot, 0, SystemAllocPolicy> conservativeRoots;
|
||||
|
@ -515,7 +515,7 @@ obj_toSource(JSContext *cx, uintN argc, Value *vp)
|
||||
|
||||
if (!chars) {
|
||||
/* If outermost, allocate 4 + 1 for "({})" and the terminator. */
|
||||
chars = (jschar *) cx->runtime->malloc(((outermost ? 4 : 2) + 1) * sizeof(jschar));
|
||||
chars = (jschar *) js_malloc(((outermost ? 4 : 2) + 1) * sizeof(jschar));
|
||||
nchars = 0;
|
||||
if (!chars)
|
||||
goto error;
|
||||
|
@ -86,11 +86,7 @@ js_GenerateShape(JSContext *cx, bool gcLocked)
|
||||
*/
|
||||
rt->shapeGen = SHAPE_OVERFLOW_BIT;
|
||||
shape = SHAPE_OVERFLOW_BIT;
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
Conditionally<AutoLockGC> lockIf(!gcLocked, rt);
|
||||
#endif
|
||||
TriggerGC(rt);
|
||||
js_TriggerGC(cx, gcLocked);
|
||||
}
|
||||
return shape;
|
||||
}
|
||||
@ -162,7 +158,7 @@ PropertyTable::init(JSContext *cx, Shape *lastProp)
|
||||
METER(tableAllocFails);
|
||||
return false;
|
||||
}
|
||||
cx->runtime->updateMallocCounter(JS_BIT(sizeLog2) * sizeof(Shape *));
|
||||
cx->updateMallocCounter(JS_BIT(sizeLog2) * sizeof(Shape *));
|
||||
|
||||
hashShift = JS_DHASH_BITS - sizeLog2;
|
||||
for (Shape::Range r = lastProp->all(); !r.empty(); r.popFront()) {
|
||||
@ -406,7 +402,7 @@ PropertyTable::change(JSContext *cx, int change)
|
||||
entries = newTable;
|
||||
|
||||
/* Treat the above calloc as a JS_malloc, to match CreateScopeTable. */
|
||||
cx->runtime->updateMallocCounter(nbytes);
|
||||
cx->updateMallocCounter(nbytes);
|
||||
|
||||
/* Copy only live entries, leaving removed and free ones behind. */
|
||||
for (oldspp = oldTable; oldsize != 0; oldspp++) {
|
||||
|
130
js/src/jstask.cpp
Normal file
130
js/src/jstask.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9.1 code, released
|
||||
* June 30, 2009.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Andreas Gal <gal@mozilla.com>
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "jstask.h"
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
static void start(void* arg) {
|
||||
((JSBackgroundThread*)arg)->work();
|
||||
}
|
||||
|
||||
JSBackgroundThread::JSBackgroundThread()
|
||||
: thread(NULL), stack(NULL), lock(NULL), wakeup(NULL), shutdown(false)
|
||||
{
|
||||
}
|
||||
|
||||
JSBackgroundThread::~JSBackgroundThread()
|
||||
{
|
||||
if (wakeup)
|
||||
PR_DestroyCondVar(wakeup);
|
||||
if (lock)
|
||||
PR_DestroyLock(lock);
|
||||
/* PR_DestroyThread is not necessary. */
|
||||
}
|
||||
|
||||
bool
|
||||
JSBackgroundThread::init()
|
||||
{
|
||||
if (!(lock = PR_NewLock()))
|
||||
return false;
|
||||
if (!(wakeup = PR_NewCondVar(lock)))
|
||||
return false;
|
||||
thread = PR_CreateThread(PR_USER_THREAD, start, this, PR_PRIORITY_LOW,
|
||||
PR_LOCAL_THREAD, PR_JOINABLE_THREAD, 0);
|
||||
return !!thread;
|
||||
}
|
||||
|
||||
void
|
||||
JSBackgroundThread::cancel()
|
||||
{
|
||||
/* We allow to call the cancel method after failed init. */
|
||||
if (!thread)
|
||||
return;
|
||||
|
||||
PR_Lock(lock);
|
||||
if (shutdown) {
|
||||
PR_Unlock(lock);
|
||||
return;
|
||||
}
|
||||
shutdown = true;
|
||||
PR_NotifyCondVar(wakeup);
|
||||
PR_Unlock(lock);
|
||||
PR_JoinThread(thread);
|
||||
}
|
||||
|
||||
void
|
||||
JSBackgroundThread::work()
|
||||
{
|
||||
PR_Lock(lock);
|
||||
while (!shutdown) {
|
||||
PR_WaitCondVar(wakeup, PR_INTERVAL_NO_TIMEOUT);
|
||||
JSBackgroundTask* t;
|
||||
while ((t = stack) != NULL) {
|
||||
stack = t->next;
|
||||
PR_Unlock(lock);
|
||||
t->run();
|
||||
delete t;
|
||||
PR_Lock(lock);
|
||||
}
|
||||
}
|
||||
PR_Unlock(lock);
|
||||
}
|
||||
|
||||
bool
|
||||
JSBackgroundThread::busy()
|
||||
{
|
||||
return !!stack; // we tolerate some racing here
|
||||
}
|
||||
|
||||
void
|
||||
JSBackgroundThread::schedule(JSBackgroundTask* task)
|
||||
{
|
||||
PR_Lock(lock);
|
||||
if (shutdown) {
|
||||
PR_Unlock(lock);
|
||||
task->run();
|
||||
delete task;
|
||||
return;
|
||||
}
|
||||
task->next = stack;
|
||||
stack = task;
|
||||
PR_NotifyCondVar(wakeup);
|
||||
PR_Unlock(lock);
|
||||
}
|
||||
|
||||
#endif
|
85
js/src/jstask.h
Normal file
85
js/src/jstask.h
Normal file
@ -0,0 +1,85 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=4 sw=4 et tw=99 ft=cpp:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Mozilla SpiderMonkey JavaScript 1.9 code, released
|
||||
* June 30, 2009.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Andreas Gal <gal@mozilla.com>
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either of the GNU General Public License Version 2 or later (the "GPL"),
|
||||
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef jstask_h___
|
||||
#define jstask_h___
|
||||
|
||||
class JSBackgroundTask {
|
||||
friend class JSBackgroundThread;
|
||||
JSBackgroundTask* next;
|
||||
public:
|
||||
virtual ~JSBackgroundTask() {}
|
||||
virtual void run() = 0;
|
||||
};
|
||||
|
||||
#ifdef JS_THREADSAFE
|
||||
|
||||
#include "prthread.h"
|
||||
#include "prlock.h"
|
||||
#include "prcvar.h"
|
||||
|
||||
class JSBackgroundThread {
|
||||
PRThread* thread;
|
||||
JSBackgroundTask* stack;
|
||||
PRLock* lock;
|
||||
PRCondVar* wakeup;
|
||||
bool shutdown;
|
||||
|
||||
public:
|
||||
JSBackgroundThread();
|
||||
~JSBackgroundThread();
|
||||
|
||||
bool init();
|
||||
void cancel();
|
||||
void work();
|
||||
bool busy();
|
||||
void schedule(JSBackgroundTask* task);
|
||||
};
|
||||
|
||||
#else
|
||||
|
||||
class JSBackgroundThread {
|
||||
public:
|
||||
void schedule(JSBackgroundTask* task) {
|
||||
task->run();
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* jstask_h___ */
|
Loading…
Reference in New Issue
Block a user