OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2009, 2010 Google Inc. All rights reserved. | 2 * Copyright (C) 2009, 2010 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 18 matching lines...) Expand all Loading... |
29 */ | 29 */ |
30 | 30 |
31 #include "core/loader/WorkerThreadableLoader.h" | 31 #include "core/loader/WorkerThreadableLoader.h" |
32 | 32 |
33 #include "core/dom/CrossThreadTask.h" | 33 #include "core/dom/CrossThreadTask.h" |
34 #include "core/dom/Document.h" | 34 #include "core/dom/Document.h" |
35 #include "core/loader/DocumentThreadableLoader.h" | 35 #include "core/loader/DocumentThreadableLoader.h" |
36 #include "core/timing/WorkerGlobalScopePerformance.h" | 36 #include "core/timing/WorkerGlobalScopePerformance.h" |
37 #include "core/workers/WorkerGlobalScope.h" | 37 #include "core/workers/WorkerGlobalScope.h" |
38 #include "core/workers/WorkerLoaderProxy.h" | 38 #include "core/workers/WorkerLoaderProxy.h" |
39 #include "core/workers/WorkerThread.h" | |
40 #include "platform/CrossThreadFunctional.h" | 39 #include "platform/CrossThreadFunctional.h" |
41 #include "platform/WaitableEvent.h" | |
42 #include "platform/heap/SafePoint.h" | 40 #include "platform/heap/SafePoint.h" |
43 #include "platform/network/ResourceError.h" | 41 #include "platform/network/ResourceError.h" |
44 #include "platform/network/ResourceRequest.h" | 42 #include "platform/network/ResourceRequest.h" |
45 #include "platform/network/ResourceResponse.h" | 43 #include "platform/network/ResourceResponse.h" |
46 #include "platform/network/ResourceTimingInfo.h" | 44 #include "platform/network/ResourceTimingInfo.h" |
47 #include "platform/weborigin/SecurityPolicy.h" | 45 #include "platform/weborigin/SecurityPolicy.h" |
48 #include "public/platform/Platform.h" | |
49 #include "wtf/PtrUtil.h" | |
50 #include "wtf/Vector.h" | |
51 #include "wtf/debug/Alias.h" | 46 #include "wtf/debug/Alias.h" |
52 #include <memory> | 47 #include <memory> |
53 | 48 |
54 namespace blink { | 49 namespace blink { |
55 | 50 |
56 static std::unique_ptr<Vector<char>> createVectorFromMemoryRegion(const char* da
ta, unsigned dataLength) | 51 namespace { |
| 52 |
| 53 std::unique_ptr<Vector<char>> createVectorFromMemoryRegion(const char* data, uns
igned dataLength) |
57 { | 54 { |
58 std::unique_ptr<Vector<char>> buffer = wrapUnique(new Vector<char>(dataLengt
h)); | 55 std::unique_ptr<Vector<char>> buffer = wrapUnique(new Vector<char>(dataLengt
h)); |
59 memcpy(buffer->data(), data, dataLength); | 56 memcpy(buffer->data(), data, dataLength); |
60 return buffer; | 57 return buffer; |
61 } | 58 } |
62 | 59 |
63 WorkerThreadableLoader::WorkerThreadableLoader(WorkerGlobalScope& workerGlobalSc
ope, ThreadableLoaderClient* client, const ThreadableLoaderOptions& options, con
st ResourceLoaderOptions& resourceLoaderOptions, BlockingBehavior blockingBehavi
or) | 60 } // namespace |
| 61 |
| 62 class WorkerThreadableLoader::AsyncTaskForwarder final : public WorkerThreadable
Loader::TaskForwarder { |
| 63 public: |
| 64 explicit AsyncTaskForwarder(PassRefPtr<WorkerLoaderProxy> loaderProxy) |
| 65 : m_loaderProxy(loaderProxy) |
| 66 { |
| 67 DCHECK(isMainThread()); |
| 68 } |
| 69 ~AsyncTaskForwarder() override |
| 70 { |
| 71 DCHECK(isMainThread()); |
| 72 } |
| 73 |
| 74 void forwardTask(const WebTraceLocation& location, std::unique_ptr<Execution
ContextTask> task) override |
| 75 { |
| 76 DCHECK(isMainThread()); |
| 77 m_loaderProxy->postTaskToWorkerGlobalScope(location, std::move(task)); |
| 78 } |
| 79 void forwardTaskWithDoneSignal(const WebTraceLocation& location, std::unique
_ptr<ExecutionContextTask> task) override |
| 80 { |
| 81 DCHECK(isMainThread()); |
| 82 m_loaderProxy->postTaskToWorkerGlobalScope(location, std::move(task)); |
| 83 } |
| 84 void abort() override |
| 85 { |
| 86 DCHECK(isMainThread()); |
| 87 } |
| 88 |
| 89 private: |
| 90 RefPtr<WorkerLoaderProxy> m_loaderProxy; |
| 91 }; |
| 92 |
| 93 struct WorkerThreadableLoader::TaskWithLocation final { |
| 94 TaskWithLocation(const WebTraceLocation& location, std::unique_ptr<Execution
ContextTask> task) |
| 95 : m_location(location) |
| 96 , m_task(std::move(task)) |
| 97 { |
| 98 } |
| 99 TaskWithLocation(TaskWithLocation&& task) |
| 100 : TaskWithLocation(task.m_location, std::move(task.m_task)) |
| 101 { |
| 102 } |
| 103 ~TaskWithLocation() = default; |
| 104 |
| 105 WebTraceLocation m_location; |
| 106 std::unique_ptr<ExecutionContextTask> m_task; |
| 107 }; |
| 108 |
| 109 // Observing functions and wait() need to be called on the worker thread. |
| 110 // Setting functions and signal() need to be called on the main thread. |
| 111 // All observing functions must be called after wait() returns, and all |
| 112 // setting functions must be called before signal() is called. |
| 113 class WorkerThreadableLoader::WaitableEventWithTasks final : public ThreadSafeRe
fCounted<WaitableEventWithTasks> { |
| 114 public: |
| 115 static PassRefPtr<WaitableEventWithTasks> create() { return adoptRef(new Wai
tableEventWithTasks); } |
| 116 |
| 117 void signal() |
| 118 { |
| 119 DCHECK(isMainThread()); |
| 120 CHECK(!m_isSignalCalled); |
| 121 m_isSignalCalled = true; |
| 122 m_event.signal(); |
| 123 } |
| 124 void wait() |
| 125 { |
| 126 DCHECK(!isMainThread()); |
| 127 CHECK(!m_isWaitDone); |
| 128 m_event.wait(); |
| 129 m_isWaitDone = true; |
| 130 } |
| 131 |
| 132 // Observing functions |
| 133 bool isAborted() const |
| 134 { |
| 135 DCHECK(!isMainThread()); |
| 136 CHECK(m_isWaitDone); |
| 137 return m_isAborted; |
| 138 } |
| 139 Vector<TaskWithLocation> take() |
| 140 { |
| 141 DCHECK(!isMainThread()); |
| 142 CHECK(m_isWaitDone); |
| 143 return std::move(m_tasks); |
| 144 } |
| 145 |
| 146 // Setting functions |
| 147 void append(TaskWithLocation task) |
| 148 { |
| 149 DCHECK(isMainThread()); |
| 150 CHECK(!m_isSignalCalled); |
| 151 m_tasks.append(std::move(task)); |
| 152 } |
| 153 void setIsAborted() |
| 154 { |
| 155 DCHECK(isMainThread()); |
| 156 CHECK(!m_isSignalCalled); |
| 157 m_isAborted = true; |
| 158 } |
| 159 |
| 160 private: |
| 161 WaitableEventWithTasks() {} |
| 162 |
| 163 WaitableEvent m_event; |
| 164 Vector<TaskWithLocation> m_tasks; |
| 165 bool m_isAborted = false; |
| 166 bool m_isSignalCalled = false; |
| 167 bool m_isWaitDone = false; |
| 168 }; |
| 169 |
| 170 class WorkerThreadableLoader::SyncTaskForwarder final : public WorkerThreadableL
oader::TaskForwarder { |
| 171 public: |
| 172 explicit SyncTaskForwarder(PassRefPtr<WaitableEventWithTasks> eventWithTasks
) |
| 173 : m_eventWithTasks(eventWithTasks) |
| 174 { |
| 175 DCHECK(isMainThread()); |
| 176 } |
| 177 ~SyncTaskForwarder() override |
| 178 { |
| 179 DCHECK(isMainThread()); |
| 180 } |
| 181 |
| 182 void forwardTask(const WebTraceLocation& location, std::unique_ptr<Execution
ContextTask> task) override |
| 183 { |
| 184 DCHECK(isMainThread()); |
| 185 m_eventWithTasks->append(TaskWithLocation(location, std::move(task))); |
| 186 } |
| 187 void forwardTaskWithDoneSignal(const WebTraceLocation& location, std::unique
_ptr<ExecutionContextTask> task) override |
| 188 { |
| 189 DCHECK(isMainThread()); |
| 190 m_eventWithTasks->append(TaskWithLocation(location, std::move(task))); |
| 191 m_eventWithTasks->signal(); |
| 192 } |
| 193 void abort() override |
| 194 { |
| 195 DCHECK(isMainThread()); |
| 196 m_eventWithTasks->setIsAborted(); |
| 197 m_eventWithTasks->signal(); |
| 198 } |
| 199 |
| 200 private: |
| 201 RefPtr<WaitableEventWithTasks> m_eventWithTasks; |
| 202 }; |
| 203 |
| 204 WorkerThreadableLoader::WorkerThreadableLoader( |
| 205 WorkerGlobalScope& workerGlobalScope, |
| 206 ThreadableLoaderClient* client, |
| 207 const ThreadableLoaderOptions& options, |
| 208 const ResourceLoaderOptions& resourceLoaderOptions, |
| 209 BlockingBehavior blockingBehavior) |
64 : m_workerGlobalScope(&workerGlobalScope) | 210 : m_workerGlobalScope(&workerGlobalScope) |
65 , m_workerClientWrapper(new ThreadableLoaderClientWrapper(workerGlobalScope,
client)) | 211 , m_workerClientWrapper(new ThreadableLoaderClientWrapper(workerGlobalScope,
client)) |
| 212 , m_bridge(new Bridge(m_workerClientWrapper, workerGlobalScope.thread()->wor
kerLoaderProxy(), options, resourceLoaderOptions, blockingBehavior)) |
66 { | 213 { |
67 if (blockingBehavior == LoadAsynchronously) { | |
68 m_bridge = new MainThreadAsyncBridge(workerGlobalScope, m_workerClientWr
apper, options, resourceLoaderOptions); | |
69 } else { | |
70 m_bridge = new MainThreadSyncBridge(workerGlobalScope, m_workerClientWra
pper, options, resourceLoaderOptions); | |
71 } | |
72 } | 214 } |
73 | 215 |
74 void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope& worker
GlobalScope, const ResourceRequest& request, ThreadableLoaderClient& client, con
st ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoader
Options) | 216 void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope& worker
GlobalScope, const ResourceRequest& request, ThreadableLoaderClient& client, con
st ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoader
Options) |
75 { | 217 { |
76 std::unique_ptr<WorkerThreadableLoader> loader = wrapUnique(new WorkerThread
ableLoader(workerGlobalScope, &client, options, resourceLoaderOptions, LoadSynch
ronously)); | 218 std::unique_ptr<WorkerThreadableLoader> loader = wrapUnique(new WorkerThread
ableLoader(workerGlobalScope, &client, options, resourceLoaderOptions, LoadSynch
ronously)); |
77 loader->start(request); | 219 loader->start(request); |
78 } | 220 } |
79 | 221 |
80 WorkerThreadableLoader::~WorkerThreadableLoader() | 222 WorkerThreadableLoader::~WorkerThreadableLoader() |
81 { | 223 { |
82 DCHECK(m_workerClientWrapper->done()); | 224 DCHECK(m_workerClientWrapper->done()); |
83 m_bridge->destroy(); | 225 m_bridge->destroy(); |
84 m_bridge = nullptr; | |
85 } | 226 } |
86 | 227 |
87 void WorkerThreadableLoader::start(const ResourceRequest& request) | 228 void WorkerThreadableLoader::start(const ResourceRequest& request) |
88 { | 229 { |
89 ResourceRequest requestToPass(request); | 230 ResourceRequest requestToPass(request); |
90 if (!requestToPass.didSetHTTPReferrer()) | 231 if (!requestToPass.didSetHTTPReferrer()) |
91 requestToPass.setHTTPReferrer(SecurityPolicy::generateReferrer(m_workerG
lobalScope->getReferrerPolicy(), request.url(), m_workerGlobalScope->outgoingRef
errer())); | 232 requestToPass.setHTTPReferrer(SecurityPolicy::generateReferrer(m_workerG
lobalScope->getReferrerPolicy(), request.url(), m_workerGlobalScope->outgoingRef
errer())); |
92 m_bridge->start(requestToPass, *m_workerGlobalScope); | 233 m_bridge->start(requestToPass, *m_workerGlobalScope); |
93 } | 234 } |
94 | 235 |
95 void WorkerThreadableLoader::overrideTimeout(unsigned long timeoutMilliseconds) | 236 void WorkerThreadableLoader::overrideTimeout(unsigned long timeoutMilliseconds) |
96 { | 237 { |
97 ASSERT(m_bridge); | |
98 m_bridge->overrideTimeout(timeoutMilliseconds); | 238 m_bridge->overrideTimeout(timeoutMilliseconds); |
99 } | 239 } |
100 | 240 |
101 void WorkerThreadableLoader::cancel() | 241 void WorkerThreadableLoader::cancel() |
102 { | 242 { |
103 ASSERT(m_bridge); | |
104 m_bridge->cancel(); | 243 m_bridge->cancel(); |
105 } | 244 } |
106 | 245 |
107 WorkerThreadableLoader::MainThreadBridgeBase::MainThreadBridgeBase( | 246 WorkerThreadableLoader::Bridge::Bridge( |
108 ThreadableLoaderClientWrapper* workerClientWrapper, | 247 ThreadableLoaderClientWrapper* clientWrapper, |
109 PassRefPtr<WorkerLoaderProxy> loaderProxy) | 248 PassRefPtr<WorkerLoaderProxy> loaderProxy, |
110 : m_workerClientWrapper(workerClientWrapper) | 249 const ThreadableLoaderOptions& threadableLoaderOptions, |
| 250 const ResourceLoaderOptions& resourceLoaderOptions, |
| 251 BlockingBehavior blockingBehavior) |
| 252 : m_clientWrapper(clientWrapper) |
111 , m_loaderProxy(loaderProxy) | 253 , m_loaderProxy(loaderProxy) |
112 { | 254 , m_threadableLoaderOptions(threadableLoaderOptions) |
113 ASSERT(m_workerClientWrapper.get()); | 255 , m_resourceLoaderOptions(resourceLoaderOptions) |
114 ASSERT(m_loaderProxy.get()); | 256 , m_blockingBehavior(blockingBehavior) |
115 } | 257 { |
116 | 258 DCHECK(!isMainThread()); |
117 WorkerThreadableLoader::MainThreadBridgeBase::~MainThreadBridgeBase() | 259 } |
118 { | 260 |
119 } | 261 WorkerThreadableLoader::Bridge::~Bridge() |
120 | 262 { |
121 void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadCreateLoader(Thread
ableLoaderOptions options, ResourceLoaderOptions resourceLoaderOptions, Executio
nContext* context) | 263 DCHECK(!isMainThread()); |
122 { | 264 DCHECK(!m_peer); |
123 ASSERT(isMainThread()); | 265 } |
124 Document* document = toDocument(context); | 266 |
125 | 267 void WorkerThreadableLoader::Bridge::start(const ResourceRequest& request, const
WorkerGlobalScope& workerGlobalScope) |
126 resourceLoaderOptions.requestInitiatorContext = WorkerContext; | 268 { |
127 m_mainThreadLoader = DocumentThreadableLoader::create(*document, this, optio
ns, resourceLoaderOptions); | 269 DCHECK(!isMainThread()); |
128 ASSERT(m_mainThreadLoader); | 270 RefPtr<WaitableEventWithTasks> eventWithTasks; |
129 } | 271 if (m_blockingBehavior == LoadSynchronously) |
130 | 272 eventWithTasks = WaitableEventWithTasks::create(); |
131 void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadStart(std::unique_p
tr<CrossThreadResourceRequestData> requestData) | 273 |
132 { | 274 m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask( |
133 ASSERT(isMainThread()); | 275 &Peer::createAndStart, |
134 ASSERT(m_mainThreadLoader); | 276 wrapCrossThreadPersistent(this), |
135 m_mainThreadLoader->start(ResourceRequest(requestData.get())); | 277 m_loaderProxy, |
136 } | 278 wrapCrossThreadPersistent(workerGlobalScope.thread()->getWorkerThreadLif
ecycleContext()), |
137 | 279 request, |
138 void WorkerThreadableLoader::MainThreadBridgeBase::createLoaderInMainThread(cons
t ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderO
ptions) | 280 m_threadableLoaderOptions, |
139 { | 281 m_resourceLoaderOptions, |
140 m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&Main
ThreadBridgeBase::mainThreadCreateLoader, crossThreadUnretained(this), options,
resourceLoaderOptions)); | 282 eventWithTasks)); |
141 } | 283 |
142 | 284 if (m_blockingBehavior == LoadAsynchronously) |
143 void WorkerThreadableLoader::MainThreadBridgeBase::startInMainThread(const Resou
rceRequest& request, const WorkerGlobalScope& workerGlobalScope) | 285 return; |
144 { | 286 |
145 loaderProxy()->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&Main
ThreadBridgeBase::mainThreadStart, crossThreadUnretained(this), request)); | |
146 } | |
147 | |
148 void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadDestroy(ExecutionCo
ntext* context) | |
149 { | |
150 ASSERT(isMainThread()); | |
151 ASSERT_UNUSED(context, context->isDocument()); | |
152 delete this; | |
153 } | |
154 | |
155 void WorkerThreadableLoader::MainThreadBridgeBase::destroy() | |
156 { | |
157 // Ensure that no more client callbacks are done in the worker context's | |
158 // thread. | |
159 // ThreadableLoaderClientWrapper is an on-heap class and this function can | |
160 // be called in the finalization step but it is safe because | |
161 // m_workerClientWrapper is a CrossThreadPersistent. | |
162 m_workerClientWrapper->clearClient(); | |
163 | |
164 // "delete this" and m_mainThreadLoader::deref() on the worker object's | |
165 // thread. | |
166 m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&Main
ThreadBridgeBase::mainThreadDestroy, crossThreadUnretained(this))); | |
167 } | |
168 | |
169 void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadOverrideTimeout(uns
igned long timeoutMilliseconds, ExecutionContext* context) | |
170 { | |
171 ASSERT(isMainThread()); | |
172 ASSERT_UNUSED(context, context->isDocument()); | |
173 | |
174 if (!m_mainThreadLoader) | |
175 return; | |
176 m_mainThreadLoader->overrideTimeout(timeoutMilliseconds); | |
177 } | |
178 | |
179 void WorkerThreadableLoader::MainThreadBridgeBase::overrideTimeout(unsigned long
timeoutMilliseconds) | |
180 { | |
181 m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&Main
ThreadBridgeBase::mainThreadOverrideTimeout, crossThreadUnretained(this), timeou
tMilliseconds)); | |
182 } | |
183 | |
184 void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadCancel(ExecutionCon
text* context) | |
185 { | |
186 ASSERT(isMainThread()); | |
187 ASSERT_UNUSED(context, context->isDocument()); | |
188 | |
189 if (!m_mainThreadLoader) | |
190 return; | |
191 m_mainThreadLoader->cancel(); | |
192 m_mainThreadLoader = nullptr; | |
193 } | |
194 | |
195 void WorkerThreadableLoader::MainThreadBridgeBase::cancel() | |
196 { | |
197 m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&Main
ThreadBridgeBase::mainThreadCancel, crossThreadUnretained(this))); | |
198 ThreadableLoaderClientWrapper* clientWrapper = m_workerClientWrapper; | |
199 if (!clientWrapper->done()) { | |
200 // If the client hasn't reached a termination state, then transition it | |
201 // by sending a cancellation error. | |
202 // Note: no more client callbacks will be done after this method -- the | |
203 // m_workerClientWrapper->clearClient() call ensures that. | |
204 ResourceError error(String(), 0, String(), String()); | |
205 error.setIsCancellation(true); | |
206 clientWrapper->didFail(error); | |
207 } | |
208 // |this| might be already destructed here because didFail() might | |
209 // clear a reference to ThreadableLoader, which might destruct | |
210 // WorkerThreadableLoader and then MainThreadBridge. | |
211 // Therefore we call clearClient() directly, rather than calling | |
212 // this->m_workerClientWrapper->clearClient(). | |
213 clientWrapper->clearClient(); | |
214 } | |
215 | |
216 void WorkerThreadableLoader::MainThreadBridgeBase::didSendData(unsigned long lon
g bytesSent, unsigned long long totalBytesToBeSent) | |
217 { | |
218 forwardTaskToWorker(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoader
ClientWrapper::didSendData, m_workerClientWrapper, bytesSent, totalBytesToBeSent
)); | |
219 } | |
220 | |
221 void WorkerThreadableLoader::MainThreadBridgeBase::didReceiveResponse(unsigned l
ong identifier, const ResourceResponse& response, std::unique_ptr<WebDataConsume
rHandle> handle) | |
222 { | |
223 forwardTaskToWorker(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoader
ClientWrapper::didReceiveResponse, m_workerClientWrapper, identifier, response,
passed(std::move(handle)))); | |
224 } | |
225 | |
226 void WorkerThreadableLoader::MainThreadBridgeBase::didReceiveData(const char* da
ta, unsigned dataLength) | |
227 { | |
228 forwardTaskToWorker(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoader
ClientWrapper::didReceiveData, m_workerClientWrapper, passed(createVectorFromMem
oryRegion(data, dataLength)))); | |
229 } | |
230 | |
231 void WorkerThreadableLoader::MainThreadBridgeBase::didDownloadData(int dataLengt
h) | |
232 { | |
233 forwardTaskToWorker(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoader
ClientWrapper::didDownloadData, m_workerClientWrapper, dataLength)); | |
234 } | |
235 | |
236 void WorkerThreadableLoader::MainThreadBridgeBase::didReceiveCachedMetadata(cons
t char* data, int dataLength) | |
237 { | |
238 forwardTaskToWorker(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoader
ClientWrapper::didReceiveCachedMetadata, m_workerClientWrapper, passed(createVec
torFromMemoryRegion(data, dataLength)))); | |
239 } | |
240 | |
241 void WorkerThreadableLoader::MainThreadBridgeBase::didFinishLoading(unsigned lon
g identifier, double finishTime) | |
242 { | |
243 forwardTaskToWorkerOnLoaderDone(BLINK_FROM_HERE, createCrossThreadTask(&Thre
adableLoaderClientWrapper::didFinishLoading, m_workerClientWrapper, identifier,
finishTime)); | |
244 } | |
245 | |
246 void WorkerThreadableLoader::MainThreadBridgeBase::didFail(const ResourceError&
error) | |
247 { | |
248 forwardTaskToWorkerOnLoaderDone(BLINK_FROM_HERE, createCrossThreadTask(&Thre
adableLoaderClientWrapper::didFail, m_workerClientWrapper, error)); | |
249 } | |
250 | |
251 void WorkerThreadableLoader::MainThreadBridgeBase::didFailAccessControlCheck(con
st ResourceError& error) | |
252 { | |
253 forwardTaskToWorkerOnLoaderDone(BLINK_FROM_HERE, createCrossThreadTask(&Thre
adableLoaderClientWrapper::didFailAccessControlCheck, m_workerClientWrapper, err
or)); | |
254 } | |
255 | |
256 void WorkerThreadableLoader::MainThreadBridgeBase::didFailRedirectCheck() | |
257 { | |
258 forwardTaskToWorkerOnLoaderDone(BLINK_FROM_HERE, createCrossThreadTask(&Thre
adableLoaderClientWrapper::didFailRedirectCheck, m_workerClientWrapper)); | |
259 } | |
260 | |
261 void WorkerThreadableLoader::MainThreadBridgeBase::didReceiveResourceTiming(cons
t ResourceTimingInfo& info) | |
262 { | |
263 forwardTaskToWorker(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableLoader
ClientWrapper::didReceiveResourceTiming, m_workerClientWrapper, info)); | |
264 } | |
265 | |
266 WorkerThreadableLoader::MainThreadAsyncBridge::MainThreadAsyncBridge( | |
267 WorkerGlobalScope& workerGlobalScope, | |
268 ThreadableLoaderClientWrapper* workerClientWrapper, | |
269 const ThreadableLoaderOptions& options, | |
270 const ResourceLoaderOptions& resourceLoaderOptions) | |
271 : MainThreadBridgeBase(workerClientWrapper, workerGlobalScope.thread()->work
erLoaderProxy()) | |
272 { | |
273 createLoaderInMainThread(options, resourceLoaderOptions); | |
274 } | |
275 | |
276 void WorkerThreadableLoader::MainThreadAsyncBridge::start(const ResourceRequest&
request, const WorkerGlobalScope& workerGlobalScope) | |
277 { | |
278 startInMainThread(request, workerGlobalScope); | |
279 } | |
280 | |
281 WorkerThreadableLoader::MainThreadAsyncBridge::~MainThreadAsyncBridge() | |
282 { | |
283 } | |
284 | |
285 void WorkerThreadableLoader::MainThreadAsyncBridge::forwardTaskToWorker(const We
bTraceLocation& location, std::unique_ptr<ExecutionContextTask> task) | |
286 { | |
287 loaderProxy()->postTaskToWorkerGlobalScope(location, std::move(task)); | |
288 } | |
289 | |
290 void WorkerThreadableLoader::MainThreadAsyncBridge::forwardTaskToWorkerOnLoaderD
one(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task
) | |
291 { | |
292 loaderProxy()->postTaskToWorkerGlobalScope(location, std::move(task)); | |
293 } | |
294 | |
295 WorkerThreadableLoader::MainThreadSyncBridge::MainThreadSyncBridge( | |
296 WorkerGlobalScope& workerGlobalScope, | |
297 ThreadableLoaderClientWrapper* workerClientWrapper, | |
298 const ThreadableLoaderOptions& options, | |
299 const ResourceLoaderOptions& resourceLoaderOptions) | |
300 : MainThreadBridgeBase(workerClientWrapper, workerGlobalScope.thread()->work
erLoaderProxy()) | |
301 , m_done(false) | |
302 { | |
303 createLoaderInMainThread(options, resourceLoaderOptions); | |
304 } | |
305 | |
306 void WorkerThreadableLoader::MainThreadSyncBridge::start(const ResourceRequest&
request, const WorkerGlobalScope& workerGlobalScope) | |
307 { | |
308 WaitableEvent* terminationEvent = workerGlobalScope.thread()->terminationEve
nt(); | |
309 m_loaderDoneEvent = wrapUnique(new WaitableEvent()); | |
310 | |
311 startInMainThread(request, workerGlobalScope); | |
312 | |
313 size_t signaledIndex; | |
314 { | 287 { |
315 Vector<WaitableEvent*> events; | |
316 // Order is important; indicies are used later. | |
317 events.append(terminationEvent); | |
318 events.append(m_loaderDoneEvent.get()); | |
319 | |
320 SafePointScope scope(BlinkGC::HeapPointersOnStack); | 288 SafePointScope scope(BlinkGC::HeapPointersOnStack); |
321 signaledIndex = WaitableEvent::waitMultiple(events); | 289 eventWithTasks->wait(); |
322 } | 290 } |
323 // |signaledIndex| is 0; which is terminationEvent. | 291 |
324 if (signaledIndex == 0) { | 292 if (eventWithTasks->isAborted()) { |
| 293 // This thread is going to terminate. |
325 cancel(); | 294 cancel(); |
326 return; | 295 return; |
327 } | 296 } |
328 | 297 |
329 // The following code must be run only after |m_loaderDoneEvent| is | 298 for (const auto& task : eventWithTasks->take()) { |
330 // signalled. | |
331 | |
332 Vector<ClientTask> tasks; | |
333 { | |
334 MutexLocker lock(m_lock); | |
335 ASSERT(m_done); | |
336 m_clientTasks.swap(tasks); | |
337 } | |
338 for (const auto& task : tasks) { | |
339 // Store the program counter where the task is posted from, and alias | 299 // Store the program counter where the task is posted from, and alias |
340 // it to ensure it is stored in the crash dump. | 300 // it to ensure it is stored in the crash dump. |
341 const void* programCounter = task.m_location.program_counter(); | 301 const void* programCounter = task.m_location.program_counter(); |
342 WTF::debug::alias(&programCounter); | 302 WTF::debug::alias(&programCounter); |
343 | 303 |
344 // m_clientTask contains only CallClosureTasks. So, it's ok to pass | 304 // m_clientTask contains only CallClosureTasks. So, it's ok to pass |
345 // the nullptr. | 305 // the nullptr. |
346 task.m_task->performTask(nullptr); | 306 task.m_task->performTask(nullptr); |
347 } | 307 } |
348 } | 308 } |
349 | 309 |
350 WorkerThreadableLoader::MainThreadSyncBridge::ClientTask::ClientTask(const WebTr
aceLocation& location, std::unique_ptr<ExecutionContextTask> task) | 310 void WorkerThreadableLoader::Bridge::overrideTimeout(unsigned long timeoutMillis
econds) |
351 : m_location(location) | 311 { |
352 , m_task(std::move(task)) {} | 312 DCHECK(!isMainThread()); |
353 | 313 if (!m_peer) |
354 WorkerThreadableLoader::MainThreadSyncBridge::ClientTask::~ClientTask() = defaul
t; | 314 return; |
355 WorkerThreadableLoader::MainThreadSyncBridge::ClientTask::ClientTask(ClientTask&
&) = default; | 315 m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&Peer
::overrideTimeout, m_peer, timeoutMilliseconds)); |
356 | 316 } |
357 WorkerThreadableLoader::MainThreadSyncBridge::~MainThreadSyncBridge() | 317 |
358 { | 318 void WorkerThreadableLoader::Bridge::cancel() |
359 ASSERT(isMainThread()); | 319 { |
360 } | 320 DCHECK(!isMainThread()); |
361 | 321 cancelPeer(); |
362 void WorkerThreadableLoader::MainThreadSyncBridge::forwardTaskToWorker(const Web
TraceLocation& location, std::unique_ptr<ExecutionContextTask> task) | 322 |
363 { | 323 if (m_clientWrapper->done()) |
364 ASSERT(isMainThread()); | 324 return; |
365 | 325 // If the client hasn't reached a termination state, then transition it |
366 MutexLocker lock(m_lock); | 326 // by sending a cancellation error. |
367 RELEASE_ASSERT(!m_done); | 327 // Note: no more client callbacks will be done after this method -- the |
368 | 328 // clearClient() call ensures that. |
369 m_clientTasks.append(ClientTask(location, std::move(task))); | 329 ResourceError error(String(), 0, String(), String()); |
370 } | 330 error.setIsCancellation(true); |
371 | 331 m_clientWrapper->didFail(error); |
372 void WorkerThreadableLoader::MainThreadSyncBridge::forwardTaskToWorkerOnLoaderDo
ne(const WebTraceLocation& location, std::unique_ptr<ExecutionContextTask> task) | 332 m_clientWrapper->clearClient(); |
373 { | 333 } |
374 ASSERT(isMainThread()); | 334 |
375 | 335 void WorkerThreadableLoader::Bridge::destroy() |
376 MutexLocker lock(m_lock); | 336 { |
377 RELEASE_ASSERT(!m_done); | 337 DCHECK(!isMainThread()); |
378 | 338 cancelPeer(); |
379 m_clientTasks.append(ClientTask(location, std::move(task))); | 339 m_clientWrapper->clearClient(); |
380 m_done = true; | 340 } |
381 m_loaderDoneEvent->signal(); | 341 |
| 342 void WorkerThreadableLoader::Bridge::didStart(Peer* peer) |
| 343 { |
| 344 DCHECK(!isMainThread()); |
| 345 DCHECK(!m_peer); |
| 346 DCHECK(peer); |
| 347 if (m_clientWrapper->done()) { |
| 348 // The loading is already cancelled. |
| 349 return; |
| 350 } |
| 351 |
| 352 m_peer = peer; |
| 353 } |
| 354 |
| 355 DEFINE_TRACE(WorkerThreadableLoader::Bridge) |
| 356 { |
| 357 visitor->trace(m_clientWrapper); |
| 358 } |
| 359 |
| 360 void WorkerThreadableLoader::Bridge::cancelPeer() |
| 361 { |
| 362 DCHECK(!isMainThread()); |
| 363 if (!m_peer) |
| 364 return; |
| 365 m_loaderProxy->postTaskToLoader(BLINK_FROM_HERE, createCrossThreadTask(&Peer
::cancel, m_peer)); |
| 366 m_peer = nullptr; |
| 367 } |
| 368 |
| 369 void WorkerThreadableLoader::Peer::createAndStart( |
| 370 Bridge* bridge, |
| 371 PassRefPtr<WorkerLoaderProxy> passLoaderProxy, |
| 372 WorkerThreadLifecycleContext* workerThreadLifecycleContext, |
| 373 std::unique_ptr<CrossThreadResourceRequestData> request, |
| 374 const ThreadableLoaderOptions& options, |
| 375 const ResourceLoaderOptions& resourceLoaderOptions, |
| 376 PassRefPtr<WaitableEventWithTasks> eventWithTasks, |
| 377 ExecutionContext* executionContext) |
| 378 { |
| 379 DCHECK(isMainThread()); |
| 380 TaskForwarder* forwarder; |
| 381 RefPtr<WorkerLoaderProxy> loaderProxy = passLoaderProxy; |
| 382 if (eventWithTasks) |
| 383 forwarder = new SyncTaskForwarder(eventWithTasks); |
| 384 else |
| 385 forwarder = new AsyncTaskForwarder(loaderProxy); |
| 386 |
| 387 Peer* peer = new Peer(forwarder, workerThreadLifecycleContext); |
| 388 if (peer->wasContextDestroyedBeforeObserverCreation()) { |
| 389 // The thread is already terminating. |
| 390 forwarder->abort(); |
| 391 peer->m_forwarder = nullptr; |
| 392 return; |
| 393 } |
| 394 peer->m_clientWrapper = bridge->clientWrapper(); |
| 395 peer->start(*toDocument(executionContext), std::move(request), options, reso
urceLoaderOptions); |
| 396 forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&Bridge::didSt
art, wrapCrossThreadPersistent(bridge), wrapCrossThreadPersistent(peer))); |
| 397 } |
| 398 |
| 399 WorkerThreadableLoader::Peer::~Peer() |
| 400 { |
| 401 DCHECK(isMainThread()); |
| 402 DCHECK(!m_mainThreadLoader); |
| 403 } |
| 404 |
| 405 void WorkerThreadableLoader::Peer::overrideTimeout(unsigned long timeoutMillisec
onds) |
| 406 { |
| 407 DCHECK(isMainThread()); |
| 408 if (!m_mainThreadLoader) |
| 409 return; |
| 410 m_mainThreadLoader->overrideTimeout(timeoutMilliseconds); |
| 411 } |
| 412 |
| 413 void WorkerThreadableLoader::Peer::cancel() |
| 414 { |
| 415 DCHECK(isMainThread()); |
| 416 if (!m_mainThreadLoader) |
| 417 return; |
| 418 m_mainThreadLoader->cancel(); |
| 419 m_mainThreadLoader = nullptr; |
| 420 } |
| 421 |
| 422 void WorkerThreadableLoader::Peer::didSendData(unsigned long long bytesSent, uns
igned long long totalBytesToBeSent) |
| 423 { |
| 424 DCHECK(isMainThread()); |
| 425 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 426 if (!clientWrapper || !m_forwarder) |
| 427 return; |
| 428 m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableL
oaderClientWrapper::didSendData, clientWrapper, bytesSent, totalBytesToBeSent)); |
| 429 } |
| 430 |
| 431 void WorkerThreadableLoader::Peer::didReceiveResponse(unsigned long identifier,
const ResourceResponse& response, std::unique_ptr<WebDataConsumerHandle> handle) |
| 432 { |
| 433 DCHECK(isMainThread()); |
| 434 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 435 if (!clientWrapper || !m_forwarder) |
| 436 return; |
| 437 m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableL
oaderClientWrapper::didReceiveResponse, clientWrapper, identifier, response, pas
sed(std::move(handle)))); |
| 438 } |
| 439 |
| 440 void WorkerThreadableLoader::Peer::didReceiveData(const char* data, unsigned dat
aLength) |
| 441 { |
| 442 DCHECK(isMainThread()); |
| 443 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 444 if (!clientWrapper || !m_forwarder) |
| 445 return; |
| 446 m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableL
oaderClientWrapper::didReceiveData, clientWrapper, passed(createVectorFromMemory
Region(data, dataLength)))); |
| 447 } |
| 448 |
| 449 void WorkerThreadableLoader::Peer::didDownloadData(int dataLength) |
| 450 { |
| 451 DCHECK(isMainThread()); |
| 452 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 453 if (!clientWrapper || !m_forwarder) |
| 454 return; |
| 455 m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableL
oaderClientWrapper::didDownloadData, clientWrapper, dataLength)); |
| 456 } |
| 457 |
| 458 void WorkerThreadableLoader::Peer::didReceiveCachedMetadata(const char* data, in
t dataLength) |
| 459 { |
| 460 DCHECK(isMainThread()); |
| 461 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 462 if (!clientWrapper || !m_forwarder) |
| 463 return; |
| 464 m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableL
oaderClientWrapper::didReceiveCachedMetadata, clientWrapper, passed(createVector
FromMemoryRegion(data, dataLength)))); |
| 465 } |
| 466 |
| 467 void WorkerThreadableLoader::Peer::didFinishLoading(unsigned long identifier, do
uble finishTime) |
| 468 { |
| 469 DCHECK(isMainThread()); |
| 470 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 471 if (!clientWrapper || !m_forwarder) |
| 472 return; |
| 473 m_forwarder->forwardTaskWithDoneSignal(BLINK_FROM_HERE, createCrossThreadTas
k(&ThreadableLoaderClientWrapper::didFinishLoading, clientWrapper, identifier, f
inishTime)); |
| 474 m_forwarder = nullptr; |
| 475 } |
| 476 |
| 477 void WorkerThreadableLoader::Peer::didFail(const ResourceError& error) |
| 478 { |
| 479 DCHECK(isMainThread()); |
| 480 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 481 if (!clientWrapper || !m_forwarder) |
| 482 return; |
| 483 m_forwarder->forwardTaskWithDoneSignal(BLINK_FROM_HERE, createCrossThreadTas
k(&ThreadableLoaderClientWrapper::didFail, clientWrapper, error)); |
| 484 m_forwarder = nullptr; |
| 485 } |
| 486 |
| 487 void WorkerThreadableLoader::Peer::didFailAccessControlCheck(const ResourceError
& error) |
| 488 { |
| 489 DCHECK(isMainThread()); |
| 490 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 491 if (!clientWrapper || !m_forwarder) |
| 492 return; |
| 493 m_forwarder->forwardTaskWithDoneSignal(BLINK_FROM_HERE, createCrossThreadTas
k(&ThreadableLoaderClientWrapper::didFailAccessControlCheck, clientWrapper, erro
r)); |
| 494 m_forwarder = nullptr; |
| 495 } |
| 496 |
| 497 void WorkerThreadableLoader::Peer::didFailRedirectCheck() |
| 498 { |
| 499 DCHECK(isMainThread()); |
| 500 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 501 if (!clientWrapper || !m_forwarder) |
| 502 return; |
| 503 m_forwarder->forwardTaskWithDoneSignal(BLINK_FROM_HERE, createCrossThreadTas
k(&ThreadableLoaderClientWrapper::didFailRedirectCheck, clientWrapper)); |
| 504 m_forwarder = nullptr; |
| 505 } |
| 506 |
| 507 void WorkerThreadableLoader::Peer::didReceiveResourceTiming(const ResourceTiming
Info& info) |
| 508 { |
| 509 DCHECK(isMainThread()); |
| 510 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 511 if (!clientWrapper || !m_forwarder) |
| 512 return; |
| 513 m_forwarder->forwardTask(BLINK_FROM_HERE, createCrossThreadTask(&ThreadableL
oaderClientWrapper::didReceiveResourceTiming, clientWrapper, info)); |
| 514 } |
| 515 |
| 516 void WorkerThreadableLoader::Peer::contextDestroyed() |
| 517 { |
| 518 DCHECK(isMainThread()); |
| 519 if (m_forwarder) { |
| 520 m_forwarder->abort(); |
| 521 m_forwarder = nullptr; |
| 522 } |
| 523 m_clientWrapper = nullptr; |
| 524 cancel(); |
| 525 } |
| 526 |
| 527 DEFINE_TRACE(WorkerThreadableLoader::Peer) |
| 528 { |
| 529 visitor->trace(m_forwarder); |
| 530 WorkerThreadLifecycleObserver::trace(visitor); |
| 531 } |
| 532 |
| 533 WorkerThreadableLoader::Peer::Peer(TaskForwarder* forwarder, WorkerThreadLifecyc
leContext* context) |
| 534 : WorkerThreadLifecycleObserver(context) |
| 535 , m_forwarder(forwarder) |
| 536 { |
| 537 DCHECK(isMainThread()); |
| 538 } |
| 539 |
| 540 void WorkerThreadableLoader::Peer::start( |
| 541 Document& document, |
| 542 std::unique_ptr<CrossThreadResourceRequestData> request, |
| 543 const ThreadableLoaderOptions& options, |
| 544 const ResourceLoaderOptions& originalResourceLoaderOptions) |
| 545 { |
| 546 DCHECK(isMainThread()); |
| 547 ResourceLoaderOptions resourceLoaderOptions = originalResourceLoaderOptions; |
| 548 resourceLoaderOptions.requestInitiatorContext = WorkerContext; |
| 549 m_mainThreadLoader = DocumentThreadableLoader::create(document, this, option
s, resourceLoaderOptions); |
| 550 m_mainThreadLoader->start(ResourceRequest(request.get())); |
382 } | 551 } |
383 | 552 |
384 } // namespace blink | 553 } // namespace blink |
OLD | NEW |