| Index: third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
|
| diff --git a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
|
| index 35343b41a748d01cf95f976e26168e470322a0b7..19f24037ed37614081c54bad4e1f452ded5a2c7c 100644
|
| --- a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
|
| +++ b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.cpp
|
| @@ -36,39 +36,181 @@
|
| #include "core/timing/WorkerGlobalScopePerformance.h"
|
| #include "core/workers/WorkerGlobalScope.h"
|
| #include "core/workers/WorkerLoaderProxy.h"
|
| -#include "core/workers/WorkerThread.h"
|
| #include "platform/CrossThreadFunctional.h"
|
| -#include "platform/WaitableEvent.h"
|
| #include "platform/heap/SafePoint.h"
|
| #include "platform/network/ResourceError.h"
|
| #include "platform/network/ResourceRequest.h"
|
| #include "platform/network/ResourceResponse.h"
|
| #include "platform/network/ResourceTimingInfo.h"
|
| #include "platform/weborigin/SecurityPolicy.h"
|
| -#include "public/platform/Platform.h"
|
| -#include "wtf/PtrUtil.h"
|
| -#include "wtf/Vector.h"
|
| #include "wtf/debug/Alias.h"
|
| #include <memory>
|
|
|
| namespace blink {
|
|
|
| -static std::unique_ptr<Vector<char>> createVectorFromMemoryRegion(const char* data, unsigned dataLength)
|
| +namespace {
|
| +
|
| +std::unique_ptr<Vector<char>> createVectorFromMemoryRegion(const char* data, unsigned dataLength)
|
| {
|
| std::unique_ptr<Vector<char>> buffer = wrapUnique(new Vector<char>(dataLength));
|
| memcpy(buffer->data(), data, dataLength);
|
| return buffer;
|
| }
|
|
|
| -WorkerThreadableLoader::WorkerThreadableLoader(WorkerGlobalScope& workerGlobalScope, ThreadableLoaderClient* client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions, BlockingBehavior blockingBehavior)
|
| +} // namespace
|
| +
|
| +class WorkerThreadableLoader::AsyncTaskForwarder final : public WorkerThreadableLoader::TaskForwarder {
|
| +public:
|
| + explicit AsyncTaskForwarder(PassRefPtr<WorkerLoaderProxy> loaderProxy)
|
| + : m_loaderProxy(loaderProxy)
|
| + {
|
| + DCHECK(isMainThread());
|
| + }
|
| + ~AsyncTaskForwarder() override
|
| + {
|
| + DCHECK(isMainThread());
|
| + }
|
| +
|
| + void forwardTask(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task) override
|
| + {
|
| + DCHECK(isMainThread());
|
| + m_loaderProxy->postTaskToWorkerGlobalScope(location, std::move(task));
|
| + }
|
| + void forwardTaskWithDoneSignal(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task) override
|
| + {
|
| + DCHECK(isMainThread());
|
| + m_loaderProxy->postTaskToWorkerGlobalScope(location, std::move(task));
|
| + }
|
| + void abort() override
|
| + {
|
| + DCHECK(isMainThread());
|
| + }
|
| +
|
| +private:
|
| + RefPtr<WorkerLoaderProxy> m_loaderProxy;
|
| +};
|
| +
|
| +struct WorkerThreadableLoader::TaskWithLocation final {
|
| + TaskWithLocation(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task)
|
| + : m_location(location)
|
| + , m_task(std::move(task))
|
| + {
|
| + }
|
| + TaskWithLocation(TaskWithLocation&& task)
|
| + : TaskWithLocation(task.m_location, std::move(task.m_task))
|
| + {
|
| + }
|
| + ~TaskWithLocation() = default;
|
| +
|
| + WebTraceLocation m_location;
|
| + std::unique_ptr<ExecutionContextTask> m_task;
|
| +};
|
| +
|
| +// Observing functions and wait() need to be called on the worker thread.
|
| +// Setting functions and signal() need to be called on the main thread.
|
| +// All observing functions must be called after wait() returns, and all
|
| +// setting functions must be called before signal() is called.
|
| +class WorkerThreadableLoader::WaitableEventWithTasks final : public ThreadSafeRefCounted<WaitableEventWithTasks> {
|
| +public:
|
| + static PassRefPtr<WaitableEventWithTasks> create() { return adoptRef(new WaitableEventWithTasks); }
|
| +
|
| + void signal()
|
| + {
|
| + DCHECK(isMainThread());
|
| + CHECK(!m_isSignalCalled);
|
| + m_isSignalCalled = true;
|
| + m_event.signal();
|
| + }
|
| + void wait()
|
| + {
|
| + DCHECK(!isMainThread());
|
| + CHECK(!m_isWaitDone);
|
| + m_event.wait();
|
| + m_isWaitDone = true;
|
| + }
|
| +
|
| + // Observing functions
|
| + bool isAborted() const
|
| + {
|
| + DCHECK(!isMainThread());
|
| + CHECK(m_isWaitDone);
|
| + return m_isAborted;
|
| + }
|
| + Vector<TaskWithLocation> take()
|
| + {
|
| + DCHECK(!isMainThread());
|
| + CHECK(m_isWaitDone);
|
| + return std::move(m_tasks);
|
| + }
|
| +
|
| + // Setting functions
|
| + void append(TaskWithLocation task)
|
| + {
|
| + DCHECK(isMainThread());
|
| + CHECK(!m_isSignalCalled);
|
| + m_tasks.append(std::move(task));
|
| + }
|
| + void setIsAborted()
|
| + {
|
| + DCHECK(isMainThread());
|
| + CHECK(!m_isSignalCalled);
|
| + m_isAborted = true;
|
| + }
|
| +
|
| +private:
|
| + WaitableEventWithTasks() {}
|
| +
|
| + WaitableEvent m_event;
|
| + Vector<TaskWithLocation> m_tasks;
|
| + bool m_isAborted = false;
|
| + bool m_isSignalCalled = false;
|
| + bool m_isWaitDone = false;
|
| +};
|
| +
|
| +class WorkerThreadableLoader::SyncTaskForwarder final : public WorkerThreadableLoader::TaskForwarder {
|
| +public:
|
| + explicit SyncTaskForwarder(PassRefPtr<WaitableEventWithTasks> eventWithTasks)
|
| + : m_eventWithTasks(eventWithTasks)
|
| + {
|
| + DCHECK(isMainThread());
|
| + }
|
| + ~SyncTaskForwarder() override
|
| + {
|
| + DCHECK(isMainThread());
|
| + }
|
| +
|
| + void forwardTask(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task) override
|
| + {
|
| + DCHECK(isMainThread());
|
| + m_eventWithTasks->append(TaskWithLocation(location, std::move(task)));
|
| + }
|
| + void forwardTaskWithDoneSignal(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task) override
|
| + {
|
| + DCHECK(isMainThread());
|
| + m_eventWithTasks->append(TaskWithLocation(location, std::move(task)));
|
| + m_eventWithTasks->signal();
|
| + }
|
| + void abort() override
|
| + {
|
| + DCHECK(isMainThread());
|
| + m_eventWithTasks->setIsAborted();
|
| + m_eventWithTasks->signal();
|
| + }
|
| +
|
| +private:
|
| + RefPtr<WaitableEventWithTasks> m_eventWithTasks;
|
| +};
|
| +
|
| +WorkerThreadableLoader::WorkerThreadableLoader(
|
| + WorkerGlobalScope& workerGlobalScope,
|
| + ThreadableLoaderClient* client,
|
| + const ThreadableLoaderOptions& options,
|
| + const ResourceLoaderOptions& resourceLoaderOptions,
|
| + BlockingBehavior blockingBehavior)
|
| : m_workerGlobalScope(&workerGlobalScope)
|
| , m_workerClientWrapper(new ThreadableLoaderClientWrapper(workerGlobalScope, client))
|
| + , m_bridge(new Bridge(m_workerClientWrapper, workerGlobalScope.thread()->workerLoaderProxy(), options, resourceLoaderOptions, blockingBehavior))
|
| {
|
| - if (blockingBehavior == LoadAsynchronously) {
|
| - m_bridge = new MainThreadAsyncBridge(workerGlobalScope, m_workerClientWrapper, options, resourceLoaderOptions);
|
| - } else {
|
| - m_bridge = new MainThreadSyncBridge(workerGlobalScope, m_workerClientWrapper, options, resourceLoaderOptions);
|
| - }
|
| }
|
|
|
| void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope& workerGlobalScope, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions)
|
| @@ -81,7 +223,6 @@ WorkerThreadableLoader::~WorkerThreadableLoader()
|
| {
|
| DCHECK(m_workerClientWrapper->done());
|
| m_bridge->destroy();
|
| - m_bridge = nullptr;
|
| }
|
|
|
| void WorkerThreadableLoader::start(const ResourceRequest& request)
|
| @@ -94,291 +235,319 @@ void WorkerThreadableLoader::start(const ResourceRequest& request)
|
|
|
| void WorkerThreadableLoader::overrideTimeout(unsigned long timeoutMilliseconds)
|
| {
|
| - ASSERT(m_bridge);
|
| m_bridge->overrideTimeout(timeoutMilliseconds);
|
| }
|
|
|
| void WorkerThreadableLoader::cancel()
|
| {
|
| - ASSERT(m_bridge);
|
| m_bridge->cancel();
|
| }
|
|
|
| -WorkerThreadableLoader::MainThreadBridgeBase::MainThreadBridgeBase(
|
| - ThreadableLoaderClientWrapper* workerClientWrapper,
|
| - PassRefPtr<WorkerLoaderProxy> loaderProxy)
|
| - : m_workerClientWrapper(workerClientWrapper)
|
| +WorkerThreadableLoader::Bridge::Bridge(
|
| + ThreadableLoaderClientWrapper* clientWrapper,
|
| + PassRefPtr<WorkerLoaderProxy> loaderProxy,
|
| + const ThreadableLoaderOptions& threadableLoaderOptions,
|
| + const ResourceLoaderOptions& resourceLoaderOptions,
|
| + BlockingBehavior blockingBehavior)
|
| + : m_clientWrapper(clientWrapper)
|
| , m_loaderProxy(loaderProxy)
|
| + , m_threadableLoaderOptions(threadableLoaderOptions)
|
| + , m_resourceLoaderOptions(resourceLoaderOptions)
|
| + , m_blockingBehavior(blockingBehavior)
|
| {
|
| - ASSERT(m_workerClientWrapper.get());
|
| - ASSERT(m_loaderProxy.get());
|
| + DCHECK(!isMainThread());
|
| }
|
|
|
| -WorkerThreadableLoader::MainThreadBridgeBase::~MainThreadBridgeBase()
|
| +WorkerThreadableLoader::Bridge::~Bridge()
|
| {
|
| + DCHECK(!isMainThread());
|
| + DCHECK(!m_peer);
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadCreateLoader(ThreadableLoaderOptions options, ResourceLoaderOptions resourceLoaderOptions, ExecutionContext* context)
|
| +void WorkerThreadableLoader::Bridge::start(const ResourceRequest& request, const WorkerGlobalScope& workerGlobalScope)
|
| {
|
| - ASSERT(isMainThread());
|
| - Document* document = toDocument(context);
|
| + DCHECK(!isMainThread());
|
| + RefPtr<WaitableEventWithTasks> eventWithTasks;
|
| + if (m_blockingBehavior == LoadSynchronously)
|
| + eventWithTasks = WaitableEventWithTasks::create();
|
|
|
| - resourceLoaderOptions.requestInitiatorContext = WorkerContext;
|
| - m_mainThreadLoader = DocumentThreadableLoader::create(*document, this, options, resourceLoaderOptions);
|
| - ASSERT(m_mainThreadLoader);
|
| -}
|
| + m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(
|
| + &Peer::createAndStart,
|
| + wrapCrossThreadPersistent(this),
|
| + m_loaderProxy,
|
| + wrapCrossThreadPersistent(workerGlobalScope.thread()->getWorkerThreadLifecycleContext()),
|
| + request,
|
| + m_threadableLoaderOptions,
|
| + m_resourceLoaderOptions,
|
| + eventWithTasks));
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadStart(std::unique_ptr<CrossThreadResourceRequestData> requestData)
|
| -{
|
| - ASSERT(isMainThread());
|
| - ASSERT(m_mainThreadLoader);
|
| - m_mainThreadLoader->start(ResourceRequest(requestData.get()));
|
| -}
|
| + if (m_blockingBehavior == LoadAsynchronously)
|
| + return;
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::createLoaderInMainThread(const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions)
|
| -{
|
| - m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&MainThreadBridgeBase::mainThreadCreateLoader, crossThreadUnretained(this), options, resourceLoaderOptions));
|
| -}
|
| + {
|
| + SafePointScope scope(BlinkGC::HeapPointersOnStack);
|
| + eventWithTasks->wait();
|
| + }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::startInMainThread(const ResourceRequest& request, const WorkerGlobalScope& workerGlobalScope)
|
| -{
|
| - loaderProxy()->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&MainThreadBridgeBase::mainThreadStart, crossThreadUnretained(this), request));
|
| -}
|
| + if (eventWithTasks->isAborted()) {
|
| + // This thread is going to terminate.
|
| + cancel();
|
| + return;
|
| + }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadDestroy(ExecutionContext* context)
|
| -{
|
| - ASSERT(isMainThread());
|
| - ASSERT_UNUSED(context, context->isDocument());
|
| - delete this;
|
| + for (const auto& task : eventWithTasks->take()) {
|
| + // Store the program counter where the task is posted from, and alias
|
| + // it to ensure it is stored in the crash dump.
|
| + const void* programCounter = task.m_location.program_counter();
|
| + WTF::debug::alias(&programCounter);
|
| +
|
| + // m_clientTask contains only CallClosureTasks. So, it's ok to pass
|
| + // the nullptr.
|
| + task.m_task->performTask(nullptr);
|
| + }
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::destroy()
|
| +void WorkerThreadableLoader::Bridge::overrideTimeout(unsigned long timeoutMilliseconds)
|
| {
|
| - // Ensure that no more client callbacks are done in the worker context's
|
| - // thread.
|
| - // ThreadableLoaderClientWrapper is an on-heap class and this function can
|
| - // be called in the finalization step but it is safe because
|
| - // m_workerClientWrapper is a CrossThreadPersistent.
|
| - m_workerClientWrapper->clearClient();
|
| -
|
| - // "delete this" and m_mainThreadLoader::deref() on the worker object's
|
| - // thread.
|
| - m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&MainThreadBridgeBase::mainThreadDestroy, crossThreadUnretained(this)));
|
| + DCHECK(!isMainThread());
|
| + if (!m_peer)
|
| + return;
|
| + m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&Peer::overrideTimeout, m_peer, timeoutMilliseconds));
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadOverrideTimeout(unsigned long timeoutMilliseconds, ExecutionContext* context)
|
| +void WorkerThreadableLoader::Bridge::cancel()
|
| {
|
| - ASSERT(isMainThread());
|
| - ASSERT_UNUSED(context, context->isDocument());
|
| + DCHECK(!isMainThread());
|
| + cancelPeer();
|
|
|
| - if (!m_mainThreadLoader)
|
| + if (m_clientWrapper->done())
|
| return;
|
| - m_mainThreadLoader->overrideTimeout(timeoutMilliseconds);
|
| + // If the client hasn't reached a termination state, then transition it
|
| + // by sending a cancellation error.
|
| + // Note: no more client callbacks will be done after this method -- the
|
| + // clearClient() call ensures that.
|
| + ResourceError error(String(), 0, String(), String());
|
| + error.setIsCancellation(true);
|
| + m_clientWrapper->didFail(error);
|
| + m_clientWrapper->clearClient();
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::overrideTimeout(unsigned long timeoutMilliseconds)
|
| +void WorkerThreadableLoader::Bridge::destroy()
|
| {
|
| - m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&MainThreadBridgeBase::mainThreadOverrideTimeout, crossThreadUnretained(this), timeoutMilliseconds));
|
| + DCHECK(!isMainThread());
|
| + cancelPeer();
|
| + m_clientWrapper->clearClient();
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadCancel(ExecutionContext* context)
|
| +void WorkerThreadableLoader::Bridge::didStart(Peer* peer)
|
| {
|
| - ASSERT(isMainThread());
|
| - ASSERT_UNUSED(context, context->isDocument());
|
| -
|
| - if (!m_mainThreadLoader)
|
| + DCHECK(!isMainThread());
|
| + DCHECK(!m_peer);
|
| + DCHECK(peer);
|
| + if (m_clientWrapper->done()) {
|
| + // The loading is already cancelled.
|
| return;
|
| - m_mainThreadLoader->cancel();
|
| - m_mainThreadLoader = nullptr;
|
| -}
|
| -
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::cancel()
|
| -{
|
| - m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&MainThreadBridgeBase::mainThreadCancel, crossThreadUnretained(this)));
|
| - ThreadableLoaderClientWrapper* clientWrapper = m_workerClientWrapper;
|
| - if (!clientWrapper->done()) {
|
| - // If the client hasn't reached a termination state, then transition it
|
| - // by sending a cancellation error.
|
| - // Note: no more client callbacks will be done after this method -- the
|
| - // m_workerClientWrapper->clearClient() call ensures that.
|
| - ResourceError error(String(), 0, String(), String());
|
| - error.setIsCancellation(true);
|
| - clientWrapper->didFail(error);
|
| }
|
| - // |this| might be already destructed here because didFail() might
|
| - // clear a reference to ThreadableLoader, which might destruct
|
| - // WorkerThreadableLoader and then MainThreadBridge.
|
| - // Therefore we call clearClient() directly, rather than calling
|
| - // this->m_workerClientWrapper->clearClient().
|
| - clientWrapper->clearClient();
|
| -}
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
|
| -{
|
| - forwardTaskToWorker(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didSendData, m_workerClientWrapper, bytesSent, totalBytesToBeSent));
|
| + m_peer = peer;
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::didReceiveResponse(unsigned long identifier, const ResourceResponse& response, std::unique_ptr<WebDataConsumerHandle> handle)
|
| +DEFINE_TRACE(WorkerThreadableLoader::Bridge)
|
| {
|
| - forwardTaskToWorker(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didReceiveResponse, m_workerClientWrapper, identifier, response, passed(std::move(handle))));
|
| + visitor->trace(m_clientWrapper);
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::didReceiveData(const char* data, unsigned dataLength)
|
| +void WorkerThreadableLoader::Bridge::cancelPeer()
|
| {
|
| - forwardTaskToWorker(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didReceiveData, m_workerClientWrapper, passed(createVectorFromMemoryRegion(data, dataLength))));
|
| + DCHECK(!isMainThread());
|
| + if (!m_peer)
|
| + return;
|
| + m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&Peer::cancel, m_peer));
|
| + m_peer = nullptr;
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::didDownloadData(int dataLength)
|
| -{
|
| - forwardTaskToWorker(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didDownloadData, m_workerClientWrapper, dataLength));
|
| +void WorkerThreadableLoader::Peer::createAndStart(
|
| + Bridge* bridge,
|
| + PassRefPtr<WorkerLoaderProxy> passLoaderProxy,
|
| + WorkerThreadLifecycleContext* workerThreadLifecycleContext,
|
| + std::unique_ptr<CrossThreadResourceRequestData> request,
|
| + const ThreadableLoaderOptions& options,
|
| + const ResourceLoaderOptions& resourceLoaderOptions,
|
| + PassRefPtr<WaitableEventWithTasks> eventWithTasks,
|
| + ExecutionContext* executionContext)
|
| +{
|
| + DCHECK(isMainThread());
|
| + TaskForwarder* forwarder;
|
| + RefPtr<WorkerLoaderProxy> loaderProxy = passLoaderProxy;
|
| + if (eventWithTasks)
|
| + forwarder = new SyncTaskForwarder(eventWithTasks);
|
| + else
|
| + forwarder = new AsyncTaskForwarder(loaderProxy);
|
| +
|
| + Peer* peer = new Peer(forwarder, workerThreadLifecycleContext);
|
| + if (peer->wasContextDestroyedBeforeObserverCreation()) {
|
| + // The thread is already terminating.
|
| + forwarder->abort();
|
| + peer->m_forwarder = nullptr;
|
| + return;
|
| + }
|
| + peer->m_clientWrapper = bridge->clientWrapper();
|
| + peer->start(*toDocument(executionContext), std::move(request), options, resourceLoaderOptions);
|
| + forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&Bridge::didStart, wrapCrossThreadPersistent(bridge), wrapCrossThreadPersistent(peer)));
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::didReceiveCachedMetadata(const char* data, int dataLength)
|
| +WorkerThreadableLoader::Peer::~Peer()
|
| {
|
| - forwardTaskToWorker(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didReceiveCachedMetadata, m_workerClientWrapper, passed(createVectorFromMemoryRegion(data, dataLength))));
|
| + DCHECK(isMainThread());
|
| + DCHECK(!m_mainThreadLoader);
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::didFinishLoading(unsigned long identifier, double finishTime)
|
| +void WorkerThreadableLoader::Peer::overrideTimeout(unsigned long timeoutMilliseconds)
|
| {
|
| - forwardTaskToWorkerOnLoaderDone(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didFinishLoading, m_workerClientWrapper, identifier, finishTime));
|
| + DCHECK(isMainThread());
|
| + if (!m_mainThreadLoader)
|
| + return;
|
| + m_mainThreadLoader->overrideTimeout(timeoutMilliseconds);
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::didFail(const ResourceError& error)
|
| +void WorkerThreadableLoader::Peer::cancel()
|
| {
|
| - forwardTaskToWorkerOnLoaderDone(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didFail, m_workerClientWrapper, error));
|
| + DCHECK(isMainThread());
|
| + if (!m_mainThreadLoader)
|
| + return;
|
| + m_mainThreadLoader->cancel();
|
| + m_mainThreadLoader = nullptr;
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::didFailAccessControlCheck(const ResourceError& error)
|
| +void WorkerThreadableLoader::Peer::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
|
| {
|
| - forwardTaskToWorkerOnLoaderDone(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didFailAccessControlCheck, m_workerClientWrapper, error));
|
| + DCHECK(isMainThread());
|
| + CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clientWrapper.get();
|
| + if (!clientWrapper || !m_forwarder)
|
| + return;
|
| + m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didSendData, clientWrapper, bytesSent, totalBytesToBeSent));
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::didFailRedirectCheck()
|
| +void WorkerThreadableLoader::Peer::didReceiveResponse(unsigned long identifier, const ResourceResponse& response, std::unique_ptr<WebDataConsumerHandle> handle)
|
| {
|
| - forwardTaskToWorkerOnLoaderDone(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didFailRedirectCheck, m_workerClientWrapper));
|
| + DCHECK(isMainThread());
|
| + CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clientWrapper.get();
|
| + if (!clientWrapper || !m_forwarder)
|
| + return;
|
| + m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didReceiveResponse, clientWrapper, identifier, response, passed(std::move(handle))));
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadBridgeBase::didReceiveResourceTiming(const ResourceTimingInfo& info)
|
| +void WorkerThreadableLoader::Peer::didReceiveData(const char* data, unsigned dataLength)
|
| {
|
| - forwardTaskToWorker(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didReceiveResourceTiming, m_workerClientWrapper, info));
|
| + DCHECK(isMainThread());
|
| + CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clientWrapper.get();
|
| + if (!clientWrapper || !m_forwarder)
|
| + return;
|
| + m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didReceiveData, clientWrapper, passed(createVectorFromMemoryRegion(data, dataLength))));
|
| }
|
|
|
| -WorkerThreadableLoader::MainThreadAsyncBridge::MainThreadAsyncBridge(
|
| - WorkerGlobalScope& workerGlobalScope,
|
| - ThreadableLoaderClientWrapper* workerClientWrapper,
|
| - const ThreadableLoaderOptions& options,
|
| - const ResourceLoaderOptions& resourceLoaderOptions)
|
| - : MainThreadBridgeBase(workerClientWrapper, workerGlobalScope.thread()->workerLoaderProxy())
|
| +void WorkerThreadableLoader::Peer::didDownloadData(int dataLength)
|
| {
|
| - createLoaderInMainThread(options, resourceLoaderOptions);
|
| + DCHECK(isMainThread());
|
| + CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clientWrapper.get();
|
| + if (!clientWrapper || !m_forwarder)
|
| + return;
|
| + m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didDownloadData, clientWrapper, dataLength));
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadAsyncBridge::start(const ResourceRequest& request, const WorkerGlobalScope& workerGlobalScope)
|
| +void WorkerThreadableLoader::Peer::didReceiveCachedMetadata(const char* data, int dataLength)
|
| {
|
| - startInMainThread(request, workerGlobalScope);
|
| + DCHECK(isMainThread());
|
| + CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clientWrapper.get();
|
| + if (!clientWrapper || !m_forwarder)
|
| + return;
|
| + m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didReceiveCachedMetadata, clientWrapper, passed(createVectorFromMemoryRegion(data, dataLength))));
|
| }
|
|
|
| -WorkerThreadableLoader::MainThreadAsyncBridge::~MainThreadAsyncBridge()
|
| +void WorkerThreadableLoader::Peer::didFinishLoading(unsigned long identifier, double finishTime)
|
| {
|
| + DCHECK(isMainThread());
|
| + CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clientWrapper.get();
|
| + if (!clientWrapper || !m_forwarder)
|
| + return;
|
| + m_forwarder->forwardTaskWithDoneSignal(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didFinishLoading, clientWrapper, identifier, finishTime));
|
| + m_forwarder = nullptr;
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadAsyncBridge::forwardTaskToWorker(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task)
|
| +void WorkerThreadableLoader::Peer::didFail(const ResourceError& error)
|
| {
|
| - loaderProxy()->postTaskToWorkerGlobalScope(location, std::move(task));
|
| + DCHECK(isMainThread());
|
| + CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clientWrapper.get();
|
| + if (!clientWrapper || !m_forwarder)
|
| + return;
|
| + m_forwarder->forwardTaskWithDoneSignal(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didFail, clientWrapper, error));
|
| + m_forwarder = nullptr;
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadAsyncBridge::forwardTaskToWorkerOnLoaderDone(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task)
|
| +void WorkerThreadableLoader::Peer::didFailAccessControlCheck(const ResourceError& error)
|
| {
|
| - loaderProxy()->postTaskToWorkerGlobalScope(location, std::move(task));
|
| + DCHECK(isMainThread());
|
| + CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clientWrapper.get();
|
| + if (!clientWrapper || !m_forwarder)
|
| + return;
|
| + m_forwarder->forwardTaskWithDoneSignal(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didFailAccessControlCheck, clientWrapper, error));
|
| + m_forwarder = nullptr;
|
| }
|
|
|
| -WorkerThreadableLoader::MainThreadSyncBridge::MainThreadSyncBridge(
|
| - WorkerGlobalScope& workerGlobalScope,
|
| - ThreadableLoaderClientWrapper* workerClientWrapper,
|
| - const ThreadableLoaderOptions& options,
|
| - const ResourceLoaderOptions& resourceLoaderOptions)
|
| - : MainThreadBridgeBase(workerClientWrapper, workerGlobalScope.thread()->workerLoaderProxy())
|
| - , m_done(false)
|
| +void WorkerThreadableLoader::Peer::didFailRedirectCheck()
|
| {
|
| - createLoaderInMainThread(options, resourceLoaderOptions);
|
| + DCHECK(isMainThread());
|
| + CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clientWrapper.get();
|
| + if (!clientWrapper || !m_forwarder)
|
| + return;
|
| + m_forwarder->forwardTaskWithDoneSignal(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didFailRedirectCheck, clientWrapper));
|
| + m_forwarder = nullptr;
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadSyncBridge::start(const ResourceRequest& request, const WorkerGlobalScope& workerGlobalScope)
|
| +void WorkerThreadableLoader::Peer::didReceiveResourceTiming(const ResourceTimingInfo& info)
|
| {
|
| - WaitableEvent* terminationEvent = workerGlobalScope.thread()->terminationEvent();
|
| - m_loaderDoneEvent = wrapUnique(new WaitableEvent());
|
| -
|
| - startInMainThread(request, workerGlobalScope);
|
| -
|
| - size_t signaledIndex;
|
| - {
|
| - Vector<WaitableEvent*> events;
|
| - // Order is important; indicies are used later.
|
| - events.append(terminationEvent);
|
| - events.append(m_loaderDoneEvent.get());
|
| -
|
| - SafePointScope scope(BlinkGC::HeapPointersOnStack);
|
| - signaledIndex = WaitableEvent::waitMultiple(events);
|
| - }
|
| - // |signaledIndex| is 0; which is terminationEvent.
|
| - if (signaledIndex == 0) {
|
| - cancel();
|
| + DCHECK(isMainThread());
|
| + CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clientWrapper.get();
|
| + if (!clientWrapper || !m_forwarder)
|
| return;
|
| - }
|
| -
|
| - // The following code must be run only after |m_loaderDoneEvent| is
|
| - // signalled.
|
| -
|
| - Vector<ClientTask> tasks;
|
| - {
|
| - MutexLocker lock(m_lock);
|
| - ASSERT(m_done);
|
| - m_clientTasks.swap(tasks);
|
| - }
|
| - for (const auto& task : tasks) {
|
| - // Store the program counter where the task is posted from, and alias
|
| - // it to ensure it is stored in the crash dump.
|
| - const void* programCounter = task.m_location.program_counter();
|
| - WTF::debug::alias(&programCounter);
|
| + m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoaderClientWrapper::didReceiveResourceTiming, clientWrapper, info));
|
| +}
|
|
|
| - // m_clientTask contains only CallClosureTasks. So, it's ok to pass
|
| - // the nullptr.
|
| - task.m_task->performTask(nullptr);
|
| +void WorkerThreadableLoader::Peer::contextDestroyed()
|
| +{
|
| + DCHECK(isMainThread());
|
| + if (m_forwarder) {
|
| + m_forwarder->abort();
|
| + m_forwarder = nullptr;
|
| }
|
| + m_clientWrapper = nullptr;
|
| + cancel();
|
| }
|
|
|
| -WorkerThreadableLoader::MainThreadSyncBridge::ClientTask::ClientTask(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task)
|
| - : m_location(location)
|
| - , m_task(std::move(task)) {}
|
| -
|
| -WorkerThreadableLoader::MainThreadSyncBridge::ClientTask::~ClientTask() = default;
|
| -WorkerThreadableLoader::MainThreadSyncBridge::ClientTask::ClientTask(ClientTask&&) = default;
|
| -
|
| -WorkerThreadableLoader::MainThreadSyncBridge::~MainThreadSyncBridge()
|
| +DEFINE_TRACE(WorkerThreadableLoader::Peer)
|
| {
|
| - ASSERT(isMainThread());
|
| + visitor->trace(m_forwarder);
|
| + WorkerThreadLifecycleObserver::trace(visitor);
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadSyncBridge::forwardTaskToWorker(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task)
|
| +WorkerThreadableLoader::Peer::Peer(TaskForwarder* forwarder, WorkerThreadLifecycleContext* context)
|
| + : WorkerThreadLifecycleObserver(context)
|
| + , m_forwarder(forwarder)
|
| {
|
| - ASSERT(isMainThread());
|
| -
|
| - MutexLocker lock(m_lock);
|
| - RELEASE_ASSERT(!m_done);
|
| -
|
| - m_clientTasks.append(ClientTask(location, std::move(task)));
|
| + DCHECK(isMainThread());
|
| }
|
|
|
| -void WorkerThreadableLoader::MainThreadSyncBridge::forwardTaskToWorkerOnLoaderDone(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task)
|
| +void WorkerThreadableLoader::Peer::start(
|
| + Document& document,
|
| + std::unique_ptr<CrossThreadResourceRequestData> request,
|
| + const ThreadableLoaderOptions& options,
|
| + const ResourceLoaderOptions& originalResourceLoaderOptions)
|
| {
|
| - ASSERT(isMainThread());
|
| -
|
| - MutexLocker lock(m_lock);
|
| - RELEASE_ASSERT(!m_done);
|
| -
|
| - m_clientTasks.append(ClientTask(location, std::move(task)));
|
| - m_done = true;
|
| - m_loaderDoneEvent->signal();
|
| + DCHECK(isMainThread());
|
| + ResourceLoaderOptions resourceLoaderOptions = originalResourceLoaderOptions;
|
| + resourceLoaderOptions.requestInitiatorContext = WorkerContext;
|
| + m_mainThreadLoader = DocumentThreadableLoader::create(document, this, options, resourceLoaderOptions);
|
| + m_mainThreadLoader->start(ResourceRequest(request.get()));
|
| }
|
|
|
| } // namespace blink
|
|
|