Bug 698621 - Part 1: Implement cross-thread dispatching for web workers. r=bent

This commit is contained in:
Blake Kaplan 2011-12-05 15:58:27 +08:00
Родитель 5ba31d7f86
Коммит ba994a2911
8 изменённых файлов: 154 добавлений и 1 удалений

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

@ -0,0 +1,7 @@
onmessage = function(event) {
var blob = event.data;
blob.mozSlice(1, 5);
postMessage("done");
}

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

@ -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__ */