Chromium Code Reviews| 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() |
|
haraken
2016/07/21 10:22:29
Is it guaranteed that WorkerThreadableLoader gets
yhirano
2016/07/21 10:56:09
No, it's not guaranteed. I thought that calling de
| |
| 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(); | |
|
haraken
2016/07/21 10:22:29
Don't we need to add:
SafePointScope scope(Blin
yhirano
2016/07/21 10:56:08
I placed at the call site. Do you think here is th
| |
| 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 } |
|
haraken
2016/07/21 10:22:29
Can we add DCHECK(!m_peer)?
yhirano
2016/07/21 11:44:55
Done.
yhirano
2016/07/21 15:06:27
memo: this breaks a test because didStart may be c
| |
| 121 ASSERT(isMainThread()); | 202 |
| 122 Document* document = toDocument(context); | 203 void WorkerThreadableLoader::Bridge::start(const ResourceRequest& request, const WorkerGlobalScope& workerGlobalScope) |
| 123 | 204 { |
| 124 resourceLoaderOptions.requestInitiatorContext = WorkerContext; | 205 DCHECK(!isMainThread()); |
| 125 m_mainThreadLoader = DocumentThreadableLoader::create(*document, this, optio ns, resourceLoaderOptions); | 206 RefPtr<WaitableEventWithTasks> eventWithTasks; |
| 126 ASSERT(m_mainThreadLoader); | 207 if (m_blockingBehavior == LoadSynchronously) |
| 127 } | 208 eventWithTasks = WaitableEventWithTasks::create(); |
| 128 | 209 |
| 129 void WorkerThreadableLoader::MainThreadBridgeBase::mainThreadStart(std::unique_p tr<CrossThreadResourceRequestData> requestData) | 210 m_loaderProxy->postTaskToLoader(createCrossThreadTask( |
| 130 { | 211 &Peer::createAndStart, |
| 131 ASSERT(isMainThread()); | 212 CrossThreadPersistent<Bridge>(this), |
| 132 ASSERT(m_mainThreadLoader); | 213 m_loaderProxy, |
| 133 m_mainThreadLoader->start(ResourceRequest(requestData.get())); | 214 CrossThreadPersistent<WorkerThreadLifecycleContext>(workerGlobalScope.th read()->getWorkerThreadLifecycleContext()), |
| 134 } | 215 request, |
| 135 | 216 threadableLoaderOptions(), |
| 136 void WorkerThreadableLoader::MainThreadBridgeBase::createLoaderInMainThread(cons t ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderO ptions) | 217 resourceLoaderOptions(), |
| 137 { | 218 eventWithTasks)); |
| 138 m_loaderProxy->postTaskToLoader(createCrossThreadTask(&MainThreadBridgeBase: :mainThreadCreateLoader, crossThreadUnretained(this), options, resourceLoaderOpt ions)); | 219 |
| 139 } | 220 if (m_blockingBehavior == LoadAsynchronously) |
| 140 | 221 return; |
| 141 void WorkerThreadableLoader::MainThreadBridgeBase::startInMainThread(const Resou rceRequest& request, const WorkerGlobalScope& workerGlobalScope) | 222 |
| 142 { | 223 { |
| 143 loaderProxy()->postTaskToLoader(createCrossThreadTask(&MainThreadBridgeBase: :mainThreadStart, crossThreadUnretained(this), request)); | 224 SafePointScope scope(BlinkGC::HeapPointersOnStack); |
| 144 } | 225 eventWithTasks->wait(); |
| 145 | |
| 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 } | 226 } |
| 206 // |this| might be already destructed here because didFail() might | 227 |
| 207 // clear a reference to ThreadableLoader, which might destruct | 228 if (eventWithTasks->isAborted()) { |
| 208 // WorkerThreadableLoader and then MainThreadBridge. | 229 // This thread is going to terminate. |
| 209 // Therefore we call clearClient() directly, rather than calling | 230 cancel(); |
| 210 // this->m_workerClientWrapper->clearClient(). | 231 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 } | 232 } |
| 321 // |signaledIndex| is 0; which is terminationEvent. | 233 |
| 322 if (signaledIndex == 0) { | 234 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 | 235 // m_clientTask contains only CallClosureTasks. So, it's ok to pass |
| 338 // the nullptr. | 236 // the nullptr. |
| 339 task->performTask(nullptr); | 237 task->performTask(nullptr); |
| 340 } | 238 } |
| 341 } | 239 } |
| 342 | 240 |
| 343 WorkerThreadableLoader::MainThreadSyncBridge::~MainThreadSyncBridge() | 241 void WorkerThreadableLoader::Bridge::overrideTimeout(unsigned long timeoutMillis econds) |
| 344 { | 242 { |
| 345 ASSERT(isMainThread()); | 243 DCHECK(!isMainThread()); |
| 346 } | 244 if (!m_peer) |
| 347 | 245 return; |
| 348 void WorkerThreadableLoader::MainThreadSyncBridge::forwardTaskToWorker(std::uniq ue_ptr<ExecutionContextTask> task) | 246 m_loaderProxy->postTaskToLoader(createCrossThreadTask(&Peer::overrideTimeout , m_peer, timeoutMilliseconds)); |
| 349 { | 247 } |
| 350 ASSERT(isMainThread()); | 248 |
| 351 | 249 void WorkerThreadableLoader::Bridge::cancel() |
| 352 MutexLocker lock(m_lock); | 250 { |
| 353 RELEASE_ASSERT(!m_done); | 251 DCHECK(!isMainThread()); |
| 354 | 252 if (!m_peer) |
| 355 m_clientTasks.append(std::move(task)); | 253 return; |
| 356 } | 254 m_loaderProxy->postTaskToLoader(createCrossThreadTask(&Peer::cancel, m_peer) ); |
| 357 | 255 m_peer = nullptr; |
| 358 void WorkerThreadableLoader::MainThreadSyncBridge::forwardTaskToWorkerOnLoaderDo ne(std::unique_ptr<ExecutionContextTask> task) | 256 |
| 359 { | 257 auto clientWrapper = m_clientWrapper.get(); |
| 360 ASSERT(isMainThread()); | 258 |
| 361 | 259 if (clientWrapper->done()) |
| 362 MutexLocker lock(m_lock); | 260 return; |
| 363 RELEASE_ASSERT(!m_done); | 261 // If the client hasn't reached a termination state, then transition it |
| 364 | 262 // by sending a cancellation error. |
| 365 m_clientTasks.append(std::move(task)); | 263 // Note: no more client callbacks will be done after this method -- the |
| 366 m_done = true; | 264 // clearClient() call ensures that. |
| 367 m_loaderDoneEvent->signal(); | 265 ResourceError error(String(), 0, String(), String()); |
| 266 error.setIsCancellation(true); | |
| 267 clientWrapper->didFail(error); | |
| 268 clientWrapper->clearClient(); | |
| 269 } | |
| 270 | |
| 271 void WorkerThreadableLoader::Bridge::destroy() | |
| 272 { | |
| 273 DCHECK(!isMainThread()); | |
| 274 m_clientWrapper->clearClient(); | |
| 275 if (!m_peer) | |
| 276 return; | |
| 277 m_loaderProxy->postTaskToLoader(createCrossThreadTask(&Peer::cancel, m_peer) ); | |
| 278 m_peer = nullptr; | |
| 279 } | |
| 280 | |
| 281 void WorkerThreadableLoader::Bridge::didStart(Peer* peer) | |
| 282 { | |
| 283 DCHECK(!isMainThread()); | |
| 284 DCHECK(!m_peer); | |
| 285 DCHECK(peer); | |
| 286 m_peer = peer; | |
| 287 } | |
| 288 | |
| 289 DEFINE_TRACE(WorkerThreadableLoader::Bridge) | |
| 290 { | |
| 291 visitor->trace(m_clientWrapper); | |
| 292 } | |
| 293 | |
| 294 void WorkerThreadableLoader::Peer::createAndStart( | |
| 295 Bridge* bridge, | |
| 296 PassRefPtr<WorkerLoaderProxy> passLoaderProxy, | |
| 297 WorkerThreadLifecycleContext* workerThreadLifecycleContext, | |
| 298 std::unique_ptr<CrossThreadResourceRequestData> request, | |
| 299 const ThreadableLoaderOptions& options, | |
| 300 const ResourceLoaderOptions& resourceLoaderOptions, | |
| 301 PassRefPtr<WaitableEventWithTasks> eventWithTasks, | |
| 302 ExecutionContext* executionContext) | |
| 303 { | |
| 304 DCHECK(isMainThread()); | |
| 305 TaskForwarder* forwarder; | |
| 306 RefPtr<WorkerLoaderProxy> loaderProxy = passLoaderProxy; | |
| 307 if (eventWithTasks) | |
| 308 forwarder = new SyncTaskForwarder(eventWithTasks); | |
| 309 else | |
| 310 forwarder = new AsyncTaskForwarder(loaderProxy); | |
| 311 | |
| 312 Peer* peer = new Peer(forwarder, workerThreadLifecycleContext); | |
| 313 if (peer->wasContextDestroyedBeforeObserverCreation()) { | |
| 314 // The thread is already terminating. | |
| 315 forwarder->abort(); | |
| 316 return; | |
| 317 } | |
| 318 peer->m_clientWrapper = bridge->clientWrapper(); | |
| 319 peer->start(*toDocument(executionContext), std::move(request), options, reso urceLoaderOptions); | |
| 320 forwarder->forwardTask(createCrossThreadTask(&Bridge::didStart, CrossThreadP ersistent<Bridge>(bridge), CrossThreadPersistent<Peer>(peer))); | |
| 321 } | |
| 322 | |
| 323 WorkerThreadableLoader::Peer::~Peer() | |
| 324 { | |
| 325 DCHECK(isMainThread()); | |
| 326 DCHECK(!m_mainThreadLoader); | |
| 327 } | |
| 328 | |
| 329 void WorkerThreadableLoader::Peer::overrideTimeout(unsigned long timeoutMillisec onds) | |
| 330 { | |
| 331 DCHECK(isMainThread()); | |
| 332 if (!m_mainThreadLoader) | |
| 333 return; | |
| 334 m_mainThreadLoader->overrideTimeout(timeoutMilliseconds); | |
| 335 } | |
| 336 | |
| 337 void WorkerThreadableLoader::Peer::cancel() | |
| 338 { | |
|
haraken
2016/07/21 10:22:29
Don't we need to call:
m_forwarder->abort();
yhirano
2016/07/21 10:56:09
We don't need to call them when this function is c
| |
| 339 DCHECK(isMainThread()); | |
| 340 if (!m_mainThreadLoader) | |
| 341 return; | |
| 342 m_mainThreadLoader->cancel(); | |
| 343 m_mainThreadLoader = nullptr; | |
| 344 } | |
| 345 | |
| 346 void WorkerThreadableLoader::Peer::didSendData(unsigned long long bytesSent, uns igned long long totalBytesToBeSent) | |
| 347 { | |
| 348 DCHECK(isMainThread()); | |
| 349 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien tWrapper.get(); | |
|
haraken
2016/07/21 10:22:29
Shall we use wrapCrossThreadPersistent()?
The sam
yhirano
2016/07/21 11:44:55
Let me confirm: Are you suggesting
(1) {
DCH
haraken
2016/07/21 15:56:14
I was suggesting 2).
if (!m_clientWrapper)
retu
yhirano
2016/07/22 04:42:14
The pattern is not safe as m_clientWrapper is weak
| |
| 350 if (!clientWrapper) | |
| 351 return; | |
| 352 m_forwarder->forwardTask(createCrossThreadTask(&ThreadableLoaderClientWrappe r::didSendData, clientWrapper, bytesSent, totalBytesToBeSent)); | |
| 353 } | |
| 354 | |
| 355 void WorkerThreadableLoader::Peer::didReceiveResponse(unsigned long identifier, const ResourceResponse& response, std::unique_ptr<WebDataConsumerHandle> handle) | |
| 356 { | |
| 357 DCHECK(isMainThread()); | |
| 358 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien tWrapper.get(); | |
| 359 if (!clientWrapper) | |
| 360 return; | |
| 361 m_forwarder->forwardTask(createCrossThreadTask(&ThreadableLoaderClientWrappe r::didReceiveResponse, clientWrapper, identifier, response, passed(std::move(han dle)))); | |
| 362 } | |
| 363 | |
| 364 void WorkerThreadableLoader::Peer::didReceiveData(const char* data, unsigned dat aLength) | |
| 365 { | |
| 366 DCHECK(isMainThread()); | |
| 367 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien tWrapper.get(); | |
| 368 if (!clientWrapper) | |
| 369 return; | |
| 370 m_forwarder->forwardTask(createCrossThreadTask(&ThreadableLoaderClientWrappe r::didReceiveData, clientWrapper, passed(createVectorFromMemoryRegion(data, data Length)))); | |
| 371 } | |
| 372 | |
| 373 void WorkerThreadableLoader::Peer::didDownloadData(int dataLength) | |
| 374 { | |
| 375 DCHECK(isMainThread()); | |
| 376 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien tWrapper.get(); | |
| 377 if (!clientWrapper) | |
| 378 return; | |
| 379 m_forwarder->forwardTask(createCrossThreadTask(&ThreadableLoaderClientWrappe r::didDownloadData, clientWrapper, dataLength)); | |
| 380 } | |
| 381 | |
| 382 void WorkerThreadableLoader::Peer::didReceiveCachedMetadata(const char* data, in t dataLength) | |
| 383 { | |
| 384 DCHECK(isMainThread()); | |
| 385 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien tWrapper.get(); | |
| 386 if (!clientWrapper) | |
| 387 return; | |
| 388 m_forwarder->forwardTask(createCrossThreadTask(&ThreadableLoaderClientWrappe r::didReceiveCachedMetadata, clientWrapper, passed(createVectorFromMemoryRegion( data, dataLength)))); | |
| 389 } | |
| 390 | |
| 391 void WorkerThreadableLoader::Peer::didFinishLoading(unsigned long identifier, do uble finishTime) | |
| 392 { | |
| 393 DCHECK(isMainThread()); | |
| 394 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien tWrapper.get(); | |
| 395 if (!clientWrapper) | |
| 396 return; | |
| 397 m_forwarder->forwardTaskWithDoneSignal(createCrossThreadTask(&ThreadableLoad erClientWrapper::didFinishLoading, clientWrapper, identifier, finishTime)); | |
| 398 } | |
| 399 | |
| 400 void WorkerThreadableLoader::Peer::didFail(const ResourceError& error) | |
| 401 { | |
| 402 DCHECK(isMainThread()); | |
| 403 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien tWrapper.get(); | |
| 404 if (!clientWrapper) | |
| 405 return; | |
| 406 m_forwarder->forwardTaskWithDoneSignal(createCrossThreadTask(&ThreadableLoad erClientWrapper::didFail, clientWrapper, error)); | |
| 407 } | |
| 408 | |
| 409 void WorkerThreadableLoader::Peer::didFailAccessControlCheck(const ResourceError & error) | |
| 410 { | |
| 411 DCHECK(isMainThread()); | |
| 412 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien tWrapper.get(); | |
| 413 if (!clientWrapper) | |
| 414 return; | |
| 415 m_forwarder->forwardTaskWithDoneSignal(createCrossThreadTask(&ThreadableLoad erClientWrapper::didFailAccessControlCheck, clientWrapper, error)); | |
| 416 } | |
| 417 | |
| 418 void WorkerThreadableLoader::Peer::didFailRedirectCheck() | |
| 419 { | |
| 420 DCHECK(isMainThread()); | |
| 421 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien tWrapper.get(); | |
| 422 if (!clientWrapper) | |
| 423 return; | |
| 424 m_forwarder->forwardTaskWithDoneSignal(createCrossThreadTask(&ThreadableLoad erClientWrapper::didFailRedirectCheck, clientWrapper)); | |
| 425 } | |
| 426 | |
| 427 void WorkerThreadableLoader::Peer::didReceiveResourceTiming(const ResourceTiming Info& info) | |
| 428 { | |
| 429 DCHECK(isMainThread()); | |
| 430 CrossThreadPersistent<ThreadableLoaderClientWrapper> clientWrapper = m_clien tWrapper.get(); | |
| 431 if (!clientWrapper) | |
| 432 return; | |
| 433 m_forwarder->forwardTask(createCrossThreadTask(&ThreadableLoaderClientWrappe r::didReceiveResourceTiming, clientWrapper, info)); | |
| 434 } | |
| 435 | |
| 436 void WorkerThreadableLoader::Peer::contextDestroyed() | |
| 437 { | |
| 438 DCHECK(isMainThread()); | |
| 439 m_forwarder->abort(); | |
| 440 m_clientWrapper = nullptr; | |
| 441 cancel(); | |
| 442 } | |
| 443 | |
| 444 DEFINE_TRACE(WorkerThreadableLoader::Peer) | |
| 445 { | |
| 446 visitor->trace(m_forwarder); | |
| 447 WorkerThreadLifecycleObserver::trace(visitor); | |
| 448 } | |
| 449 | |
| 450 WorkerThreadableLoader::Peer::Peer(TaskForwarder* forwarder, WorkerThreadLifecyc leContext* context) | |
| 451 : WorkerThreadLifecycleObserver(context) | |
| 452 , m_forwarder(forwarder) | |
| 453 { | |
| 454 DCHECK(isMainThread()); | |
| 455 } | |
| 456 | |
| 457 void WorkerThreadableLoader::Peer::start( | |
| 458 Document& document, | |
| 459 std::unique_ptr<CrossThreadResourceRequestData> request, | |
| 460 const ThreadableLoaderOptions& options, | |
| 461 const ResourceLoaderOptions& originalResourceLoaderOptions) | |
| 462 { | |
| 463 DCHECK(isMainThread()); | |
| 464 ResourceLoaderOptions resourceLoaderOptions = originalResourceLoaderOptions; | |
| 465 resourceLoaderOptions.requestInitiatorContext = WorkerContext; | |
| 466 m_mainThreadLoader = DocumentThreadableLoader::create(document, this, option s, resourceLoaderOptions); | |
| 467 m_mainThreadLoader->start(ResourceRequest(request.get())); | |
| 368 } | 468 } |
| 369 | 469 |
| 370 } // namespace blink | 470 } // namespace blink |
| OLD | NEW |