зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1054638 - Move WorkerThread into its own file, r=khuey.
This commit is contained in:
Родитель
793516eb34
Коммит
c8b921018d
|
@ -26,6 +26,7 @@
|
|||
#include "jsfriendapi.h"
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/CycleCollectedJSRuntime.h"
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/dom/asmjscache/AsmJSCache.h"
|
||||
#include "mozilla/dom/AtomList.h"
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
|
@ -45,7 +46,6 @@
|
|||
#include "nsLayoutStatics.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThread.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsXPCOMPrivate.h"
|
||||
|
@ -56,15 +56,12 @@
|
|||
#include "ipc/Nuwa.h"
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "nsThreadManager.h"
|
||||
#endif
|
||||
|
||||
#include "Principal.h"
|
||||
#include "ServiceWorker.h"
|
||||
#include "SharedWorker.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
#include "WorkerThread.h"
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
#include "BackgroundChildImpl.h"
|
||||
|
@ -90,10 +87,6 @@ using mozilla::Preferences;
|
|||
// The size of the worker JS allocation threshold in MB. May be changed via pref.
|
||||
#define WORKER_DEFAULT_ALLOCATION_THRESHOLD 30
|
||||
|
||||
// The C stack size. We use the same stack size on all platforms for
|
||||
// consistency.
|
||||
#define WORKER_STACK_SIZE 256 * sizeof(size_t) * 1024
|
||||
|
||||
// Half the size of the actual C stack, to be safe.
|
||||
#define WORKER_CONTEXT_NATIVE_STACK_LIMIT 128 * sizeof(size_t) * 1024
|
||||
|
||||
|
@ -907,6 +900,58 @@ private:
|
|||
WorkerPrivate* mWorkerPrivate;
|
||||
};
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
|
||||
class TestPBackgroundCreateCallback MOZ_FINAL :
|
||||
public nsIIPCBackgroundChildCreateCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
virtual void
|
||||
ActorCreated(PBackgroundChild* aActor) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(aActor);
|
||||
}
|
||||
|
||||
virtual void
|
||||
ActorFailed() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_CRASH("TestPBackground() should not fail "
|
||||
"GetOrCreateForCurrentThread()");
|
||||
}
|
||||
|
||||
private:
|
||||
~TestPBackgroundCreateCallback()
|
||||
{ }
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(TestPBackgroundCreateCallback,
|
||||
nsIIPCBackgroundChildCreateCallback);
|
||||
|
||||
void
|
||||
TestPBackground()
|
||||
{
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
if (gTestPBackground) {
|
||||
// Randomize value to validate workers are not cross-posting messages.
|
||||
uint32_t testValue;
|
||||
size_t randomSize = PR_GetRandomNoise(&testValue, sizeof(testValue));
|
||||
MOZ_RELEASE_ASSERT(randomSize == sizeof(testValue));
|
||||
nsCString testStr;
|
||||
testStr.AppendInt(testValue);
|
||||
testStr.AppendInt(reinterpret_cast<int64_t>(PR_GetCurrentThread()));
|
||||
PBackgroundChild* existingBackgroundChild =
|
||||
BackgroundChild::GetForCurrentThread();
|
||||
MOZ_RELEASE_ASSERT(existingBackgroundChild);
|
||||
bool ok = existingBackgroundChild->SendPBackgroundTestConstructor(testStr);
|
||||
MOZ_RELEASE_ASSERT(ok);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // ENABLE_TESTS
|
||||
|
||||
class WorkerBackgroundChildCallback MOZ_FINAL :
|
||||
public nsIIPCBackgroundChildCreateCallback
|
||||
{
|
||||
|
@ -942,15 +987,15 @@ private:
|
|||
class WorkerThreadPrimaryRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsRefPtr<RuntimeService::WorkerThread> mThread;
|
||||
nsRefPtr<WorkerThread> mThread;
|
||||
JSRuntime* mParentRuntime;
|
||||
|
||||
class FinishedRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
nsRefPtr<RuntimeService::WorkerThread> mThread;
|
||||
nsRefPtr<WorkerThread> mThread;
|
||||
|
||||
public:
|
||||
explicit FinishedRunnable(already_AddRefed<RuntimeService::WorkerThread> aThread)
|
||||
explicit FinishedRunnable(already_AddRefed<WorkerThread> aThread)
|
||||
: mThread(aThread)
|
||||
{
|
||||
MOZ_ASSERT(mThread);
|
||||
|
@ -967,7 +1012,7 @@ class WorkerThreadPrimaryRunnable MOZ_FINAL : public nsRunnable
|
|||
|
||||
public:
|
||||
WorkerThreadPrimaryRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
RuntimeService::WorkerThread* aThread,
|
||||
WorkerThread* aThread,
|
||||
JSRuntime* aParentRuntime)
|
||||
: mWorkerPrivate(aWorkerPrivate), mThread(aThread), mParentRuntime(aParentRuntime)
|
||||
{
|
||||
|
@ -1078,129 +1123,6 @@ PlatformOverrideChanged(const char* /* aPrefName */, void* /* aClosure */)
|
|||
|
||||
} /* anonymous namespace */
|
||||
|
||||
class RuntimeService::WorkerThread MOZ_FINAL : public nsThread
|
||||
{
|
||||
class Observer MOZ_FINAL : public nsIThreadObserver
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
public:
|
||||
explicit Observer(WorkerPrivate* aWorkerPrivate)
|
||||
: mWorkerPrivate(aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
private:
|
||||
~Observer()
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
NS_DECL_NSITHREADOBSERVER
|
||||
};
|
||||
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsRefPtr<Observer> mObserver;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Protected by nsThread::mLock.
|
||||
bool mAcceptingNonWorkerRunnables;
|
||||
#endif
|
||||
|
||||
public:
|
||||
static already_AddRefed<WorkerThread>
|
||||
Create();
|
||||
|
||||
void
|
||||
SetWorker(WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_IMETHOD
|
||||
Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) MOZ_OVERRIDE;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
IsAcceptingNonWorkerRunnables()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
return mAcceptingNonWorkerRunnables;
|
||||
}
|
||||
|
||||
void
|
||||
SetAcceptingNonWorkerRunnables(bool aAcceptingNonWorkerRunnables)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
mAcceptingNonWorkerRunnables = aAcceptingNonWorkerRunnables;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
class TestPBackgroundCreateCallback MOZ_FINAL :
|
||||
public nsIIPCBackgroundChildCreateCallback
|
||||
{
|
||||
public:
|
||||
virtual void ActorCreated(PBackgroundChild* actor) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(actor);
|
||||
}
|
||||
|
||||
virtual void ActorFailed() MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_CRASH("TestPBackground() should not fail GetOrCreateForCurrentThread()");
|
||||
}
|
||||
|
||||
private:
|
||||
~TestPBackgroundCreateCallback()
|
||||
{ }
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS;
|
||||
};
|
||||
|
||||
void
|
||||
TestPBackground()
|
||||
{
|
||||
using namespace mozilla::ipc;
|
||||
if (gTestPBackground) {
|
||||
// Randomize value to validate workers are not cross-posting messages.
|
||||
uint32_t testValue;
|
||||
size_t randomSize = PR_GetRandomNoise(&testValue, sizeof(testValue));
|
||||
MOZ_RELEASE_ASSERT(randomSize == sizeof(testValue));
|
||||
nsCString testStr;
|
||||
testStr.AppendInt(testValue);
|
||||
testStr.AppendInt(reinterpret_cast<int64_t>(PR_GetCurrentThread()));
|
||||
PBackgroundChild* existingBackgroundChild =
|
||||
BackgroundChild::GetForCurrentThread();
|
||||
MOZ_RELEASE_ASSERT(existingBackgroundChild);
|
||||
bool ok = existingBackgroundChild->SendPBackgroundTestConstructor(testStr);
|
||||
MOZ_RELEASE_ASSERT(ok);
|
||||
}
|
||||
}
|
||||
#endif // #ENABLE_TESTS
|
||||
|
||||
private:
|
||||
WorkerThread()
|
||||
: nsThread(nsThread::NOT_MAIN_THREAD, WORKER_STACK_SIZE),
|
||||
mWorkerPrivate(nullptr)
|
||||
#ifdef DEBUG
|
||||
, mAcceptingNonWorkerRunnables(true)
|
||||
#endif
|
||||
{ }
|
||||
|
||||
~WorkerThread()
|
||||
{ }
|
||||
};
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
NS_IMPL_ISUPPORTS(RuntimeService::WorkerThread::TestPBackgroundCreateCallback,
|
||||
nsIIPCBackgroundChildCreateCallback);
|
||||
#endif
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
void
|
||||
|
@ -1307,6 +1229,12 @@ GetCurrentThreadJSContext()
|
|||
|
||||
END_WORKERS_NAMESPACE
|
||||
|
||||
struct RuntimeService::IdleThreadInfo
|
||||
{
|
||||
nsRefPtr<WorkerThread> mThread;
|
||||
mozilla::TimeStamp mExpirationTime;
|
||||
};
|
||||
|
||||
// This is only touched on the main thread. Initialized in Init() below.
|
||||
JSSettings RuntimeService::sDefaultJSSettings;
|
||||
bool RuntimeService::sDefaultPreferences[WORKERPREF_COUNT] = { false };
|
||||
|
@ -2592,145 +2520,6 @@ RuntimeService::JSVersionChanged(const char* /* aPrefName */, void* /* aClosure
|
|||
options.setVersion(useLatest ? JSVERSION_LATEST : JSVERSION_DEFAULT);
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<RuntimeService::WorkerThread>
|
||||
RuntimeService::WorkerThread::Create()
|
||||
{
|
||||
MOZ_ASSERT(nsThreadManager::get());
|
||||
|
||||
nsRefPtr<WorkerThread> thread = new WorkerThread();
|
||||
if (NS_FAILED(thread->Init())) {
|
||||
NS_WARNING("Failed to create new thread!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_SetThreadName(thread, "DOM Worker");
|
||||
|
||||
return thread.forget();
|
||||
}
|
||||
|
||||
void
|
||||
RuntimeService::WorkerThread::SetWorker(WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mThread);
|
||||
MOZ_ASSERT_IF(aWorkerPrivate, !mWorkerPrivate);
|
||||
MOZ_ASSERT_IF(!aWorkerPrivate, mWorkerPrivate);
|
||||
|
||||
// No need to lock here because mWorkerPrivate is only modified on mThread.
|
||||
|
||||
if (mWorkerPrivate) {
|
||||
MOZ_ASSERT(mObserver);
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(RemoveObserver(mObserver)));
|
||||
|
||||
mObserver = nullptr;
|
||||
mWorkerPrivate->SetThread(nullptr);
|
||||
}
|
||||
|
||||
mWorkerPrivate = aWorkerPrivate;
|
||||
|
||||
if (mWorkerPrivate) {
|
||||
mWorkerPrivate->SetThread(this);
|
||||
|
||||
nsRefPtr<Observer> observer = new Observer(mWorkerPrivate);
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(AddObserver(observer)));
|
||||
|
||||
mObserver.swap(observer);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(RuntimeService::WorkerThread, nsThread)
|
||||
|
||||
NS_IMETHODIMP
|
||||
RuntimeService::WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
|
||||
{
|
||||
// May be called on any thread!
|
||||
|
||||
#ifdef DEBUG
|
||||
if (PR_GetCurrentThread() == mThread) {
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
else if (aRunnable && !IsAcceptingNonWorkerRunnables()) {
|
||||
// Only enforce cancelable runnables after we've started the worker loop.
|
||||
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(aRunnable);
|
||||
MOZ_ASSERT(cancelable,
|
||||
"Should have been wrapped by the worker's event target!");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Workers only support asynchronous dispatch for now.
|
||||
if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsIRunnable* runnableToDispatch;
|
||||
nsRefPtr<WorkerRunnable> workerRunnable;
|
||||
|
||||
if (aRunnable && PR_GetCurrentThread() == mThread) {
|
||||
// No need to lock here because mWorkerPrivate is only modified on mThread.
|
||||
workerRunnable = mWorkerPrivate->MaybeWrapAsWorkerRunnable(aRunnable);
|
||||
runnableToDispatch = workerRunnable;
|
||||
}
|
||||
else {
|
||||
runnableToDispatch = aRunnable;
|
||||
}
|
||||
|
||||
nsresult rv = nsThread::Dispatch(runnableToDispatch, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(RuntimeService::WorkerThread::Observer, nsIThreadObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
RuntimeService::WorkerThread::Observer::OnDispatchedEvent(
|
||||
nsIThreadInternal* /*aThread */)
|
||||
{
|
||||
MOZ_CRASH("OnDispatchedEvent() should never be called!");
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RuntimeService::WorkerThread::Observer::OnProcessNextEvent(
|
||||
nsIThreadInternal* /* aThread */,
|
||||
bool aMayWait,
|
||||
uint32_t aRecursionDepth)
|
||||
{
|
||||
using mozilla::ipc::BackgroundChild;
|
||||
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
// If the PBackground child is not created yet, then we must permit
|
||||
// blocking event processing to support SynchronouslyCreatePBackground().
|
||||
// If this occurs then we are spinning on the event queue at the start of
|
||||
// PrimaryWorkerRunnable::Run() and don't want to process the event in
|
||||
// mWorkerPrivate yet.
|
||||
if (aMayWait) {
|
||||
MOZ_ASSERT(aRecursionDepth == 2);
|
||||
MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mWorkerPrivate->OnProcessNextEvent(aRecursionDepth);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
RuntimeService::WorkerThread::Observer::AfterProcessNextEvent(
|
||||
nsIThreadInternal* /* aThread */,
|
||||
uint32_t aRecursionDepth,
|
||||
bool /* aEventWasProcessed */)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
mWorkerPrivate->AfterProcessNextEvent(aRecursionDepth);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(LogViolationDetailsRunnable, nsRunnable)
|
||||
|
||||
NS_IMETHODIMP
|
||||
|
@ -2796,7 +2585,7 @@ WorkerThreadPrimaryRunnable::Run()
|
|||
mThread->SetWorker(mWorkerPrivate);
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
mThread->TestPBackground();
|
||||
TestPBackground();
|
||||
#endif
|
||||
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
@ -2831,7 +2620,7 @@ WorkerThreadPrimaryRunnable::Run()
|
|||
}
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
mThread->TestPBackground();
|
||||
TestPBackground();
|
||||
#endif
|
||||
|
||||
BackgroundChild::CloseForCurrentThread();
|
||||
|
@ -2914,7 +2703,7 @@ WorkerThreadPrimaryRunnable::FinishedRunnable::Run()
|
|||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
nsRefPtr<RuntimeService::WorkerThread> thread;
|
||||
nsRefPtr<WorkerThread> thread;
|
||||
mThread.swap(thread);
|
||||
|
||||
RuntimeService* rts = RuntimeService::GetService();
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
|
||||
#include "nsIObserver.h"
|
||||
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "nsClassHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
@ -20,7 +19,6 @@
|
|||
#include "WorkerPrivate.h"
|
||||
|
||||
class nsIRunnable;
|
||||
class nsIThread;
|
||||
class nsITimer;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
|
@ -28,13 +26,10 @@ BEGIN_WORKERS_NAMESPACE
|
|||
|
||||
class ServiceWorker;
|
||||
class SharedWorker;
|
||||
class WorkerThread;
|
||||
|
||||
class RuntimeService MOZ_FINAL : public nsIObserver
|
||||
{
|
||||
public:
|
||||
class WorkerThread;
|
||||
|
||||
private:
|
||||
struct SharedWorkerInfo
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
|
@ -67,11 +62,7 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
struct IdleThreadInfo
|
||||
{
|
||||
nsRefPtr<WorkerThread> mThread;
|
||||
mozilla::TimeStamp mExpirationTime;
|
||||
};
|
||||
struct IdleThreadInfo;
|
||||
|
||||
struct MatchSharedWorkerInfo
|
||||
{
|
||||
|
|
|
@ -0,0 +1,206 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WorkerThread.h"
|
||||
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "nsIThreadInternal.h"
|
||||
#include "WorkerPrivate.h"
|
||||
#include "WorkerRunnable.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#include "nsThreadManager.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace {
|
||||
|
||||
// The C stack size. We use the same stack size on all platforms for
|
||||
// consistency.
|
||||
const uint32_t kWorkerStackSize = 256 * sizeof(size_t) * 1024;
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
class WorkerThread::Observer MOZ_FINAL
|
||||
: public nsIThreadObserver
|
||||
{
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
public:
|
||||
explicit Observer(WorkerPrivate* aWorkerPrivate)
|
||||
: mWorkerPrivate(aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
aWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
private:
|
||||
~Observer()
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
|
||||
NS_DECL_NSITHREADOBSERVER
|
||||
};
|
||||
|
||||
WorkerThread::WorkerThread()
|
||||
: nsThread(nsThread::NOT_MAIN_THREAD, kWorkerStackSize),
|
||||
mWorkerPrivate(nullptr)
|
||||
#ifdef DEBUG
|
||||
, mAcceptingNonWorkerRunnables(true)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
WorkerThread::~WorkerThread()
|
||||
{
|
||||
}
|
||||
|
||||
// static
|
||||
already_AddRefed<WorkerThread>
|
||||
WorkerThread::Create()
|
||||
{
|
||||
MOZ_ASSERT(nsThreadManager::get());
|
||||
|
||||
nsRefPtr<WorkerThread> thread = new WorkerThread();
|
||||
if (NS_FAILED(thread->Init())) {
|
||||
NS_WARNING("Failed to create new thread!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_SetThreadName(thread, "DOM Worker");
|
||||
|
||||
return thread.forget();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerThread::SetWorker(WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(PR_GetCurrentThread() == mThread);
|
||||
MOZ_ASSERT_IF(aWorkerPrivate, !mWorkerPrivate);
|
||||
MOZ_ASSERT_IF(!aWorkerPrivate, mWorkerPrivate);
|
||||
|
||||
// No need to lock here because mWorkerPrivate is only modified on mThread.
|
||||
|
||||
if (mWorkerPrivate) {
|
||||
MOZ_ASSERT(mObserver);
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(RemoveObserver(mObserver)));
|
||||
|
||||
mObserver = nullptr;
|
||||
mWorkerPrivate->SetThread(nullptr);
|
||||
}
|
||||
|
||||
mWorkerPrivate = aWorkerPrivate;
|
||||
|
||||
if (mWorkerPrivate) {
|
||||
mWorkerPrivate->SetThread(this);
|
||||
|
||||
nsRefPtr<Observer> observer = new Observer(mWorkerPrivate);
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(AddObserver(observer)));
|
||||
|
||||
mObserver.swap(observer);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(WorkerThread, nsThread)
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerThread::Dispatch(nsIRunnable* aRunnable, uint32_t aFlags)
|
||||
{
|
||||
// May be called on any thread!
|
||||
|
||||
#ifdef DEBUG
|
||||
if (PR_GetCurrentThread() == mThread) {
|
||||
MOZ_ASSERT(mWorkerPrivate);
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
}
|
||||
else if (aRunnable && !IsAcceptingNonWorkerRunnables()) {
|
||||
// Only enforce cancelable runnables after we've started the worker loop.
|
||||
nsCOMPtr<nsICancelableRunnable> cancelable = do_QueryInterface(aRunnable);
|
||||
MOZ_ASSERT(cancelable,
|
||||
"Should have been wrapped by the worker's event target!");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Workers only support asynchronous dispatch for now.
|
||||
if (NS_WARN_IF(aFlags != NS_DISPATCH_NORMAL)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsIRunnable* runnableToDispatch;
|
||||
nsRefPtr<WorkerRunnable> workerRunnable;
|
||||
|
||||
if (aRunnable && PR_GetCurrentThread() == mThread) {
|
||||
// No need to lock here because mWorkerPrivate is only modified on mThread.
|
||||
workerRunnable = mWorkerPrivate->MaybeWrapAsWorkerRunnable(aRunnable);
|
||||
runnableToDispatch = workerRunnable;
|
||||
}
|
||||
else {
|
||||
runnableToDispatch = aRunnable;
|
||||
}
|
||||
|
||||
nsresult rv = nsThread::Dispatch(runnableToDispatch, NS_DISPATCH_NORMAL);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(WorkerThread::Observer, nsIThreadObserver)
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerThread::Observer::OnDispatchedEvent(nsIThreadInternal* /* aThread */)
|
||||
{
|
||||
MOZ_CRASH("OnDispatchedEvent() should never be called!");
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerThread::Observer::OnProcessNextEvent(nsIThreadInternal* /* aThread */,
|
||||
bool aMayWait,
|
||||
uint32_t aRecursionDepth)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
// If the PBackground child is not created yet, then we must permit
|
||||
// blocking event processing to support SynchronouslyCreatePBackground().
|
||||
// If this occurs then we are spinning on the event queue at the start of
|
||||
// PrimaryWorkerRunnable::Run() and don't want to process the event in
|
||||
// mWorkerPrivate yet.
|
||||
if (aMayWait) {
|
||||
MOZ_ASSERT(aRecursionDepth == 2);
|
||||
MOZ_ASSERT(!BackgroundChild::GetForCurrentThread());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mWorkerPrivate->OnProcessNextEvent(aRecursionDepth);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
WorkerThread::Observer::AfterProcessNextEvent(nsIThreadInternal* /* aThread */,
|
||||
uint32_t aRecursionDepth,
|
||||
bool /* aEventWasProcessed */)
|
||||
{
|
||||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
mWorkerPrivate->AfterProcessNextEvent(aRecursionDepth);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace workers
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,76 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_workers_WorkerThread_h__
|
||||
#define mozilla_dom_workers_WorkerThread_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsRefPtr.h"
|
||||
#include "nsThread.h"
|
||||
|
||||
class nsIRunnable;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
|
||||
class WorkerPrivate;
|
||||
class WorkerRunnable;
|
||||
|
||||
class WorkerThread MOZ_FINAL
|
||||
: public nsThread
|
||||
{
|
||||
class Observer;
|
||||
|
||||
WorkerPrivate* mWorkerPrivate;
|
||||
nsRefPtr<Observer> mObserver;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Protected by nsThread::mLock.
|
||||
bool mAcceptingNonWorkerRunnables;
|
||||
#endif
|
||||
|
||||
public:
|
||||
static already_AddRefed<WorkerThread>
|
||||
Create();
|
||||
|
||||
void
|
||||
SetWorker(WorkerPrivate* aWorkerPrivate);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_IMETHOD
|
||||
Dispatch(nsIRunnable* aRunnable, uint32_t aFlags) MOZ_OVERRIDE;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool
|
||||
IsAcceptingNonWorkerRunnables()
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
return mAcceptingNonWorkerRunnables;
|
||||
}
|
||||
|
||||
void
|
||||
SetAcceptingNonWorkerRunnables(bool aAcceptingNonWorkerRunnables)
|
||||
{
|
||||
MutexAutoLock lock(mLock);
|
||||
mAcceptingNonWorkerRunnables = aAcceptingNonWorkerRunnables;
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
WorkerThread();
|
||||
|
||||
~WorkerThread();
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_workers_WorkerThread_h__
|
|
@ -72,6 +72,7 @@ UNIFIED_SOURCES += [
|
|||
'WorkerPrivate.cpp',
|
||||
'WorkerRunnable.cpp',
|
||||
'WorkerScope.cpp',
|
||||
'WorkerThread.cpp',
|
||||
'XMLHttpRequest.cpp',
|
||||
'XMLHttpRequestUpload.cpp',
|
||||
]
|
||||
|
|
Загрузка…
Ссылка в новой задаче