Chromium Code Reviews| Index: third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h |
| diff --git a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h |
| index efbb0748bbd3cdecbec230493d8d58a6300e663c..e1995571febdcca691852b946c9098cbde315231 100644 |
| --- a/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h |
| +++ b/third_party/WebKit/Source/core/loader/WorkerThreadableLoader.h |
| @@ -31,28 +31,27 @@ |
| #ifndef WorkerThreadableLoader_h |
| #define WorkerThreadableLoader_h |
| +#include "core/dom/ExecutionContextTask.h" |
| #include "core/loader/ThreadableLoader.h" |
| #include "core/loader/ThreadableLoaderClient.h" |
| #include "core/loader/ThreadableLoaderClientWrapper.h" |
| +#include "core/workers/WorkerThread.h" |
| +#include "core/workers/WorkerThreadLifecycleObserver.h" |
| +#include "platform/WaitableEvent.h" |
| #include "platform/heap/Handle.h" |
| -#include "platform/weborigin/Referrer.h" |
| -#include "wtf/Functional.h" |
| #include "wtf/PassRefPtr.h" |
| #include "wtf/PtrUtil.h" |
| #include "wtf/RefPtr.h" |
| #include "wtf/Threading.h" |
| -#include "wtf/ThreadingPrimitives.h" |
| #include "wtf/Vector.h" |
| #include "wtf/text/WTFString.h" |
| #include <memory> |
| namespace blink { |
| -class ExecutionContextTask; |
| class ResourceError; |
| class ResourceRequest; |
| class ResourceResponse; |
| -class WaitableEvent; |
| class WorkerGlobalScope; |
| class WorkerLoaderProxy; |
| struct CrossThreadResourceRequestData; |
| @@ -69,9 +68,7 @@ public: |
| ~WorkerThreadableLoader() override; |
| void start(const ResourceRequest&) override; |
| - |
| void overrideTimeout(unsigned long timeout) override; |
| - |
| void cancel() override; |
| private: |
| @@ -80,122 +77,153 @@ private: |
| LoadAsynchronously |
| }; |
| - // Creates a loader on the main thread and bridges communication between |
| - // the main thread and the worker context's thread where WorkerThreadableLoader runs. |
| - // |
| - // Regarding the bridge and lifetimes of items used in callbacks, there are a few cases: |
| - // |
| - // all cases. All tasks posted from the worker context's thread are ok because |
| - // the last task posted always is "mainThreadDestroy", so MainThreadBridge is |
| - // around for all tasks that use it on the main thread. |
| - // |
| - // case 1. worker.terminate is called. |
| - // In this case, no more tasks are posted from the worker object's thread to the worker |
| - // context's thread -- WorkerGlobalScopeProxy implementation enforces this. |
| - // |
| - // case 2. xhr gets aborted and the worker context continues running. |
| - // The ThreadableLoaderClientWrapper has the underlying client cleared, so no more calls |
| - // go through it. All tasks posted from the worker object's thread to the worker context's |
| - // thread do "ThreadableLoaderClientWrapper::ref" (automatically inside of the cross thread copy |
| - // done in createCrossThreadTask), so the ThreadableLoaderClientWrapper instance is there until all |
| - // tasks are executed. |
| - class MainThreadBridgeBase : public ThreadableLoaderClient { |
| + // A TaskForwarder forwards an ExecutionContextTask to the worker thread. |
| + class TaskForwarder : public GarbageCollectedFinalized<TaskForwarder> { |
| public: |
| - // All executed on the worker context's thread. |
| - MainThreadBridgeBase(ThreadableLoaderClientWrapper*, PassRefPtr<WorkerLoaderProxy>); |
| - virtual void start(const ResourceRequest&, const WorkerGlobalScope&) = 0; |
| - void overrideTimeout(unsigned long timeoutMilliseconds); |
| - void cancel(); |
| - void destroy(); |
| + virtual ~TaskForwarder() {} |
| + virtual void forwardTask(std::unique_ptr<ExecutionContextTask>) = 0; |
| + virtual void forwardTaskWithDoneSignal(std::unique_ptr<ExecutionContextTask>) = 0; |
| + virtual void abort() = 0; |
| - // All executed on the main thread. |
| - void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) final; |
| - void didReceiveResponse(unsigned long identifier, const ResourceResponse&, std::unique_ptr<WebDataConsumerHandle>) final; |
| - void didReceiveData(const char*, unsigned dataLength) final; |
| - void didDownloadData(int dataLength) final; |
| - void didReceiveCachedMetadata(const char*, int dataLength) final; |
| - void didFinishLoading(unsigned long identifier, double finishTime) final; |
| - void didFail(const ResourceError&) final; |
| - void didFailAccessControlCheck(const ResourceError&) final; |
| - void didFailRedirectCheck() final; |
| - void didReceiveResourceTiming(const ResourceTimingInfo&) final; |
| - |
| - protected: |
| - ~MainThreadBridgeBase() override; |
| - |
| - // Posts a task to the main thread to run mainThreadCreateLoader(). |
| - void createLoaderInMainThread(const ThreadableLoaderOptions&, const ResourceLoaderOptions&); |
| - // Posts a task to the main thread to run mainThreadStart(); |
| - void startInMainThread(const ResourceRequest&, const WorkerGlobalScope&); |
| - |
| - WorkerLoaderProxy* loaderProxy() |
| - { |
| - return m_loaderProxy.get(); |
| - } |
| + DEFINE_INLINE_VIRTUAL_TRACE() {} |
| + }; |
| - private: |
| - // The following methods are overridden by the subclasses to implement |
| - // code to forward did.* method invocations to the worker context's |
| - // thread which is specialized for sync and async case respectively. |
| - virtual void forwardTaskToWorker(std::unique_ptr<ExecutionContextTask>) = 0; |
| - virtual void forwardTaskToWorkerOnLoaderDone(std::unique_ptr<ExecutionContextTask>) = 0; |
| - |
| - // All executed on the main thread. |
| - void mainThreadCreateLoader(ThreadableLoaderOptions, ResourceLoaderOptions, ExecutionContext*); |
| - void mainThreadStart(std::unique_ptr<CrossThreadResourceRequestData>); |
| - void mainThreadDestroy(ExecutionContext*); |
| - void mainThreadOverrideTimeout(unsigned long timeoutMilliseconds, ExecutionContext*); |
| - void mainThreadCancel(ExecutionContext*); |
| - |
| - // Only to be used on the main thread. |
| - std::unique_ptr<ThreadableLoader> m_mainThreadLoader; |
| + class AsyncTaskForwarder final : public TaskForwarder { |
| + public: |
| + explicit AsyncTaskForwarder(PassRefPtr<WorkerLoaderProxy>); |
| + ~AsyncTaskForwarder() override; |
| - // |m_workerClientWrapper| holds an pointer created on the worker |
| - // thread, and |this| instance is created on the main thread. |
| - CrossThreadPersistent<ThreadableLoaderClientWrapper> m_workerClientWrapper; |
| + void forwardTask(std::unique_ptr<ExecutionContextTask>) override; |
| + void forwardTaskWithDoneSignal(std::unique_ptr<ExecutionContextTask>) override; |
| + void abort() override; |
| - // Used on the worker context thread. |
| + private: |
| RefPtr<WorkerLoaderProxy> m_loaderProxy; |
| }; |
| - class MainThreadAsyncBridge final : public MainThreadBridgeBase { |
| + // All observing functions must be called after |wait()| returns, and all |
| + // setting functions must be called before |signal()| is called. |
| + class WaitableEventWithTasks final : public ThreadSafeRefCounted<WaitableEventWithTasks> { |
| public: |
| - MainThreadAsyncBridge(WorkerGlobalScope&, ThreadableLoaderClientWrapper*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&); |
| - void start(const ResourceRequest&, const WorkerGlobalScope&) override; |
| + static PassRefPtr<WaitableEventWithTasks> create() { return adoptRef(new WaitableEventWithTasks); } |
| + ~WaitableEventWithTasks(); |
| + |
| + void signal(); |
| + void wait(); |
| + |
| + // Observing functions |
| + bool isAborted() const { return m_isAborted; } |
| + Vector<std::unique_ptr<ExecutionContextTask>> take(); |
| + |
| + // Setting functions |
| + void append(std::unique_ptr<ExecutionContextTask>); |
| + void setIsAborted() { m_isAborted = true; } |
| private: |
| - ~MainThreadAsyncBridge() override; |
| + WaitableEventWithTasks() {} |
| - void forwardTaskToWorker(std::unique_ptr<ExecutionContextTask>) override; |
| - void forwardTaskToWorkerOnLoaderDone(std::unique_ptr<ExecutionContextTask>) override; |
| + WaitableEvent m_event; |
| + Vector<std::unique_ptr<ExecutionContextTask>> m_tasks; |
| + bool m_isAborted = false; |
| }; |
| - class MainThreadSyncBridge final : public MainThreadBridgeBase { |
| + class SyncTaskForwarder final : public TaskForwarder { |
| public: |
| - MainThreadSyncBridge(WorkerGlobalScope&, ThreadableLoaderClientWrapper*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&); |
| - void start(const ResourceRequest&, const WorkerGlobalScope&) override; |
| + explicit SyncTaskForwarder(PassRefPtr<WaitableEventWithTasks>); |
| + ~SyncTaskForwarder() override; |
| + |
| + void forwardTask(std::unique_ptr<ExecutionContextTask>) override; |
| + void forwardTaskWithDoneSignal(std::unique_ptr<ExecutionContextTask>) override; |
| + void abort() override; |
| private: |
| - ~MainThreadSyncBridge() override; |
| - |
| - void forwardTaskToWorker(std::unique_ptr<ExecutionContextTask>) override; |
| - void forwardTaskToWorkerOnLoaderDone(std::unique_ptr<ExecutionContextTask>) override; |
| - |
| - bool m_done; |
| - std::unique_ptr<WaitableEvent> m_loaderDoneEvent; |
| - // Thread-safety: |m_clientTasks| can be written (i.e. Closures are added) |
| - // on the main thread only before |m_loaderDoneEvent| is signaled and can be read |
| - // on the worker context thread only after |m_loaderDoneEvent| is signaled. |
| - Vector<std::unique_ptr<ExecutionContextTask>> m_clientTasks; |
| - Mutex m_lock; |
| + RefPtr<WaitableEventWithTasks> m_eventWithTasks; |
| + }; |
| + |
| + class Peer; |
| + // A Bridge instance lives in the worker thread and asks loading tasks the |
| + // associated Peer object which lives in the main thread. |
| + class Bridge final : public GarbageCollectedFinalized<Bridge> { |
| + public: |
| + Bridge(ThreadableLoaderClientWrapper*, PassRefPtr<WorkerLoaderProxy>, const ThreadableLoaderOptions&, const ResourceLoaderOptions&, BlockingBehavior); |
| + ~Bridge(); |
| + |
| + void start(const ResourceRequest&, const WorkerGlobalScope&); |
| + void overrideTimeout(unsigned long timeoutMilliseconds); |
| + void cancel(); |
| + void destroy(); |
| + |
| + void didStart(Peer*); |
| + |
| + // These getter functions are thread safe. |
| + ThreadableLoaderClientWrapper* clientWrapper() { return m_clientWrapper.get(); } |
| + const ThreadableLoaderOptions& threadableLoaderOptions() const { return m_threadableLoaderOptions; } |
| + const ResourceLoaderOptions& resourceLoaderOptions() const { return m_resourceLoaderOptions; } |
| + |
| + DECLARE_VIRTUAL_TRACE(); |
| + |
| + private: |
| + const Member<ThreadableLoaderClientWrapper> m_clientWrapper; |
| + const RefPtr<WorkerLoaderProxy> m_loaderProxy; |
| + const ThreadableLoaderOptions m_threadableLoaderOptions; |
| + const ResourceLoaderOptions m_resourceLoaderOptions; |
| + const BlockingBehavior m_blockingBehavior; |
| + |
| + // |*m_peer| lives in the main thread. |
| + CrossThreadPersistent<Peer> m_peer; |
| + }; |
| + |
| + // A Peer instance lives in the main thread. It is a ThreadableLoaderClient |
| + // for a DocumentThreadableLoader and forward notifications to the |
| + // ThreadableLoaderClientWrapper which lives in the worker thread. |
| + class Peer final : public GarbageCollectedFinalized<Peer>, public ThreadableLoaderClient, public WorkerThreadLifecycleObserver { |
| + USING_GARBAGE_COLLECTED_MIXIN(Peer); |
| + public: |
| + static void createAndStart( |
| + Bridge*, |
| + PassRefPtr<WorkerLoaderProxy>, |
| + WorkerThreadLifecycleContext*, |
| + std::unique_ptr<CrossThreadResourceRequestData>, |
| + const ThreadableLoaderOptions&, |
| + const ResourceLoaderOptions&, |
| + PassRefPtr<WaitableEventWithTasks>, |
| + ExecutionContext*); |
| + ~Peer() override; |
| + |
| + void overrideTimeout(unsigned long timeoutMillisecond); |
| + void cancel(); |
| + |
| + void didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) override; |
| + void didReceiveResponse(unsigned long identifier, const ResourceResponse&, std::unique_ptr<WebDataConsumerHandle>) override; |
| + void didReceiveData(const char*, unsigned dataLength) override; |
| + void didDownloadData(int dataLength) override; |
| + void didReceiveCachedMetadata(const char*, int dataLength) override; |
| + void didFinishLoading(unsigned long identifier, double finishTime) override; |
| + void didFail(const ResourceError&) override; |
| + void didFailAccessControlCheck(const ResourceError&) override; |
| + void didFailRedirectCheck() override; |
| + void didReceiveResourceTiming(const ResourceTimingInfo&) override; |
| + |
| + void contextDestroyed() override; |
| + |
| + DECLARE_TRACE(); |
| + |
| + private: |
| + Peer(TaskForwarder*, WorkerThreadLifecycleContext*); |
| + void start(Document&, std::unique_ptr<CrossThreadResourceRequestData>, const ThreadableLoaderOptions&, const ResourceLoaderOptions&); |
| + |
| + Member<TaskForwarder> m_forwarder; |
| + std::unique_ptr<ThreadableLoader> m_mainThreadLoader; |
| + |
| + // |*m_clientWrapper| lives in the worker thread. |
| + CrossThreadWeakPersistent<ThreadableLoaderClientWrapper> m_clientWrapper; |
|
haraken
2016/07/21 10:22:29
Does this need to be a weak pointer?
yhirano
2016/07/21 10:56:09
Having this as a strong persistent may form a refe
haraken
2016/07/21 15:56:14
I want to confirm two things:
- Even if we use a
yhirano
2016/07/22 04:42:14
contextDestroyed is called at the worker thread te
haraken
2016/07/22 08:57:30
Makes sense.
Once we move ThreadableLoader to Oil
|
| }; |
| WorkerThreadableLoader(WorkerGlobalScope&, ThreadableLoaderClient*, const ThreadableLoaderOptions&, const ResourceLoaderOptions&, BlockingBehavior); |
| Persistent<WorkerGlobalScope> m_workerGlobalScope; |
| const Persistent<ThreadableLoaderClientWrapper> m_workerClientWrapper; |
| - |
| - MainThreadBridgeBase* m_bridge; |
| + const Persistent<Bridge> m_bridge; |
| }; |
| } // namespace blink |