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 <memory> | 46 #include <memory> |
52 | 47 |
53 namespace blink { | 48 namespace blink { |
54 | 49 |
55 static std::unique_ptr<Vector<char>> createVectorFromMemoryRegion(const char* da
ta, unsigned dataLength) | 50 namespace { |
| 51 |
| 52 std::unique_ptr<Vector<char>> createVectorFromMemoryRegion(const char* data, uns
igned dataLength) |
56 { | 53 { |
57 std::unique_ptr<Vector<char>> buffer = wrapUnique(new Vector<char>(dataLengt
h)); | 54 std::unique_ptr<Vector<char>> buffer = wrapUnique(new Vector<char>(dataLengt
h)); |
58 memcpy(buffer->data(), data, dataLength); | 55 memcpy(buffer->data(), data, dataLength); |
59 return buffer; | 56 return buffer; |
60 } | 57 } |
61 | 58 |
62 WorkerThreadableLoader::WorkerThreadableLoader(WorkerGlobalScope& workerGlobalSc
ope, ThreadableLoaderClient* client, const ThreadableLoaderOptions& options, con
st ResourceLoaderOptions& resourceLoaderOptions, BlockingBehavior blockingBehavi
or) | 59 } // namespace |
| 60 |
| 61 WorkerThreadableLoader::WorkerThreadableLoader( |
| 62 WorkerGlobalScope& workerGlobalScope, |
| 63 ThreadableLoaderClient* client, |
| 64 const ThreadableLoaderOptions& options, |
| 65 const ResourceLoaderOptions& resourceLoaderOptions, |
| 66 BlockingBehavior blockingBehavior) |
63 : m_workerGlobalScope(&workerGlobalScope) | 67 : m_workerGlobalScope(&workerGlobalScope) |
64 , m_workerClientWrapper(new ThreadableLoaderClientWrapper(workerGlobalScope,
client)) | 68 , m_workerClientWrapper(new ThreadableLoaderClientWrapper(workerGlobalScope,
client)) |
| 69 , m_bridge(new Bridge(m_workerClientWrapper, workerGlobalScope.thread()->wor
kerLoaderProxy(), options, resourceLoaderOptions, blockingBehavior)) |
65 { | 70 { |
66 if (blockingBehavior == LoadAsynchronously) { | |
67 m_bridge = new MainThreadAsyncBridge(workerGlobalScope, m_workerClientWr
apper, options, resourceLoaderOptions); | |
68 } else { | |
69 m_bridge = new MainThreadSyncBridge(workerGlobalScope, m_workerClientWra
pper, options, resourceLoaderOptions); | |
70 } | |
71 } | 71 } |
72 | 72 |
73 void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope& worker
GlobalScope, const ResourceRequest& request, ThreadableLoaderClient& client, con
st ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoader
Options) | 73 void WorkerThreadableLoader::loadResourceSynchronously(WorkerGlobalScope& worker
GlobalScope, const ResourceRequest& request, ThreadableLoaderClient& client, con
st ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoader
Options) |
74 { | 74 { |
75 std::unique_ptr<WorkerThreadableLoader> loader = wrapUnique(new WorkerThread
ableLoader(workerGlobalScope, &client, options, resourceLoaderOptions, LoadSynch
ronously)); | 75 std::unique_ptr<WorkerThreadableLoader> loader = wrapUnique(new WorkerThread
ableLoader(workerGlobalScope, &client, options, resourceLoaderOptions, LoadSynch
ronously)); |
76 loader->start(request); | 76 loader->start(request); |
77 } | 77 } |
78 | 78 |
79 WorkerThreadableLoader::~WorkerThreadableLoader() | 79 WorkerThreadableLoader::~WorkerThreadableLoader() |
80 { | 80 { |
81 m_bridge->destroy(); | 81 m_bridge->destroy(); |
82 m_bridge = nullptr; | |
83 } | 82 } |
84 | 83 |
85 void WorkerThreadableLoader::start(const ResourceRequest& request) | 84 void WorkerThreadableLoader::start(const ResourceRequest& request) |
86 { | 85 { |
87 ResourceRequest requestToPass(request); | 86 ResourceRequest requestToPass(request); |
88 if (!requestToPass.didSetHTTPReferrer()) | 87 if (!requestToPass.didSetHTTPReferrer()) |
89 requestToPass.setHTTPReferrer(SecurityPolicy::generateReferrer(m_workerG
lobalScope->getReferrerPolicy(), request.url(), m_workerGlobalScope->outgoingRef
errer())); | 88 requestToPass.setHTTPReferrer(SecurityPolicy::generateReferrer(m_workerG
lobalScope->getReferrerPolicy(), request.url(), m_workerGlobalScope->outgoingRef
errer())); |
90 m_bridge->start(requestToPass, *m_workerGlobalScope); | 89 m_bridge->start(requestToPass, *m_workerGlobalScope); |
91 } | 90 } |
92 | 91 |
93 void WorkerThreadableLoader::overrideTimeout(unsigned long timeoutMilliseconds) | 92 void WorkerThreadableLoader::overrideTimeout(unsigned long timeoutMilliseconds) |
94 { | 93 { |
95 ASSERT(m_bridge); | |
96 m_bridge->overrideTimeout(timeoutMilliseconds); | 94 m_bridge->overrideTimeout(timeoutMilliseconds); |
97 } | 95 } |
98 | 96 |
99 void WorkerThreadableLoader::cancel() | 97 void WorkerThreadableLoader::cancel() |
100 { | 98 { |
101 ASSERT(m_bridge); | |
102 m_bridge->cancel(); | 99 m_bridge->cancel(); |
103 } | 100 } |
104 | 101 |
105 WorkerThreadableLoader::MainThreadBridgeBase::MainThreadBridgeBase( | 102 WorkerThreadableLoader::AsyncTaskForwarder::AsyncTaskForwarder(PassRefPtr<Worker
LoaderProxy> loaderProxy) |
106 ThreadableLoaderClientWrapper* workerClientWrapper, | 103 : m_loaderProxy(loaderProxy) |
107 PassRefPtr<WorkerLoaderProxy> loaderProxy) | 104 { |
108 : m_workerClientWrapper(workerClientWrapper) | 105 DCHECK(isMainThread()); |
| 106 } |
| 107 |
| 108 WorkerThreadableLoader::AsyncTaskForwarder::~AsyncTaskForwarder() |
| 109 { |
| 110 DCHECK(isMainThread()); |
| 111 } |
| 112 |
| 113 void WorkerThreadableLoader::AsyncTaskForwarder::forwardTask(std::unique_ptr<Exe
cutionContextTask> task) |
| 114 { |
| 115 DCHECK(isMainThread()); |
| 116 m_loaderProxy->postTaskToWorkerGlobalScope(std::move(task)); |
| 117 } |
| 118 |
| 119 void WorkerThreadableLoader::AsyncTaskForwarder::forwardTaskWithDoneSignal(std::
unique_ptr<ExecutionContextTask> task) |
| 120 { |
| 121 DCHECK(isMainThread()); |
| 122 m_loaderProxy->postTaskToWorkerGlobalScope(std::move(task)); |
| 123 } |
| 124 |
| 125 void WorkerThreadableLoader::AsyncTaskForwarder::abort() |
| 126 { |
| 127 DCHECK(isMainThread()); |
| 128 } |
| 129 |
| 130 WorkerThreadableLoader::WaitableEventWithTasks::~WaitableEventWithTasks() {} |
| 131 |
| 132 void WorkerThreadableLoader::WaitableEventWithTasks::signal() |
| 133 { |
| 134 m_event.signal(); |
| 135 } |
| 136 |
| 137 void WorkerThreadableLoader::WaitableEventWithTasks::wait() |
| 138 { |
| 139 m_event.wait(); |
| 140 } |
| 141 |
| 142 Vector<std::unique_ptr<ExecutionContextTask>> WorkerThreadableLoader::WaitableEv
entWithTasks::take() |
| 143 { |
| 144 return std::move(m_tasks); |
| 145 } |
| 146 |
| 147 void WorkerThreadableLoader::WaitableEventWithTasks::append(std::unique_ptr<Exec
utionContextTask> task) |
| 148 { |
| 149 m_tasks.append(std::move(task)); |
| 150 } |
| 151 |
| 152 WorkerThreadableLoader::SyncTaskForwarder::SyncTaskForwarder(PassRefPtr<Waitable
EventWithTasks> eventWithTasks) |
| 153 : m_eventWithTasks(eventWithTasks) |
| 154 { |
| 155 DCHECK(isMainThread()); |
| 156 } |
| 157 |
| 158 WorkerThreadableLoader::SyncTaskForwarder::~SyncTaskForwarder() |
| 159 { |
| 160 DCHECK(isMainThread()); |
| 161 } |
| 162 |
| 163 void WorkerThreadableLoader::SyncTaskForwarder::forwardTask(std::unique_ptr<Exec
utionContextTask> task) |
| 164 { |
| 165 DCHECK(isMainThread()); |
| 166 m_eventWithTasks->append(std::move(task)); |
| 167 } |
| 168 |
| 169 void WorkerThreadableLoader::SyncTaskForwarder::forwardTaskWithDoneSignal(std::u
nique_ptr<ExecutionContextTask> task) |
| 170 { |
| 171 DCHECK(isMainThread()); |
| 172 m_eventWithTasks->append(std::move(task)); |
| 173 m_eventWithTasks->signal(); |
| 174 } |
| 175 |
| 176 void WorkerThreadableLoader::SyncTaskForwarder::abort() |
| 177 { |
| 178 DCHECK(isMainThread()); |
| 179 m_eventWithTasks->setIsAborted(); |
| 180 m_eventWithTasks->signal(); |
| 181 } |
| 182 |
| 183 WorkerThreadableLoader::Bridge::Bridge( |
| 184 ThreadableLoaderClientWrapper* clientWrapper, |
| 185 PassRefPtr<WorkerLoaderProxy> loaderProxy, |
| 186 const ThreadableLoaderOptions& threadableLoaderOptions, |
| 187 const ResourceLoaderOptions& resourceLoaderOptions, |
| 188 BlockingBehavior blockingBehavior) |
| 189 : m_clientWrapper(clientWrapper) |
109 , m_loaderProxy(loaderProxy) | 190 , m_loaderProxy(loaderProxy) |
110 { | 191 , m_threadableLoaderOptions(threadableLoaderOptions) |
111 ASSERT(m_workerClientWrapper.get()); | 192 , m_resourceLoaderOptions(resourceLoaderOptions) |
112 ASSERT(m_loaderProxy.get()); | 193 , m_blockingBehavior(blockingBehavior) |
113 } | 194 { |
114 | 195 DCHECK(!isMainThread()); |
115 WorkerThreadableLoader::MainThreadBridgeBase::~MainThreadBridgeBase() | 196 } |
116 { | 197 |
117 } | 198 WorkerThreadableLoader::Bridge::~Bridge() |
118 | 199 { |
119 void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadCreateLoader(Thread
ableLoaderOptions options, ResourceLoaderOptions resourceLoaderOptions, Executio
nContext* context) | 200 DCHECK(!isMainThread()); |
120 { | 201 DCHECK(!m_peer); |
121 ASSERT(isMainThread()); | 202 } |
122 Document* document = toDocument(context); | 203 |
123 | 204 void WorkerThreadableLoader::Bridge::start(const ResourceRequest& request, const
WorkerGlobalScope& workerGlobalScope) |
124 resourceLoaderOptions.requestInitiatorContext = WorkerContext; | 205 { |
125 m_mainThreadLoader = DocumentThreadableLoader::create(*document, this, optio
ns, resourceLoaderOptions); | 206 DCHECK(!isMainThread()); |
126 ASSERT(m_mainThreadLoader); | 207 RefPtr<WaitableEventWithTasks> eventWithTasks; |
127 } | 208 if (m_blockingBehavior == LoadSynchronously) |
128 | 209 eventWithTasks = WaitableEventWithTasks::create(); |
129 void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadStart(std::unique_p
tr<CrossThreadResourceRequestData> requestData) | 210 |
130 { | 211 m_loaderProxy->postTaskToLoader(createCrossThreadTask( |
131 ASSERT(isMainThread()); | 212 &Peer::createAndStart, |
132 ASSERT(m_mainThreadLoader); | 213 CrossThreadPersistent<Bridge>(this), |
133 m_mainThreadLoader->start(ResourceRequest(requestData.get())); | 214 m_loaderProxy, |
134 } | 215 CrossThreadPersistent<WorkerThreadLifecycleContext>(workerGlobalScope.th
read()->getWorkerThreadLifecycleContext()), |
135 | 216 request, |
136 void WorkerThreadableLoader::MainThreadBridgeBase::createLoaderInMainThread(cons
t ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderO
ptions) | 217 threadableLoaderOptions(), |
137 { | 218 resourceLoaderOptions(), |
138 m_loaderProxy->postTaskToLoader(createCrossThreadTask(&MainThreadBridgeBase:
:mainThreadCreateLoader, crossThreadUnretained(this), options, resourceLoaderOpt
ions)); | 219 eventWithTasks)); |
139 } | 220 |
140 | 221 if (m_blockingBehavior == LoadAsynchronously) |
141 void WorkerThreadableLoader::MainThreadBridgeBase::startInMainThread(const Resou
rceRequest& request, const WorkerGlobalScope& workerGlobalScope) | 222 return; |
142 { | 223 |
143 loaderProxy()->postTaskToLoader(createCrossThreadTask(&MainThreadBridgeBase:
:mainThreadStart, crossThreadUnretained(this), request)); | 224 { |
144 } | 225 SafePointScope scope(BlinkGC::HeapPointersOnStack); |
145 | 226 eventWithTasks->wait(); |
146 void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadDestroy(ExecutionCo
ntext* context) | |
147 { | |
148 ASSERT(isMainThread()); | |
149 ASSERT_UNUSED(context, context->isDocument()); | |
150 delete this; | |
151 } | |
152 | |
153 void WorkerThreadableLoader::MainThreadBridgeBase::destroy() | |
154 { | |
155 // Ensure that no more client callbacks are done in the worker context's | |
156 // thread. | |
157 // ThreadableLoaderClientWrapper is an on-heap class and this function can | |
158 // be called in the finalization step but it is safe because | |
159 // m_workerClientWrapper is a CrossThreadPersistent. | |
160 m_workerClientWrapper->clearClient(); | |
161 | |
162 // "delete this" and m_mainThreadLoader::deref() on the worker object's | |
163 // thread. | |
164 m_loaderProxy->postTaskToLoader(createCrossThreadTask(&MainThreadBridgeBase:
:mainThreadDestroy, crossThreadUnretained(this))); | |
165 } | |
166 | |
167 void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadOverrideTimeout(uns
igned long timeoutMilliseconds, ExecutionContext* context) | |
168 { | |
169 ASSERT(isMainThread()); | |
170 ASSERT_UNUSED(context, context->isDocument()); | |
171 | |
172 if (!m_mainThreadLoader) | |
173 return; | |
174 m_mainThreadLoader->overrideTimeout(timeoutMilliseconds); | |
175 } | |
176 | |
177 void WorkerThreadableLoader::MainThreadBridgeBase::overrideTimeout(unsigned long
timeoutMilliseconds) | |
178 { | |
179 m_loaderProxy->postTaskToLoader(createCrossThreadTask(&MainThreadBridgeBase:
:mainThreadOverrideTimeout, crossThreadUnretained(this), timeoutMilliseconds)); | |
180 } | |
181 | |
182 void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadCancel(ExecutionCon
text* context) | |
183 { | |
184 ASSERT(isMainThread()); | |
185 ASSERT_UNUSED(context, context->isDocument()); | |
186 | |
187 if (!m_mainThreadLoader) | |
188 return; | |
189 m_mainThreadLoader->cancel(); | |
190 m_mainThreadLoader = nullptr; | |
191 } | |
192 | |
193 void WorkerThreadableLoader::MainThreadBridgeBase::cancel() | |
194 { | |
195 m_loaderProxy->postTaskToLoader(createCrossThreadTask(&MainThreadBridgeBase:
:mainThreadCancel, crossThreadUnretained(this))); | |
196 ThreadableLoaderClientWrapper* clientWrapper = m_workerClientWrapper; | |
197 if (!clientWrapper->done()) { | |
198 // If the client hasn't reached a termination state, then transition it | |
199 // by sending a cancellation error. | |
200 // Note: no more client callbacks will be done after this method -- the | |
201 // m_workerClientWrapper->clearClient() call ensures that. | |
202 ResourceError error(String(), 0, String(), String()); | |
203 error.setIsCancellation(true); | |
204 clientWrapper->didFail(error); | |
205 } | 227 } |
206 // |this| might be already destructed here because didFail() might | 228 |
207 // clear a reference to ThreadableLoader, which might destruct | 229 if (eventWithTasks->isAborted()) { |
208 // WorkerThreadableLoader and then MainThreadBridge. | 230 // This thread is going to terminate. |
209 // Therefore we call clearClient() directly, rather than calling | 231 cancel(); |
210 // this->m_workerClientWrapper->clearClient(). | 232 return; |
211 clientWrapper->clearClient(); | |
212 } | |
213 | |
214 void WorkerThreadableLoader::MainThreadBridgeBase::didSendData(unsigned long lon
g bytesSent, unsigned long long totalBytesToBeSent) | |
215 { | |
216 forwardTaskToWorker(createCrossThreadTask(&ThreadableLoaderClientWrapper::di
dSendData, m_workerClientWrapper, bytesSent, totalBytesToBeSent)); | |
217 } | |
218 | |
219 void WorkerThreadableLoader::MainThreadBridgeBase::didReceiveResponse(unsigned l
ong identifier, const ResourceResponse& response, std::unique_ptr<WebDataConsume
rHandle> handle) | |
220 { | |
221 forwardTaskToWorker(createCrossThreadTask(&ThreadableLoaderClientWrapper::di
dReceiveResponse, m_workerClientWrapper, identifier, response, passed(std::move(
handle)))); | |
222 } | |
223 | |
224 void WorkerThreadableLoader::MainThreadBridgeBase::didReceiveData(const char* da
ta, unsigned dataLength) | |
225 { | |
226 forwardTaskToWorker(createCrossThreadTask(&ThreadableLoaderClientWrapper::di
dReceiveData, m_workerClientWrapper, passed(createVectorFromMemoryRegion(data, d
ataLength)))); | |
227 } | |
228 | |
229 void WorkerThreadableLoader::MainThreadBridgeBase::didDownloadData(int dataLengt
h) | |
230 { | |
231 forwardTaskToWorker(createCrossThreadTask(&ThreadableLoaderClientWrapper::di
dDownloadData, m_workerClientWrapper, dataLength)); | |
232 } | |
233 | |
234 void WorkerThreadableLoader::MainThreadBridgeBase::didReceiveCachedMetadata(cons
t char* data, int dataLength) | |
235 { | |
236 forwardTaskToWorker(createCrossThreadTask(&ThreadableLoaderClientWrapper::di
dReceiveCachedMetadata, m_workerClientWrapper, passed(createVectorFromMemoryRegi
on(data, dataLength)))); | |
237 } | |
238 | |
239 void WorkerThreadableLoader::MainThreadBridgeBase::didFinishLoading(unsigned lon
g identifier, double finishTime) | |
240 { | |
241 forwardTaskToWorkerOnLoaderDone(createCrossThreadTask(&ThreadableLoaderClien
tWrapper::didFinishLoading, m_workerClientWrapper, identifier, finishTime)); | |
242 } | |
243 | |
244 void WorkerThreadableLoader::MainThreadBridgeBase::didFail(const ResourceError&
error) | |
245 { | |
246 forwardTaskToWorkerOnLoaderDone(createCrossThreadTask(&ThreadableLoaderClien
tWrapper::didFail, m_workerClientWrapper, error)); | |
247 } | |
248 | |
249 void WorkerThreadableLoader::MainThreadBridgeBase::didFailAccessControlCheck(con
st ResourceError& error) | |
250 { | |
251 forwardTaskToWorkerOnLoaderDone(createCrossThreadTask(&ThreadableLoaderClien
tWrapper::didFailAccessControlCheck, m_workerClientWrapper, error)); | |
252 } | |
253 | |
254 void WorkerThreadableLoader::MainThreadBridgeBase::didFailRedirectCheck() | |
255 { | |
256 forwardTaskToWorkerOnLoaderDone(createCrossThreadTask(&ThreadableLoaderClien
tWrapper::didFailRedirectCheck, m_workerClientWrapper)); | |
257 } | |
258 | |
259 void WorkerThreadableLoader::MainThreadBridgeBase::didReceiveResourceTiming(cons
t ResourceTimingInfo& info) | |
260 { | |
261 forwardTaskToWorker(createCrossThreadTask(&ThreadableLoaderClientWrapper::di
dReceiveResourceTiming, m_workerClientWrapper, info)); | |
262 } | |
263 | |
264 WorkerThreadableLoader::MainThreadAsyncBridge::MainThreadAsyncBridge( | |
265 WorkerGlobalScope& workerGlobalScope, | |
266 ThreadableLoaderClientWrapper* workerClientWrapper, | |
267 const ThreadableLoaderOptions& options, | |
268 const ResourceLoaderOptions& resourceLoaderOptions) | |
269 : MainThreadBridgeBase(workerClientWrapper, workerGlobalScope.thread()->work
erLoaderProxy()) | |
270 { | |
271 createLoaderInMainThread(options, resourceLoaderOptions); | |
272 } | |
273 | |
274 void WorkerThreadableLoader::MainThreadAsyncBridge::start(const ResourceRequest&
request, const WorkerGlobalScope& workerGlobalScope) | |
275 { | |
276 startInMainThread(request, workerGlobalScope); | |
277 } | |
278 | |
279 WorkerThreadableLoader::MainThreadAsyncBridge::~MainThreadAsyncBridge() | |
280 { | |
281 } | |
282 | |
283 void WorkerThreadableLoader::MainThreadAsyncBridge::forwardTaskToWorker(std::uni
que_ptr<ExecutionContextTask> task) | |
284 { | |
285 loaderProxy()->postTaskToWorkerGlobalScope(std::move(task)); | |
286 } | |
287 | |
288 void WorkerThreadableLoader::MainThreadAsyncBridge::forwardTaskToWorkerOnLoaderD
one(std::unique_ptr<ExecutionContextTask> task) | |
289 { | |
290 loaderProxy()->postTaskToWorkerGlobalScope(std::move(task)); | |
291 } | |
292 | |
293 WorkerThreadableLoader::MainThreadSyncBridge::MainThreadSyncBridge( | |
294 WorkerGlobalScope& workerGlobalScope, | |
295 ThreadableLoaderClientWrapper* workerClientWrapper, | |
296 const ThreadableLoaderOptions& options, | |
297 const ResourceLoaderOptions& resourceLoaderOptions) | |
298 : MainThreadBridgeBase(workerClientWrapper, workerGlobalScope.thread()->work
erLoaderProxy()) | |
299 , m_done(false) | |
300 { | |
301 createLoaderInMainThread(options, resourceLoaderOptions); | |
302 } | |
303 | |
304 void WorkerThreadableLoader::MainThreadSyncBridge::start(const ResourceRequest&
request, const WorkerGlobalScope& workerGlobalScope) | |
305 { | |
306 WaitableEvent* terminationEvent = workerGlobalScope.thread()->terminationEve
nt(); | |
307 m_loaderDoneEvent = wrapUnique(new WaitableEvent()); | |
308 | |
309 startInMainThread(request, workerGlobalScope); | |
310 | |
311 size_t signaledIndex; | |
312 { | |
313 Vector<WaitableEvent*> events; | |
314 // Order is important; indicies are used later. | |
315 events.append(terminationEvent); | |
316 events.append(m_loaderDoneEvent.get()); | |
317 | |
318 SafePointScope scope(BlinkGC::HeapPointersOnStack); | |
319 signaledIndex = WaitableEvent::waitMultiple(events); | |
320 } | 233 } |
321 // |signaledIndex| is 0; which is terminationEvent. | 234 |
322 if (signaledIndex == 0) { | 235 for (const auto& task : eventWithTasks->take()) { |
323 cancel(); | |
324 return; | |
325 } | |
326 | |
327 // The following code must be run only after |m_loaderDoneEvent| is | |
328 // signalled. | |
329 | |
330 Vector<std::unique_ptr<ExecutionContextTask>> tasks; | |
331 { | |
332 MutexLocker lock(m_lock); | |
333 ASSERT(m_done); | |
334 m_clientTasks.swap(tasks); | |
335 } | |
336 for (const auto& task : tasks) { | |
337 // m_clientTask contains only CallClosureTasks. So, it's ok to pass | 236 // m_clientTask contains only CallClosureTasks. So, it's ok to pass |
338 // the nullptr. | 237 // the nullptr. |
339 task->performTask(nullptr); | 238 task->performTask(nullptr); |
340 } | 239 } |
341 } | 240 } |
342 | 241 |
343 WorkerThreadableLoader::MainThreadSyncBridge::~MainThreadSyncBridge() | 242 void WorkerThreadableLoader::Bridge::overrideTimeout(unsigned long timeoutMillis
econds) |
344 { | 243 { |
345 ASSERT(isMainThread()); | 244 DCHECK(!isMainThread()); |
346 } | 245 if (!m_peer) |
347 | 246 return; |
348 void WorkerThreadableLoader::MainThreadSyncBridge::forwardTaskToWorker(std::uniq
ue_ptr<ExecutionContextTask> task) | 247 m_loaderProxy->postTaskToLoader(createCrossThreadTask(&Peer::overrideTimeout
, m_peer, timeoutMilliseconds)); |
349 { | 248 } |
350 ASSERT(isMainThread()); | 249 |
351 | 250 void WorkerThreadableLoader::Bridge::cancel() |
352 MutexLocker lock(m_lock); | 251 { |
353 RELEASE_ASSERT(!m_done); | 252 DCHECK(!isMainThread()); |
354 | 253 if (!m_peer) |
355 m_clientTasks.append(std::move(task)); | 254 return; |
356 } | 255 m_loaderProxy->postTaskToLoader(createCrossThreadTask(&Peer::cancel, m_peer)
); |
357 | 256 m_peer = nullptr; |
358 void WorkerThreadableLoader::MainThreadSyncBridge::forwardTaskToWorkerOnLoaderDo
ne(std::unique_ptr<ExecutionContextTask> task) | 257 |
359 { | 258 auto clientWrapper = m_clientWrapper.get(); |
360 ASSERT(isMainThread()); | 259 |
361 | 260 if (clientWrapper->done()) |
362 MutexLocker lock(m_lock); | 261 return; |
363 RELEASE_ASSERT(!m_done); | 262 // If the client hasn't reached a termination state, then transition it |
364 | 263 // by sending a cancellation error. |
365 m_clientTasks.append(std::move(task)); | 264 // Note: no more client callbacks will be done after this method -- the |
366 m_done = true; | 265 // clearClient() call ensures that. |
367 m_loaderDoneEvent->signal(); | 266 ResourceError error(String(), 0, String(), String()); |
| 267 error.setIsCancellation(true); |
| 268 clientWrapper->didFail(error); |
| 269 clientWrapper->clearClient(); |
| 270 } |
| 271 |
| 272 void WorkerThreadableLoader::Bridge::destroy() |
| 273 { |
| 274 DCHECK(!isMainThread()); |
| 275 m_clientWrapper->clearClient(); |
| 276 if (!m_peer) |
| 277 return; |
| 278 m_loaderProxy->postTaskToLoader(createCrossThreadTask(&Peer::cancel, m_peer)
); |
| 279 m_peer = nullptr; |
| 280 } |
| 281 |
| 282 void WorkerThreadableLoader::Bridge::didStart(Peer* peer) |
| 283 { |
| 284 DCHECK(!isMainThread()); |
| 285 DCHECK(!m_peer); |
| 286 DCHECK(peer); |
| 287 m_peer = peer; |
| 288 } |
| 289 |
| 290 DEFINE_TRACE(WorkerThreadableLoader::Bridge) |
| 291 { |
| 292 visitor->trace(m_clientWrapper); |
| 293 } |
| 294 |
| 295 void WorkerThreadableLoader::Peer::createAndStart( |
| 296 Bridge* bridge, |
| 297 PassRefPtr<WorkerLoaderProxy> passLoaderProxy, |
| 298 WorkerThreadLifecycleContext* workerThreadLifecycleContext, |
| 299 std::unique_ptr<CrossThreadResourceRequestData> request, |
| 300 const ThreadableLoaderOptions& options, |
| 301 const ResourceLoaderOptions& resourceLoaderOptions, |
| 302 PassRefPtr<WaitableEventWithTasks> eventWithTasks, |
| 303 ExecutionContext* executionContext) |
| 304 { |
| 305 DCHECK(isMainThread()); |
| 306 TaskForwarder* forwarder; |
| 307 RefPtr<WorkerLoaderProxy> loaderProxy = passLoaderProxy; |
| 308 if (eventWithTasks) |
| 309 forwarder = new SyncTaskForwarder(eventWithTasks); |
| 310 else |
| 311 forwarder = new AsyncTaskForwarder(loaderProxy); |
| 312 |
| 313 Peer* peer = new Peer(forwarder, workerThreadLifecycleContext); |
| 314 if (peer->wasContextDestroyedBeforeObserverCreation()) { |
| 315 // The thread is already terminating. |
| 316 forwarder->abort(); |
| 317 return; |
| 318 } |
| 319 peer->m_clientWrapper = bridge->clientWrapper(); |
| 320 peer->start(*toDocument(executionContext), std::move(request), options, reso
urceLoaderOptions); |
| 321 forwarder->forwardTask(createCrossThreadTask(&Bridge::didStart, CrossThreadP
ersistent<Bridge>(bridge), CrossThreadPersistent<Peer>(peer))); |
| 322 } |
| 323 |
| 324 WorkerThreadableLoader::Peer::~Peer() |
| 325 { |
| 326 DCHECK(isMainThread()); |
| 327 DCHECK(!m_mainThreadLoader); |
| 328 } |
| 329 |
| 330 void WorkerThreadableLoader::Peer::overrideTimeout(unsigned long timeoutMillisec
onds) |
| 331 { |
| 332 DCHECK(isMainThread()); |
| 333 if (!m_mainThreadLoader) |
| 334 return; |
| 335 m_mainThreadLoader->overrideTimeout(timeoutMilliseconds); |
| 336 } |
| 337 |
| 338 void WorkerThreadableLoader::Peer::cancel() |
| 339 { |
| 340 DCHECK(isMainThread()); |
| 341 if (!m_mainThreadLoader) |
| 342 return; |
| 343 m_mainThreadLoader->cancel(); |
| 344 m_mainThreadLoader = nullptr; |
| 345 } |
| 346 |
| 347 void WorkerThreadableLoader::Peer::didSendData(unsigned long long bytesSent, uns
igned long long totalBytesToBeSent) |
| 348 { |
| 349 DCHECK(isMainThread()); |
| 350 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 351 if (!clientWrapper) |
| 352 return; |
| 353 m_forwarder->forwardTask(createCrossThreadTask(&ThreadableLoaderClientWrappe
r::didSendData, clientWrapper, bytesSent, totalBytesToBeSent)); |
| 354 } |
| 355 |
| 356 void WorkerThreadableLoader::Peer::didReceiveResponse(unsigned long identifier,
const ResourceResponse& response, std::unique_ptr<WebDataConsumerHandle> handle) |
| 357 { |
| 358 DCHECK(isMainThread()); |
| 359 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 360 if (!clientWrapper) |
| 361 return; |
| 362 m_forwarder->forwardTask(createCrossThreadTask(&ThreadableLoaderClientWrappe
r::didReceiveResponse, clientWrapper, identifier, response, passed(std::move(han
dle)))); |
| 363 } |
| 364 |
| 365 void WorkerThreadableLoader::Peer::didReceiveData(const char* data, unsigned dat
aLength) |
| 366 { |
| 367 DCHECK(isMainThread()); |
| 368 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 369 if (!clientWrapper) |
| 370 return; |
| 371 m_forwarder->forwardTask(createCrossThreadTask(&ThreadableLoaderClientWrappe
r::didReceiveData, clientWrapper, passed(createVectorFromMemoryRegion(data, data
Length)))); |
| 372 } |
| 373 |
| 374 void WorkerThreadableLoader::Peer::didDownloadData(int dataLength) |
| 375 { |
| 376 DCHECK(isMainThread()); |
| 377 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 378 if (!clientWrapper) |
| 379 return; |
| 380 m_forwarder->forwardTask(createCrossThreadTask(&ThreadableLoaderClientWrappe
r::didDownloadData, clientWrapper, dataLength)); |
| 381 } |
| 382 |
| 383 void WorkerThreadableLoader::Peer::didReceiveCachedMetadata(const char* data, in
t dataLength) |
| 384 { |
| 385 DCHECK(isMainThread()); |
| 386 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 387 if (!clientWrapper) |
| 388 return; |
| 389 m_forwarder->forwardTask(createCrossThreadTask(&ThreadableLoaderClientWrappe
r::didReceiveCachedMetadata, clientWrapper, passed(createVectorFromMemoryRegion(
data, dataLength)))); |
| 390 } |
| 391 |
| 392 void WorkerThreadableLoader::Peer::didFinishLoading(unsigned long identifier, do
uble finishTime) |
| 393 { |
| 394 DCHECK(isMainThread()); |
| 395 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 396 if (!clientWrapper) |
| 397 return; |
| 398 m_forwarder->forwardTaskWithDoneSignal(createCrossThreadTask(&ThreadableLoad
erClientWrapper::didFinishLoading, clientWrapper, identifier, finishTime)); |
| 399 } |
| 400 |
| 401 void WorkerThreadableLoader::Peer::didFail(const ResourceError& error) |
| 402 { |
| 403 DCHECK(isMainThread()); |
| 404 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 405 if (!clientWrapper) |
| 406 return; |
| 407 m_forwarder->forwardTaskWithDoneSignal(createCrossThreadTask(&ThreadableLoad
erClientWrapper::didFail, clientWrapper, error)); |
| 408 } |
| 409 |
| 410 void WorkerThreadableLoader::Peer::didFailAccessControlCheck(const ResourceError
& error) |
| 411 { |
| 412 DCHECK(isMainThread()); |
| 413 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 414 if (!clientWrapper) |
| 415 return; |
| 416 m_forwarder->forwardTaskWithDoneSignal(createCrossThreadTask(&ThreadableLoad
erClientWrapper::didFailAccessControlCheck, clientWrapper, error)); |
| 417 } |
| 418 |
| 419 void WorkerThreadableLoader::Peer::didFailRedirectCheck() |
| 420 { |
| 421 DCHECK(isMainThread()); |
| 422 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 423 if (!clientWrapper) |
| 424 return; |
| 425 m_forwarder->forwardTaskWithDoneSignal(createCrossThreadTask(&ThreadableLoad
erClientWrapper::didFailRedirectCheck, clientWrapper)); |
| 426 } |
| 427 |
| 428 void WorkerThreadableLoader::Peer::didReceiveResourceTiming(const ResourceTiming
Info& info) |
| 429 { |
| 430 DCHECK(isMainThread()); |
| 431 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien
tWrapper.get(); |
| 432 if (!clientWrapper) |
| 433 return; |
| 434 m_forwarder->forwardTask(createCrossThreadTask(&ThreadableLoaderClientWrappe
r::didReceiveResourceTiming, clientWrapper, info)); |
| 435 } |
| 436 |
| 437 void WorkerThreadableLoader::Peer::contextDestroyed() |
| 438 { |
| 439 DCHECK(isMainThread()); |
| 440 m_forwarder->abort(); |
| 441 m_clientWrapper = nullptr; |
| 442 cancel(); |
| 443 } |
| 444 |
| 445 DEFINE_TRACE(WorkerThreadableLoader::Peer) |
| 446 { |
| 447 visitor->trace(m_forwarder); |
| 448 WorkerThreadLifecycleObserver::trace(visitor); |
| 449 } |
| 450 |
| 451 WorkerThreadableLoader::Peer::Peer(TaskForwarder* forwarder, WorkerThreadLifecyc
leContext* context) |
| 452 : WorkerThreadLifecycleObserver(context) |
| 453 , m_forwarder(forwarder) |
| 454 { |
| 455 DCHECK(isMainThread()); |
| 456 } |
| 457 |
| 458 void WorkerThreadableLoader::Peer::start( |
| 459 Document& document, |
| 460 std::unique_ptr<CrossThreadResourceRequestData> request, |
| 461 const ThreadableLoaderOptions& options, |
| 462 const ResourceLoaderOptions& originalResourceLoaderOptions) |
| 463 { |
| 464 DCHECK(isMainThread()); |
| 465 ResourceLoaderOptions resourceLoaderOptions = originalResourceLoaderOptions; |
| 466 resourceLoaderOptions.requestInitiatorContext = WorkerContext; |
| 467 m_mainThreadLoader = DocumentThreadableLoader::create(document, this, option
s, resourceLoaderOptions); |
| 468 m_mainThreadLoader->start(ResourceRequest(request.get())); |
368 } | 469 } |
369 | 470 |
370 } // namespace blink | 471 } // namespace blink |
OLD | NEW |