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