mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-20 08:51:04 +00:00
Bug 698621 - Part 1: Implement cross-thread dispatching for web workers. r=bent
This commit is contained in:
parent
5ba31d7f86
commit
ba994a2911
7
content/base/crashtests/700512-worker.js
Normal file
7
content/base/crashtests/700512-worker.js
Normal file
@ -0,0 +1,7 @@
|
||||
onmessage = function(event) {
|
||||
var blob = event.data;
|
||||
|
||||
blob.mozSlice(1, 5);
|
||||
|
||||
postMessage("done");
|
||||
}
|
16
content/base/crashtests/700512.html
Normal file
16
content/base/crashtests/700512.html
Normal file
@ -0,0 +1,16 @@
|
||||
<html class="reftest-wait">
|
||||
<script type="text/javascript">
|
||||
var worker = new Worker("700512-worker.js");
|
||||
|
||||
var bb = new MozBlobBuilder();
|
||||
|
||||
bb.append("foo");
|
||||
bb.append("bar");
|
||||
|
||||
worker.onmessage = function() {
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
worker.postMessage(bb.getBlob());
|
||||
</script>
|
||||
</html>
|
@ -100,4 +100,5 @@ load 693212.xhtml
|
||||
load 698974-1.html
|
||||
load 700090-1.html
|
||||
load 700090-2.html
|
||||
load 700512.html
|
||||
load xhr_html_nullresponse.html
|
||||
|
@ -455,6 +455,51 @@ ResumeWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow)
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class WorkerTaskRunnable : public WorkerRunnable
|
||||
{
|
||||
public:
|
||||
WorkerTaskRunnable(WorkerPrivate* aPrivate, WorkerTask* aTask)
|
||||
: WorkerRunnable(aPrivate, WorkerThread, UnchangedBusyCount),
|
||||
mTask(aTask)
|
||||
{ }
|
||||
|
||||
virtual bool PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) {
|
||||
return true;
|
||||
}
|
||||
|
||||
virtual void PostDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
|
||||
bool aDispatchResult)
|
||||
{ }
|
||||
|
||||
virtual bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
private:
|
||||
nsRefPtr<WorkerTask> mTask;
|
||||
};
|
||||
|
||||
bool
|
||||
WorkerTaskRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
return mTask->RunTask(aCx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerCrossThreadDispatcher::PostTask(WorkerTask* aTask)
|
||||
{
|
||||
mozilla::MutexAutoLock lock(mMutex);
|
||||
if (!mPrivate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsRefPtr<WorkerTaskRunnable> runnable = new WorkerTaskRunnable(mPrivate, aTask);
|
||||
runnable->Dispatch(nsnull);
|
||||
return true;
|
||||
}
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
PRUint32 RuntimeService::sDefaultJSContextOptions = kRequiredJSContextOptions;
|
||||
|
@ -134,10 +134,10 @@ public:
|
||||
SetJSPrivateSafeish(aCx, aObj, NULL);
|
||||
}
|
||||
|
||||
protected:
|
||||
static WorkerPrivate*
|
||||
GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName);
|
||||
|
||||
protected:
|
||||
static JSBool
|
||||
ConstructInternal(JSContext* aCx, uintN aArgc, jsval* aVp,
|
||||
bool aIsChromeWorker)
|
||||
@ -471,6 +471,23 @@ ClearPrivateSlot(JSContext* aCx, JSObject* aObj, bool aSaveEventHandlers)
|
||||
|
||||
} // namespace worker
|
||||
|
||||
WorkerCrossThreadDispatcher*
|
||||
GetWorkerCrossThreadDispatcher(JSContext* aCx, jsval aWorker)
|
||||
{
|
||||
if (JSVAL_IS_PRIMITIVE(aWorker)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
WorkerPrivate* w =
|
||||
Worker::GetInstancePrivate(aCx, JSVAL_TO_OBJECT(aWorker),
|
||||
"GetWorkerCrossThreadDispatcher");
|
||||
if (!w) {
|
||||
return NULL;
|
||||
}
|
||||
return w->GetCrossThreadDispatcher();
|
||||
}
|
||||
|
||||
|
||||
namespace chromeworker {
|
||||
|
||||
bool
|
||||
|
@ -3051,6 +3051,16 @@ WorkerPrivate::NotifyInternal(JSContext* aCx, Status aStatus)
|
||||
mStatus = aStatus;
|
||||
}
|
||||
|
||||
// Now that status > Running, no-one can create a new mCrossThreadDispatcher
|
||||
// if we don't already have one.
|
||||
if (mCrossThreadDispatcher) {
|
||||
// Since we'll no longer process events, make sure we no longer allow
|
||||
// anyone to post them.
|
||||
// We have to do this without mMutex held, since our mutex must be
|
||||
// acquired *after* mCrossThreadDispatcher's mutex when they're both held.
|
||||
mCrossThreadDispatcher->Forget();
|
||||
}
|
||||
|
||||
NS_ASSERTION(previousStatus != Pending, "How is this possible?!");
|
||||
|
||||
NS_ASSERTION(previousStatus >= Canceling || mKillTime.IsNull(),
|
||||
@ -3588,6 +3598,16 @@ WorkerPrivate::AssertIsOnWorkerThread() const
|
||||
}
|
||||
#endif
|
||||
|
||||
WorkerCrossThreadDispatcher*
|
||||
WorkerPrivate::GetCrossThreadDispatcher()
|
||||
{
|
||||
mozilla::MutexAutoLock lock(mMutex);
|
||||
if (!mCrossThreadDispatcher && mStatus <= Running) {
|
||||
mCrossThreadDispatcher = new WorkerCrossThreadDispatcher(this);
|
||||
}
|
||||
return mCrossThreadDispatcher;
|
||||
}
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
// Force instantiation.
|
||||
|
@ -508,6 +508,7 @@ class WorkerPrivate : public WorkerPrivateParent<WorkerPrivate>
|
||||
|
||||
// Touched on multiple threads, protected with mMutex.
|
||||
JSContext* mJSContext;
|
||||
nsRefPtr<WorkerCrossThreadDispatcher> mCrossThreadDispatcher;
|
||||
|
||||
// Things touched on worker thread only.
|
||||
nsTArray<ParentType*> mChildWorkers;
|
||||
@ -693,6 +694,9 @@ public:
|
||||
{ }
|
||||
#endif
|
||||
|
||||
WorkerCrossThreadDispatcher*
|
||||
GetCrossThreadDispatcher();
|
||||
|
||||
private:
|
||||
WorkerPrivate(JSContext* aCx, JSObject* aObject, WorkerPrivate* aParent,
|
||||
JSContext* aParentJSContext, const nsAString& aScriptURL,
|
||||
|
@ -40,6 +40,9 @@
|
||||
#define mozilla_dom_workers_workers_h__
|
||||
|
||||
#include "jspubtd.h"
|
||||
#include "jsapi.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "mozilla/Mutex.h"
|
||||
|
||||
#define BEGIN_WORKERS_NAMESPACE \
|
||||
namespace mozilla { namespace dom { namespace workers {
|
||||
@ -52,6 +55,8 @@ class nsPIDOMWindow;
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class WorkerPrivate;
|
||||
|
||||
struct PrivatizableBase
|
||||
{ };
|
||||
|
||||
@ -78,6 +83,44 @@ SuspendWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
|
||||
void
|
||||
ResumeWorkersForWindow(JSContext* aCx, nsPIDOMWindow* aWindow);
|
||||
|
||||
class WorkerTask {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerTask)
|
||||
|
||||
virtual ~WorkerTask() { }
|
||||
|
||||
virtual bool RunTask(JSContext* aCx) = 0;
|
||||
};
|
||||
|
||||
class WorkerCrossThreadDispatcher {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(WorkerCrossThreadDispatcher)
|
||||
|
||||
WorkerCrossThreadDispatcher(WorkerPrivate* aPrivate) :
|
||||
mMutex("WorkerCrossThreadDispatcher"), mPrivate(aPrivate) {}
|
||||
void Forget()
|
||||
{
|
||||
mozilla::MutexAutoLock lock(mMutex);
|
||||
mPrivate = nsnull;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generically useful function for running a bit of C++ code on the worker
|
||||
* thread.
|
||||
*/
|
||||
bool PostTask(WorkerTask* aTask);
|
||||
|
||||
protected:
|
||||
friend class WorkerPrivate;
|
||||
|
||||
// Must be acquired *before* the WorkerPrivate's mutex, when they're both held.
|
||||
mozilla::Mutex mMutex;
|
||||
WorkerPrivate* mPrivate;
|
||||
};
|
||||
|
||||
WorkerCrossThreadDispatcher*
|
||||
GetWorkerCrossThreadDispatcher(JSContext* aCx, jsval aWorker);
|
||||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
#endif /* mozilla_dom_workers_workers_h__ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user