зеркало из https://github.com/mozilla/pjs.git
bug 551680 - replacing JS_(Suspend|Resume)Request with JSAutoSuspendRequest. r=mrbkap
This commit is contained in:
Родитель
0d27280dc0
Коммит
3007509e8e
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
|
@ -514,71 +514,49 @@ DOMWorkerOperationCallback(JSContext* aCx)
|
|||
nsDOMWorker* worker = (nsDOMWorker*)JS_GetContextPrivate(aCx);
|
||||
NS_ASSERTION(worker, "This must never be null!");
|
||||
|
||||
PRBool wasSuspended = PR_FALSE;
|
||||
PRBool extraThreadAllowed = PR_FALSE;
|
||||
jsrefcount suspendDepth = 0;
|
||||
PRBool canceled = worker->IsCanceled();
|
||||
if (!canceled && worker->IsSuspended()) {
|
||||
JSAutoSuspendRequest suspended(aCx);
|
||||
|
||||
for (;;) {
|
||||
// Kill execution if we're canceled.
|
||||
if (worker->IsCanceled()) {
|
||||
LOG(("Forcefully killing JS for worker [0x%p]",
|
||||
static_cast<void*>(worker)));
|
||||
// Since we're going to block this thread we should open up a new thread
|
||||
// in the thread pool for other workers. Must check the return value to
|
||||
// make sure we don't decrement when we failed.
|
||||
PRBool extraThreadAllowed =
|
||||
NS_SUCCEEDED(gDOMThreadService->ChangeThreadPoolMaxThreads(1));
|
||||
|
||||
if (wasSuspended) {
|
||||
if (extraThreadAllowed) {
|
||||
gDOMThreadService->ChangeThreadPoolMaxThreads(-1);
|
||||
}
|
||||
JS_ResumeRequest(aCx, suspendDepth);
|
||||
// Flush JIT caches now before suspending to avoid holding memory that we
|
||||
// are not going to use.
|
||||
JS_FlushCaches(aCx);
|
||||
|
||||
for (;;) {
|
||||
nsAutoMonitor mon(worker->Pool()->Monitor());
|
||||
|
||||
// There's a small chance that the worker was canceled after our check
|
||||
// above in which case we shouldn't wait here. We're guaranteed not to
|
||||
// race here because the pool reenters its monitor after canceling each
|
||||
// worker in order to notify its condition variable.
|
||||
canceled = worker->IsCanceled();
|
||||
if (!canceled && worker->IsSuspended()) {
|
||||
mon.Wait();
|
||||
}
|
||||
|
||||
// Kill execution of the currently running JS.
|
||||
JS_ClearPendingException(aCx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
// Break out if we're not suspended.
|
||||
if (!worker->IsSuspended()) {
|
||||
if (wasSuspended) {
|
||||
if (extraThreadAllowed) {
|
||||
gDOMThreadService->ChangeThreadPoolMaxThreads(-1);
|
||||
}
|
||||
JS_ResumeRequest(aCx, suspendDepth);
|
||||
else {
|
||||
break;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
if (!wasSuspended) {
|
||||
// Make sure to suspend our request while we block like this, otherwise we
|
||||
// prevent GC for everyone.
|
||||
suspendDepth = JS_SuspendRequest(aCx);
|
||||
|
||||
// Since we're going to block this thread we should open up a new thread
|
||||
// in the thread pool for other workers. Must check the return value to
|
||||
// make sure we don't decrement when we failed.
|
||||
extraThreadAllowed =
|
||||
NS_SUCCEEDED(gDOMThreadService->ChangeThreadPoolMaxThreads(1));
|
||||
|
||||
// Flush JIT caches now before suspending to avoid holding memory that we
|
||||
// are not going to use.
|
||||
JS_FlushCaches(aCx);
|
||||
|
||||
// Only do all this setup once.
|
||||
wasSuspended = PR_TRUE;
|
||||
}
|
||||
|
||||
nsAutoMonitor mon(worker->Pool()->Monitor());
|
||||
|
||||
// There's a small chance that the worker was canceled after our check
|
||||
// above in which case we shouldn't wait here. We're guaranteed not to race
|
||||
// here because the pool reenters its monitor after canceling each worker
|
||||
// in order to notify its condition variable.
|
||||
if (worker->IsSuspended() && !worker->IsCanceled()) {
|
||||
mon.Wait();
|
||||
if (extraThreadAllowed) {
|
||||
gDOMThreadService->ChangeThreadPoolMaxThreads(-1);
|
||||
}
|
||||
}
|
||||
|
||||
NS_NOTREACHED("Should never get here!");
|
||||
return JS_FALSE;
|
||||
if (canceled) {
|
||||
LOG(("Forcefully killing JS for worker [0x%p]",
|
||||
static_cast<void*>(worker)));
|
||||
// Kill execution of the currently running JS.
|
||||
JS_ClearPendingException(aCx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -236,11 +236,10 @@ Function::Execute(JSContext* cx, PRUint32 argc, jsval* vp)
|
|||
|
||||
// suspend the request before we call into the function, since the call
|
||||
// may block or otherwise take a long time to return.
|
||||
jsrefcount rc = JS_SuspendRequest(cx);
|
||||
|
||||
ffi_call(&mCIF, FFI_FN(mFunc), resultValue.mData, reinterpret_cast<void**>(values.Elements()));
|
||||
|
||||
JS_ResumeRequest(cx, rc);
|
||||
{
|
||||
JSAutoSuspendRequest suspended(cx);
|
||||
ffi_call(&mCIF, FFI_FN(mFunc), resultValue.mData, reinterpret_cast<void**>(values.Elements()));
|
||||
}
|
||||
|
||||
// prepare a JS object from the result
|
||||
jsval rval;
|
||||
|
|
|
@ -878,6 +878,26 @@ JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth)
|
|||
#endif
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_TransferRequest(JSContext *cx, JSContext *another)
|
||||
{
|
||||
JS_ASSERT(cx != another);
|
||||
JS_ASSERT(cx->runtime == another->runtime);
|
||||
#ifdef JS_THREADSAFE
|
||||
JS_ASSERT(cx->thread);
|
||||
JS_ASSERT(another->thread);
|
||||
JS_ASSERT(cx->thread == another->thread);
|
||||
JS_ASSERT(cx->requestDepth != 0);
|
||||
JS_ASSERT(another->requestDepth == 0);
|
||||
|
||||
/* Serialize access to JSContext::requestDepth from other threads. */
|
||||
JS_LOCK_GC(cx->runtime);
|
||||
another->requestDepth = cx->requestDepth;
|
||||
cx->requestDepth = 0;
|
||||
JS_UNLOCK_GC(cx->runtime);
|
||||
#endif
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_Lock(JSRuntime *rt)
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
* vim: set ts=8 sw=4 et tw=78:
|
||||
*
|
||||
* ***** BEGIN LICENSE BLOCK *****
|
||||
|
@ -561,6 +561,9 @@ JS_SuspendRequest(JSContext *cx);
|
|||
extern JS_PUBLIC_API(void)
|
||||
JS_ResumeRequest(JSContext *cx, jsrefcount saveDepth);
|
||||
|
||||
extern JS_PUBLIC_API(void)
|
||||
JS_TransferRequest(JSContext *cx, JSContext *another);
|
||||
|
||||
#ifdef __cplusplus
|
||||
JS_END_EXTERN_C
|
||||
|
||||
|
@ -626,6 +629,27 @@ class JSAutoSuspendRequest {
|
|||
#endif
|
||||
};
|
||||
|
||||
class JSAutoTransferRequest
|
||||
{
|
||||
public:
|
||||
JSAutoTransferRequest(JSContext* cx1, JSContext* cx2)
|
||||
: cx1(cx1), cx2(cx2) {
|
||||
if(cx1 != cx2)
|
||||
JS_TransferRequest(cx1, cx2);
|
||||
}
|
||||
~JSAutoTransferRequest() {
|
||||
if(cx1 != cx2)
|
||||
JS_TransferRequest(cx2, cx1);
|
||||
}
|
||||
private:
|
||||
JSContext* const cx1;
|
||||
JSContext* const cx2;
|
||||
|
||||
/* Not copyable. */
|
||||
JSAutoTransferRequest(JSAutoTransferRequest &);
|
||||
void operator =(JSAutoTransferRequest&);
|
||||
};
|
||||
|
||||
JS_BEGIN_EXTERN_C
|
||||
#endif
|
||||
|
||||
|
|
|
@ -469,12 +469,15 @@ Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY)
|
|||
size_t len = 0; /* initialize to avoid warnings */
|
||||
do {
|
||||
ScheduleWatchdog(cx->runtime, -1);
|
||||
jsrefcount rc = JS_SuspendRequest(cx);
|
||||
gCanceled = false;
|
||||
errno = 0;
|
||||
char *line = GetLine(file, startline == lineno ? "js> " : "");
|
||||
|
||||
char *line;
|
||||
{
|
||||
JSAutoSuspendRequest suspended(cx);
|
||||
line = GetLine(file, startline == lineno ? "js> " : "");
|
||||
}
|
||||
if (!line) {
|
||||
JS_ResumeRequest(cx, rc);
|
||||
if (errno) {
|
||||
JS_ReportError(cx, strerror(errno));
|
||||
free(buffer);
|
||||
|
@ -498,7 +501,6 @@ Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY)
|
|||
if (!newBuf) {
|
||||
free(buffer);
|
||||
free(line);
|
||||
JS_ResumeRequest(cx, rc);
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return;
|
||||
}
|
||||
|
@ -512,7 +514,6 @@ Process(JSContext *cx, JSObject *obj, char *filename, JSBool forceTTY)
|
|||
free(line);
|
||||
}
|
||||
lineno++;
|
||||
JS_ResumeRequest(cx, rc);
|
||||
if (!ScheduleWatchdog(cx->runtime, gTimeoutInterval)) {
|
||||
hitEOF = JS_TRUE;
|
||||
break;
|
||||
|
@ -1920,8 +1921,15 @@ DisassWithSrc(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
|
||||
/* burn the leading lines */
|
||||
line2 = JS_PCToLineNumber(cx, script, pc);
|
||||
for (line1 = 0; line1 < line2 - 1; line1++)
|
||||
(void) fgets(linebuf, LINE_BUF_LEN, file); /* Intentionally unused result. */
|
||||
for (line1 = 0; line1 < line2 - 1; line1++) {
|
||||
char *tmp = fgets(linebuf, LINE_BUF_LEN, file);
|
||||
if (!tmp) {
|
||||
JS_ReportError(cx, "failed to read %s fully",
|
||||
script->filename);
|
||||
ok = JS_FALSE;
|
||||
goto bail;
|
||||
}
|
||||
}
|
||||
|
||||
bupline = 0;
|
||||
while (pc < end) {
|
||||
|
@ -2947,7 +2955,6 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
const jschar *src;
|
||||
size_t srclen;
|
||||
JSBool lazy, split, ok;
|
||||
jsval v;
|
||||
JSStackFrame *fp;
|
||||
|
||||
sobj = NULL;
|
||||
|
@ -2963,7 +2970,7 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
}
|
||||
JS_SetOptions(scx, JS_GetOptions(cx));
|
||||
|
||||
JS_BeginRequest(scx);
|
||||
JS_TransferRequest(cx, scx);
|
||||
src = JS_GetStringChars(str);
|
||||
srclen = JS_GetStringLength(str);
|
||||
split = lazy = JS_FALSE;
|
||||
|
@ -2987,12 +2994,12 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
ok = JS_FALSE;
|
||||
goto out;
|
||||
}
|
||||
v = BOOLEAN_TO_JSVAL(lazy);
|
||||
ok = JS_SetProperty(cx, sobj, "lazy", &v);
|
||||
AutoValueRooter root(scx, BOOLEAN_TO_JSVAL(lazy));
|
||||
ok = JS_SetProperty(scx, sobj, "lazy", root.addr());
|
||||
if (!ok)
|
||||
goto out;
|
||||
if (split)
|
||||
sobj = split_outerObject(cx, sobj);
|
||||
sobj = split_outerObject(scx, sobj);
|
||||
}
|
||||
|
||||
if (srclen == 0) {
|
||||
|
@ -3002,7 +3009,7 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
fp = JS_GetScriptedCaller(cx, NULL);
|
||||
JS_SetGlobalObject(scx, sobj);
|
||||
JS_ToggleOptions(scx, JSOPTION_DONT_REPORT_UNCAUGHT);
|
||||
OBJ_TO_INNER_OBJECT(cx, sobj);
|
||||
OBJ_TO_INNER_OBJECT(scx, sobj);
|
||||
if (!sobj) {
|
||||
ok = JS_FALSE;
|
||||
goto out;
|
||||
|
@ -3012,16 +3019,18 @@ EvalInContext(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
|
|||
JS_PCToLineNumber(cx, fp->script,
|
||||
fp->regs->pc),
|
||||
rval);
|
||||
if (!ok) {
|
||||
if (JS_GetPendingException(scx, &v))
|
||||
JS_SetPendingException(cx, v);
|
||||
else
|
||||
JS_ReportOutOfMemory(cx);
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
JS_EndRequest(scx);
|
||||
jsval exceptionValue = JSVAL_NULL;
|
||||
JSBool exception = !ok && JS_GetPendingException(scx, &exceptionValue);
|
||||
|
||||
JS_TransferRequest(scx, cx);
|
||||
if (exception)
|
||||
JS_SetPendingException(cx, exceptionValue);
|
||||
else if (!ok)
|
||||
JS_ClearPendingException(cx);
|
||||
|
||||
WITH_LOCKED_CONTEXT_LIST(
|
||||
JS_DestroyContextNoGC(scx)
|
||||
);
|
||||
|
@ -3135,7 +3144,7 @@ Sleep_fn(JSContext *cx, uintN argc, jsval *vp)
|
|||
if (t_ticks == 0) {
|
||||
JS_YieldRequest(cx);
|
||||
} else {
|
||||
jsrefcount rc = JS_SuspendRequest(cx);
|
||||
JSAutoSuspendRequest suspended(cx);
|
||||
PR_Lock(gWatchdogLock);
|
||||
PRIntervalTime to_wakeup = PR_IntervalNow() + t_ticks;
|
||||
for (;;) {
|
||||
|
@ -3148,7 +3157,6 @@ Sleep_fn(JSContext *cx, uintN argc, jsval *vp)
|
|||
t_ticks = to_wakeup - now;
|
||||
}
|
||||
PR_Unlock(gWatchdogLock);
|
||||
JS_ResumeRequest(cx, rc);
|
||||
}
|
||||
return !gCanceled;
|
||||
}
|
||||
|
@ -3236,9 +3244,9 @@ Scatter(JSContext *cx, uintN argc, jsval *vp)
|
|||
jsuint n; /* number of threads */
|
||||
JSObject *inArr;
|
||||
JSObject *arr;
|
||||
JSObject *global;
|
||||
ScatterData sd;
|
||||
JSBool ok;
|
||||
jsrefcount rc;
|
||||
|
||||
sd.lock = NULL;
|
||||
sd.cvar = NULL;
|
||||
|
@ -3305,6 +3313,7 @@ Scatter(JSContext *cx, uintN argc, jsval *vp)
|
|||
}
|
||||
}
|
||||
|
||||
global = JS_GetGlobalObject(cx);
|
||||
for (i = 1; i < n; i++) {
|
||||
JSContext *newcx;
|
||||
WITH_LOCKED_CONTEXT_LIST(
|
||||
|
@ -3312,9 +3321,11 @@ Scatter(JSContext *cx, uintN argc, jsval *vp)
|
|||
);
|
||||
if (!newcx)
|
||||
goto fail;
|
||||
JS_BeginRequest(newcx);
|
||||
JS_SetGlobalObject(newcx, JS_GetGlobalObject(cx));
|
||||
JS_EndRequest(newcx);
|
||||
|
||||
{
|
||||
JSAutoTransferRequest transfer(cx, newcx);
|
||||
JS_SetGlobalObject(newcx, global);
|
||||
}
|
||||
JS_ClearContextThread(newcx);
|
||||
sd.threads[i].cx = newcx;
|
||||
}
|
||||
|
@ -3347,11 +3358,12 @@ Scatter(JSContext *cx, uintN argc, jsval *vp)
|
|||
|
||||
DoScatteredWork(cx, &sd.threads[0]);
|
||||
|
||||
rc = JS_SuspendRequest(cx);
|
||||
for (i = 1; i < n; i++) {
|
||||
PR_JoinThread(sd.threads[i].thr);
|
||||
{
|
||||
JSAutoSuspendRequest suspended(cx);
|
||||
for (i = 1; i < n; i++) {
|
||||
PR_JoinThread(sd.threads[i].thr);
|
||||
}
|
||||
}
|
||||
JS_ResumeRequest(cx, rc);
|
||||
|
||||
success:
|
||||
arr = JS_NewArrayObject(cx, n, sd.results);
|
||||
|
|
|
@ -195,7 +195,7 @@ JSBool XPCDispObject::Dispatch(XPCCallContext& ccx, IDispatch * disp,
|
|||
// Scope the lock
|
||||
{
|
||||
// avoid deadlock in case the native method blocks somehow
|
||||
AutoJSSuspendRequest req(ccx); // scoped suspend of request
|
||||
JSAutoSuspendRequest req(ccx); // scoped suspend of request
|
||||
// call IDispatch's invoke
|
||||
invokeResult= disp->Invoke(
|
||||
dispID, // IDispatch ID
|
||||
|
|
|
@ -2179,7 +2179,7 @@ nsXPConnect::UpdateXOWs(JSContext* aJSContext,
|
|||
if(!list)
|
||||
return NS_OK; // No wrappers to update.
|
||||
|
||||
AutoJSRequestWithNoCallContext req(aJSContext);
|
||||
JSAutoRequest req(aJSContext);
|
||||
|
||||
Link* cur = list;
|
||||
if(cur->obj && !PerformOp(aJSContext, aWay, cur->obj))
|
||||
|
|
|
@ -3221,7 +3221,7 @@ xpc_CreateSandboxObject(JSContext * cx, jsval * vp, nsISupports *prinOrSop)
|
|||
if (!tempcx)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
AutoJSRequestWithNoCallContext req(tempcx);
|
||||
JSAutoRequest req(tempcx);
|
||||
JSObject *sandbox = JS_NewObject(tempcx, &SandboxClass, nsnull, nsnull);
|
||||
if (!sandbox)
|
||||
return NS_ERROR_XPC_UNEXPECTED;
|
||||
|
@ -3592,7 +3592,7 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source,
|
|||
nsresult rv = NS_OK;
|
||||
|
||||
{
|
||||
AutoJSRequestWithNoCallContext req(sandcx->GetJSContext());
|
||||
JSAutoRequest req(sandcx->GetJSContext());
|
||||
JSString *str = nsnull;
|
||||
if (!JS_EvaluateUCScriptForPrincipals(sandcx->GetJSContext(), sandbox,
|
||||
jsPrincipals,
|
||||
|
@ -3608,9 +3608,7 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source,
|
|||
// Stash the exception in |cx| so we can execute code on
|
||||
// sandcx without a pending exception.
|
||||
{
|
||||
AutoJSSuspendRequestWithNoCallContext sus(sandcx->GetJSContext());
|
||||
AutoJSRequestWithNoCallContext cxreq(cx);
|
||||
|
||||
JSAutoTransferRequest transfer(sandcx->GetJSContext(), cx);
|
||||
JS_SetPendingException(cx, exn);
|
||||
}
|
||||
|
||||
|
@ -3620,8 +3618,7 @@ xpc_EvalInSandbox(JSContext *cx, JSObject *sandbox, const nsAString& source,
|
|||
// exception into a string.
|
||||
str = JS_ValueToString(sandcx->GetJSContext(), exn);
|
||||
|
||||
AutoJSSuspendRequestWithNoCallContext sus(sandcx->GetJSContext());
|
||||
AutoJSRequestWithNoCallContext cxreq(cx);
|
||||
JSAutoTransferRequest transfer(sandcx->GetJSContext(), cx);
|
||||
if (str) {
|
||||
// We converted the exception to a string. Use that
|
||||
// as the value exception.
|
||||
|
|
|
@ -157,7 +157,7 @@ LogSlimWrapperNotCreated(JSContext *cx, nsISupports *obj, const char *reason)
|
|||
className ? " for " : "", className ? className : "", reason, obj);
|
||||
if(className)
|
||||
PR_Free(className);
|
||||
AutoJSRequestWithNoCallContext autoRequest(cx);
|
||||
JSAutoRequest autoRequest(cx);
|
||||
xpc_DumpJSStack(cx, JS_FALSE, JS_FALSE, JS_FALSE);
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -3771,136 +3771,6 @@ private:
|
|||
nsCString mCategory;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
// XXX allowing for future notifications to XPCCallContext
|
||||
|
||||
class AutoJSRequest
|
||||
{
|
||||
public:
|
||||
AutoJSRequest(XPCCallContext& aCCX)
|
||||
: mCCX(aCCX), mCX(aCCX.GetJSContext()) {BeginRequest();}
|
||||
~AutoJSRequest() {EndRequest();}
|
||||
|
||||
void EndRequest() {
|
||||
if(mCX) {
|
||||
JS_EndRequest(mCX);
|
||||
mCX = nsnull;
|
||||
}
|
||||
}
|
||||
private:
|
||||
void BeginRequest() {
|
||||
if(JS_GetContextThread(mCX))
|
||||
JS_BeginRequest(mCX);
|
||||
else
|
||||
mCX = nsnull;
|
||||
}
|
||||
private:
|
||||
XPCCallContext& mCCX;
|
||||
JSContext* mCX;
|
||||
};
|
||||
|
||||
class AutoJSSuspendRequest
|
||||
{
|
||||
public:
|
||||
AutoJSSuspendRequest(XPCCallContext& aCCX)
|
||||
: mCX(aCCX.GetJSContext()) {SuspendRequest();}
|
||||
~AutoJSSuspendRequest() {ResumeRequest();}
|
||||
|
||||
void ResumeRequest() {
|
||||
if(mCX) {
|
||||
JS_ResumeRequest(mCX, mDepth);
|
||||
mCX = nsnull;
|
||||
}
|
||||
}
|
||||
private:
|
||||
void SuspendRequest() {
|
||||
if(JS_GetContextThread(mCX))
|
||||
mDepth = JS_SuspendRequest(mCX);
|
||||
else
|
||||
mCX = nsnull;
|
||||
}
|
||||
private:
|
||||
JSContext* mCX;
|
||||
jsrefcount mDepth;
|
||||
};
|
||||
|
||||
class AutoJSSuspendRequestWithNoCallContext
|
||||
{
|
||||
public:
|
||||
AutoJSSuspendRequestWithNoCallContext(JSContext *aCX)
|
||||
: mCX(aCX) {SuspendRequest();}
|
||||
~AutoJSSuspendRequestWithNoCallContext() {ResumeRequest();}
|
||||
|
||||
void ResumeRequest() {
|
||||
if(mCX) {
|
||||
JS_ResumeRequest(mCX, mDepth);
|
||||
mCX = nsnull;
|
||||
}
|
||||
}
|
||||
private:
|
||||
void SuspendRequest() {
|
||||
if(JS_GetContextThread(mCX))
|
||||
mDepth = JS_SuspendRequest(mCX);
|
||||
else
|
||||
mCX = nsnull;
|
||||
}
|
||||
private:
|
||||
JSContext* mCX;
|
||||
jsrefcount mDepth;
|
||||
};
|
||||
|
||||
class AutoJSSuspendNonMainThreadRequest
|
||||
{
|
||||
public:
|
||||
AutoJSSuspendNonMainThreadRequest(JSContext *aCX)
|
||||
: mCX(aCX) {SuspendRequest();}
|
||||
~AutoJSSuspendNonMainThreadRequest() {ResumeRequest();}
|
||||
|
||||
void ResumeRequest() {
|
||||
if (mCX) {
|
||||
JS_ResumeRequest(mCX, mDepth);
|
||||
mCX = nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void SuspendRequest() {
|
||||
if (mCX && !XPCPerThreadData::IsMainThread(mCX))
|
||||
mDepth = JS_SuspendRequest(mCX);
|
||||
else
|
||||
mCX = nsnull;
|
||||
}
|
||||
|
||||
JSContext *mCX;
|
||||
jsrefcount mDepth;
|
||||
};
|
||||
|
||||
|
||||
/*****************************************/
|
||||
|
||||
class AutoJSRequestWithNoCallContext
|
||||
{
|
||||
public:
|
||||
AutoJSRequestWithNoCallContext(JSContext* aCX) : mCX(aCX) {BeginRequest();}
|
||||
~AutoJSRequestWithNoCallContext() {EndRequest();}
|
||||
|
||||
void EndRequest() {
|
||||
if(mCX) {
|
||||
JS_EndRequest(mCX);
|
||||
mCX = nsnull;
|
||||
}
|
||||
}
|
||||
private:
|
||||
void BeginRequest() {
|
||||
if(JS_GetContextThread(mCX))
|
||||
JS_BeginRequest(mCX);
|
||||
else
|
||||
mCX = nsnull;
|
||||
}
|
||||
private:
|
||||
JSContext* mCX;
|
||||
};
|
||||
|
||||
/***************************************************************************/
|
||||
class AutoJSErrorAndExceptionEater
|
||||
{
|
||||
|
|
|
@ -248,12 +248,12 @@ XPCJSContextStack::GetSafeJSContext(JSContext * *aSafeJSContext)
|
|||
|
||||
if(xpc && (xpcrt = xpc->GetRuntime()) && (rt = xpcrt->GetJSRuntime()))
|
||||
{
|
||||
JSObject *glob;
|
||||
mSafeJSContext = JS_NewContext(rt, 8192);
|
||||
if(mSafeJSContext)
|
||||
{
|
||||
// scoped JS Request
|
||||
AutoJSRequestWithNoCallContext req(mSafeJSContext);
|
||||
JSObject *glob;
|
||||
JSAutoRequest req(mSafeJSContext);
|
||||
glob = JS_NewObject(mSafeJSContext, &global_class, NULL, NULL);
|
||||
|
||||
#ifndef XPCONNECT_STANDALONE
|
||||
|
@ -276,23 +276,26 @@ XPCJSContextStack::GetSafeJSContext(JSContext * *aSafeJSContext)
|
|||
// nsCOMPtr or dealt with, or we'll release in the finalize
|
||||
// hook.
|
||||
#endif
|
||||
if(!glob || NS_FAILED(xpc->InitClasses(mSafeJSContext, glob)))
|
||||
if(glob && NS_FAILED(xpc->InitClasses(mSafeJSContext, glob)))
|
||||
{
|
||||
// Explicitly end the request since we are about to kill
|
||||
// the JSContext that 'req' will try to use when it
|
||||
// goes out of scope.
|
||||
req.EndRequest();
|
||||
JS_DestroyContext(mSafeJSContext);
|
||||
mSafeJSContext = nsnull;
|
||||
glob = nsnull;
|
||||
}
|
||||
// Save it off so we can destroy it later, even if
|
||||
// mSafeJSContext has been set to another context
|
||||
// via SetSafeJSContext. If we don't get here,
|
||||
// then mSafeJSContext must have been set via
|
||||
// SetSafeJSContext, and we're not responsible for
|
||||
// destroying the passed-in context.
|
||||
mOwnSafeJSContext = mSafeJSContext;
|
||||
|
||||
}
|
||||
if(!glob && mSafeJSContext)
|
||||
{
|
||||
// Destroy the context outside the scope of JSAutoRequest that
|
||||
// uses the context in its destructor.
|
||||
JS_DestroyContext(mSafeJSContext);
|
||||
mSafeJSContext = nsnull;
|
||||
}
|
||||
// Save it off so we can destroy it later, even if
|
||||
// mSafeJSContext has been set to another context
|
||||
// via SetSafeJSContext. If we don't get here,
|
||||
// then mSafeJSContext must have been set via
|
||||
// SetSafeJSContext, and we're not responsible for
|
||||
// destroying the passed-in context.
|
||||
mOwnSafeJSContext = mSafeJSContext;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2310,8 +2310,15 @@ XPCWrappedNative::CallMethod(XPCCallContext& ccx,
|
|||
|
||||
nsISupports* qiresult = nsnull;
|
||||
{
|
||||
AutoJSSuspendNonMainThreadRequest req(ccx.GetJSContext());
|
||||
invokeResult = callee->QueryInterface(*iid, (void**) &qiresult);
|
||||
if(XPCPerThreadData::IsMainThread(ccx))
|
||||
{
|
||||
invokeResult = callee->QueryInterface(*iid, (void**) &qiresult);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAutoSuspendRequest suspended(ccx);
|
||||
invokeResult = callee->QueryInterface(*iid, (void**) &qiresult);
|
||||
}
|
||||
}
|
||||
|
||||
xpcc->SetLastResult(invokeResult);
|
||||
|
@ -2721,10 +2728,18 @@ XPCWrappedNative::CallMethod(XPCCallContext& ccx,
|
|||
|
||||
// do the invoke
|
||||
{
|
||||
AutoJSSuspendNonMainThreadRequest req(ccx.GetJSContext());
|
||||
invokeResult = NS_InvokeByIndex(callee, vtblIndex,
|
||||
paramCount + wantsOptArgc,
|
||||
dispatchParams);
|
||||
uint8 allParamCount = paramCount + wantsOptArgc;
|
||||
if(XPCPerThreadData::IsMainThread(ccx))
|
||||
{
|
||||
invokeResult = NS_InvokeByIndex(callee, vtblIndex,
|
||||
allParamCount, dispatchParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAutoSuspendRequest suspended(ccx);
|
||||
invokeResult = NS_InvokeByIndex(callee, vtblIndex,
|
||||
allParamCount, dispatchParams);
|
||||
}
|
||||
}
|
||||
|
||||
xpcc->SetLastResult(invokeResult);
|
||||
|
|
|
@ -203,19 +203,11 @@ XPCNativeMember::Resolve(XPCCallContext& ccx, XPCNativeInterface* iface)
|
|||
|
||||
const char *memberName = iface->GetMemberName(ccx, this);
|
||||
|
||||
jsrefcount suspendDepth = 0;
|
||||
if(cx != ccx) {
|
||||
// Switching contexts, suspend the old and enter the new request.
|
||||
suspendDepth = JS_SuspendRequest(ccx);
|
||||
JS_BeginRequest(cx);
|
||||
}
|
||||
|
||||
JSFunction *fun = JS_NewFunction(cx, callback, argc, flags, nsnull,
|
||||
memberName);
|
||||
|
||||
if(suspendDepth) {
|
||||
JS_EndRequest(cx);
|
||||
JS_ResumeRequest(ccx, suspendDepth);
|
||||
JSFunction *fun;
|
||||
// Switching contexts, suspend the old and enter the new request.
|
||||
{
|
||||
JSAutoTransferRequest transfer(ccx, cx);
|
||||
fun = JS_NewFunction(cx, callback, argc, flags, nsnull, memberName);
|
||||
}
|
||||
|
||||
if(!fun)
|
||||
|
|
Загрузка…
Ссылка в новой задаче