| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright (C) 2009 Google Inc. All rights reserved. | |
| 3 * | |
| 4 * Redistribution and use in source and binary forms, with or without | |
| 5 * modification, are permitted provided that the following conditions are | |
| 6 * met: | |
| 7 * | |
| 8 * * Redistributions of source code must retain the above copyright | |
| 9 * notice, this list of conditions and the following disclaimer. | |
| 10 * * Redistributions in binary form must reproduce the above | |
| 11 * copyright notice, this list of conditions and the following disclaimer | |
| 12 * in the documentation and/or other materials provided with the | |
| 13 * distribution. | |
| 14 * * Neither the name of Google Inc. nor the names of its | |
| 15 * contributors may be used to endorse or promote products derived from | |
| 16 * this software without specific prior written permission. | |
| 17 * | |
| 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 */ | |
| 30 | |
| 31 #include "config.h" | |
| 32 #include "WebWorkerClientImpl.h" | |
| 33 | |
| 34 #if ENABLE(WORKERS) | |
| 35 | |
| 36 #include "DedicatedWorkerThread.h" | |
| 37 #include "ErrorEvent.h" | |
| 38 #include "Frame.h" | |
| 39 #include "FrameLoaderClient.h" | |
| 40 #include "GenericWorkerTask.h" | |
| 41 #include "MessageEvent.h" | |
| 42 #include "MessagePort.h" | |
| 43 #include "MessagePortChannel.h" | |
| 44 #include "ScriptExecutionContext.h" | |
| 45 #include "Worker.h" | |
| 46 #include "WorkerContext.h" | |
| 47 #include "WorkerContextExecutionProxy.h" | |
| 48 #include "WorkerMessagingProxy.h" | |
| 49 #include <wtf/Threading.h> | |
| 50 | |
| 51 #include "FrameLoaderClientImpl.h" | |
| 52 #include "PlatformMessagePortChannel.h" | |
| 53 #include "WebFrameClient.h" | |
| 54 #include "WebFrameImpl.h" | |
| 55 #include "WebKit.h" | |
| 56 #include "WebKitClient.h" | |
| 57 #include "WebMessagePortChannel.h" | |
| 58 #include "WebString.h" | |
| 59 #include "WebURL.h" | |
| 60 #include "WebViewImpl.h" | |
| 61 #include "WebWorker.h" | |
| 62 #include "WebWorkerImpl.h" | |
| 63 | |
| 64 using namespace WebCore; | |
| 65 | |
| 66 namespace WebKit { | |
| 67 | |
| 68 // When WebKit creates a WorkerContextProxy object, we check if we're in the | |
| 69 // renderer or worker process. If the latter, then we just use | |
| 70 // WorkerMessagingProxy. | |
| 71 // | |
| 72 // If we're in the renderer process, then we need use the glue provided | |
| 73 // WebWorker object to talk to the worker process over IPC. The worker process | |
| 74 // talks to Worker* using WorkerObjectProxy, which we implement on | |
| 75 // WebWorkerClientImpl. | |
| 76 // | |
| 77 // Note that if we're running each worker in a separate process, then nested | |
| 78 // workers end up using the same codepath as the renderer process. | |
| 79 | |
| 80 // static | |
| 81 WorkerContextProxy* WebWorkerClientImpl::createWorkerContextProxy(Worker* worker) | |
| 82 { | |
| 83 // Special behavior for multiple workers per process. | |
| 84 // FIXME: v8 doesn't support more than one workers per process. | |
| 85 // if (!worker->scriptExecutionContext()->isDocument()) | |
| 86 // return new WorkerMessagingProxy(worker); | |
| 87 | |
| 88 WebWorker* webWorker = 0; | |
| 89 WebWorkerClientImpl* proxy = new WebWorkerClientImpl(worker); | |
| 90 | |
| 91 if (worker->scriptExecutionContext()->isDocument()) { | |
| 92 Document* document = static_cast<Document*>( | |
| 93 worker->scriptExecutionContext()); | |
| 94 WebFrameImpl* webFrame = WebFrameImpl::fromFrame(document->frame()); | |
| 95 webWorker = webFrame->client()->createWorker(webFrame, proxy); | |
| 96 } else { | |
| 97 WorkerContextExecutionProxy* currentContext = | |
| 98 WorkerContextExecutionProxy::retrieve(); | |
| 99 if (!currentContext) { | |
| 100 ASSERT_NOT_REACHED(); | |
| 101 return 0; | |
| 102 } | |
| 103 | |
| 104 DedicatedWorkerThread* thread = | |
| 105 static_cast<DedicatedWorkerThread*>(currentContext->workerContext()->thread()); | |
| 106 WorkerObjectProxy* workerObjectProxy = &thread->workerObjectProxy(); | |
| 107 WebWorkerImpl* impl = reinterpret_cast<WebWorkerImpl*>(workerObjectProxy); | |
| 108 webWorker = impl->client()->createWorker(proxy); | |
| 109 } | |
| 110 | |
| 111 proxy->setWebWorker(webWorker); | |
| 112 return proxy; | |
| 113 } | |
| 114 | |
| 115 WebWorkerClientImpl::WebWorkerClientImpl(Worker* worker) | |
| 116 : m_scriptExecutionContext(worker->scriptExecutionContext()) | |
| 117 , m_worker(worker) | |
| 118 , m_askedToTerminate(false) | |
| 119 , m_unconfirmedMessageCount(0) | |
| 120 , m_workerContextHadPendingActivity(false) | |
| 121 , m_workerThreadId(currentThread()) | |
| 122 { | |
| 123 } | |
| 124 | |
| 125 WebWorkerClientImpl::~WebWorkerClientImpl() | |
| 126 { | |
| 127 } | |
| 128 | |
| 129 void WebWorkerClientImpl::setWebWorker(WebWorker* webWorker) | |
| 130 { | |
| 131 m_webWorker = webWorker; | |
| 132 } | |
| 133 | |
| 134 void WebWorkerClientImpl::startWorkerContext(const KURL& scriptURL, | |
| 135 const String& userAgent, | |
| 136 const String& sourceCode) | |
| 137 { | |
| 138 // Worker.terminate() could be called from JS before the context is started. | |
| 139 if (m_askedToTerminate) | |
| 140 return; | |
| 141 if (!isMainThread()) { | |
| 142 WebWorkerBase::dispatchTaskToMainThread(createCallbackTask( | |
| 143 &startWorkerContextTask, | |
| 144 this, | |
| 145 scriptURL.string(), | |
| 146 userAgent, | |
| 147 sourceCode)); | |
| 148 return; | |
| 149 } | |
| 150 m_webWorker->startWorkerContext(scriptURL, userAgent, sourceCode); | |
| 151 } | |
| 152 | |
| 153 void WebWorkerClientImpl::terminateWorkerContext() | |
| 154 { | |
| 155 if (m_askedToTerminate) | |
| 156 return; | |
| 157 m_askedToTerminate = true; | |
| 158 if (!isMainThread()) { | |
| 159 WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&terminateWorkerContextTask, this)); | |
| 160 return; | |
| 161 } | |
| 162 m_webWorker->terminateWorkerContext(); | |
| 163 } | |
| 164 | |
| 165 void WebWorkerClientImpl::postMessageToWorkerContext( | |
| 166 PassRefPtr<SerializedScriptValue> message, | |
| 167 PassOwnPtr<MessagePortChannelArray> channels) | |
| 168 { | |
| 169 // Worker.terminate() could be called from JS before the context is started. | |
| 170 if (m_askedToTerminate) | |
| 171 return; | |
| 172 ++m_unconfirmedMessageCount; | |
| 173 if (!isMainThread()) { | |
| 174 WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&postMessageToWorkerContextTask, | |
| 175 this, | |
| 176 message->toString(), | |
| 177 channels)); | |
| 178 return; | |
| 179 } | |
| 180 WebMessagePortChannelArray webChannels(channels.get() ? channels->size() : 0); | |
| 181 for (size_t i = 0; i < webChannels.size(); ++i) { | |
| 182 WebMessagePortChannel* webchannel = | |
| 183 (*channels)[i]->channel()->webChannelRelease(); | |
| 184 webchannel->setClient(0); | |
| 185 webChannels[i] = webchannel; | |
| 186 } | |
| 187 m_webWorker->postMessageToWorkerContext(message->toString(), webChannels); | |
| 188 } | |
| 189 | |
| 190 bool WebWorkerClientImpl::hasPendingActivity() const | |
| 191 { | |
| 192 return !m_askedToTerminate | |
| 193 && (m_unconfirmedMessageCount || m_workerContextHadPendingActivity); | |
| 194 } | |
| 195 | |
| 196 void WebWorkerClientImpl::workerObjectDestroyed() | |
| 197 { | |
| 198 if (isMainThread()) { | |
| 199 m_webWorker->workerObjectDestroyed(); | |
| 200 m_worker = 0; | |
| 201 } | |
| 202 // Even if this is called on the main thread, there could be a queued task for | |
| 203 // this object, so don't delete it right away. | |
| 204 WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&workerObjectDestroyedTask, | |
| 205 this)); | |
| 206 } | |
| 207 | |
| 208 void WebWorkerClientImpl::postMessageToWorkerObject(const WebString& message, | |
| 209 const WebMessagePortChannelArray& channels) | |
| 210 { | |
| 211 OwnPtr<MessagePortChannelArray> channels2; | |
| 212 if (channels.size()) { | |
| 213 channels2 = new MessagePortChannelArray(channels.size()); | |
| 214 for (size_t i = 0; i < channels.size(); ++i) { | |
| 215 RefPtr<PlatformMessagePortChannel> platform_channel = | |
| 216 PlatformMessagePortChannel::create(channels[i]); | |
| 217 channels[i]->setClient(platform_channel.get()); | |
| 218 (*channels2)[i] = MessagePortChannel::create(platform_channel); | |
| 219 } | |
| 220 } | |
| 221 | |
| 222 if (currentThread() != m_workerThreadId) { | |
| 223 m_scriptExecutionContext->postTask(createCallbackTask(&postMessageToWorkerObjectTask, | |
| 224 this, | |
| 225 String(message), | |
| 226 channels2.release())); | |
| 227 return; | |
| 228 } | |
| 229 | |
| 230 postMessageToWorkerObjectTask(m_scriptExecutionContext.get(), this, | |
| 231 message, channels2.release()); | |
| 232 } | |
| 233 | |
| 234 void WebWorkerClientImpl::postExceptionToWorkerObject(const WebString& errorMessage, | |
| 235 int lineNumber, | |
| 236 const WebString& sourceURL) | |
| 237 { | |
| 238 if (currentThread() != m_workerThreadId) { | |
| 239 m_scriptExecutionContext->postTask(createCallbackTask(&postExceptionToWorkerObjectTask, | |
| 240 this, | |
| 241 String(errorMessage), | |
| 242 lineNumber, | |
| 243 String(sourceURL))); | |
| 244 return; | |
| 245 } | |
| 246 | |
| 247 bool handled = false; | |
| 248 handled = m_worker->dispatchEvent(ErrorEvent::create(errorMessage, | |
| 249 sourceURL, | |
| 250 lineNumber)); | |
| 251 if (!handled) | |
| 252 m_scriptExecutionContext->reportException(errorMessage, lineNumber, sourceURL); | |
| 253 } | |
| 254 | |
| 255 void WebWorkerClientImpl::postConsoleMessageToWorkerObject(int destinationId, | |
| 256 int sourceId, | |
| 257 int messageType, | |
| 258 int messageLevel, | |
| 259 const WebString& message, | |
| 260 int lineNumber, | |
| 261 const WebString& sourceURL) | |
| 262 { | |
| 263 if (currentThread() != m_workerThreadId) { | |
| 264 m_scriptExecutionContext->postTask(createCallbackTask(&postConsoleMessageToWorkerObjectTask, | |
| 265 this, | |
| 266 destinationId, | |
| 267 sourceId, | |
| 268 messageType, | |
| 269 messageLevel, | |
| 270 String(message), | |
| 271 lineNumber, | |
| 272 String(sourceURL))); | |
| 273 return; | |
| 274 } | |
| 275 | |
| 276 m_scriptExecutionContext->addMessage(static_cast<MessageDestination>(destinationId), | |
| 277 static_cast<MessageSource>(sourceId), | |
| 278 static_cast<MessageType>(messageType), | |
| 279 static_cast<MessageLevel>(messageLevel), | |
| 280 String(message), lineNumber, | |
| 281 String(sourceURL)); | |
| 282 } | |
| 283 | |
| 284 void WebWorkerClientImpl::confirmMessageFromWorkerObject(bool hasPendingActivity) | |
| 285 { | |
| 286 // unconfirmed_message_count_ can only be updated on the thread where it's | |
| 287 // accessed. Otherwise there are race conditions with v8's garbage | |
| 288 // collection. | |
| 289 m_scriptExecutionContext->postTask(createCallbackTask(&confirmMessageFromWorkerObjectTask, | |
| 290 this)); | |
| 291 } | |
| 292 | |
| 293 void WebWorkerClientImpl::reportPendingActivity(bool hasPendingActivity) | |
| 294 { | |
| 295 // See above comment in confirmMessageFromWorkerObject. | |
| 296 m_scriptExecutionContext->postTask(createCallbackTask(&reportPendingActivityTask, | |
| 297 this, | |
| 298 hasPendingActivity)); | |
| 299 } | |
| 300 | |
| 301 void WebWorkerClientImpl::workerContextDestroyed() | |
| 302 { | |
| 303 } | |
| 304 | |
| 305 void WebWorkerClientImpl::workerContextClosed() | |
| 306 { | |
| 307 } | |
| 308 | |
| 309 void WebWorkerClientImpl::startWorkerContextTask(ScriptExecutionContext* context, | |
| 310 WebWorkerClientImpl* thisPtr, | |
| 311 const String& scriptURL, | |
| 312 const String& userAgent, | |
| 313 const String& sourceCode) | |
| 314 { | |
| 315 thisPtr->m_webWorker->startWorkerContext(KURL(ParsedURLString, scriptURL), | |
| 316 userAgent, sourceCode); | |
| 317 } | |
| 318 | |
| 319 void WebWorkerClientImpl::terminateWorkerContextTask(ScriptExecutionContext* context, | |
| 320 WebWorkerClientImpl* thisPtr) | |
| 321 { | |
| 322 thisPtr->m_webWorker->terminateWorkerContext(); | |
| 323 } | |
| 324 | |
| 325 void WebWorkerClientImpl::postMessageToWorkerContextTask(ScriptExecutionContext* context, | |
| 326 WebWorkerClientImpl* thisPtr, | |
| 327 const String& message, | |
| 328 PassOwnPtr<MessagePortChannelArray> channels) | |
| 329 { | |
| 330 WebMessagePortChannelArray webChannels(channels.get() ? channels->size() : 0); | |
| 331 | |
| 332 for (size_t i = 0; i < webChannels.size(); ++i) { | |
| 333 webChannels[i] = (*channels)[i]->channel()->webChannelRelease(); | |
| 334 webChannels[i]->setClient(0); | |
| 335 } | |
| 336 | |
| 337 thisPtr->m_webWorker->postMessageToWorkerContext(message, webChannels); | |
| 338 } | |
| 339 | |
| 340 void WebWorkerClientImpl::workerObjectDestroyedTask(ScriptExecutionContext* context, | |
| 341 WebWorkerClientImpl* thisPtr) | |
| 342 { | |
| 343 if (thisPtr->m_worker) // Check we haven't alread called this. | |
| 344 thisPtr->m_webWorker->workerObjectDestroyed(); | |
| 345 delete thisPtr; | |
| 346 } | |
| 347 | |
| 348 void WebWorkerClientImpl::postMessageToWorkerObjectTask( | |
| 349 ScriptExecutionContext* context, | |
| 350 WebWorkerClientImpl* thisPtr, | |
| 351 const String& message, | |
| 352 PassOwnPtr<MessagePortChannelArray> channels) | |
| 353 { | |
| 354 | |
| 355 if (thisPtr->m_worker) { | |
| 356 OwnPtr<MessagePortArray> ports = | |
| 357 MessagePort::entanglePorts(*context, channels.release()); | |
| 358 RefPtr<SerializedScriptValue> serializedMessage = | |
| 359 SerializedScriptValue::create(message); | |
| 360 thisPtr->m_worker->dispatchEvent(MessageEvent::create(ports.release(), | |
| 361 serializedMessage.release())); | |
| 362 } | |
| 363 } | |
| 364 | |
| 365 void WebWorkerClientImpl::postExceptionToWorkerObjectTask( | |
| 366 ScriptExecutionContext* context, | |
| 367 WebWorkerClientImpl* thisPtr, | |
| 368 const String& errorMessage, | |
| 369 int lineNumber, | |
| 370 const String& sourceURL) | |
| 371 { | |
| 372 bool handled = false; | |
| 373 if (thisPtr->m_worker) | |
| 374 handled = thisPtr->m_worker->dispatchEvent(ErrorEvent::create(errorMessage, | |
| 375 sourceURL, | |
| 376 lineNumber)); | |
| 377 if (!handled) | |
| 378 thisPtr->m_scriptExecutionContext->reportException(errorMessage, | |
| 379 lineNumber, | |
| 380 sourceURL); | |
| 381 } | |
| 382 | |
| 383 void WebWorkerClientImpl::postConsoleMessageToWorkerObjectTask(ScriptExecutionContext* context, | |
| 384 WebWorkerClientImpl* thisPtr, | |
| 385 int destinationId, | |
| 386 int sourceId, | |
| 387 int messageType, | |
| 388 int messageLevel, | |
| 389 const String& message, | |
| 390 int lineNumber, | |
| 391 const String& sourceURL) | |
| 392 { | |
| 393 thisPtr->m_scriptExecutionContext->addMessage(static_cast<MessageDestination>(destinationId), | |
| 394 static_cast<MessageSource>(sourceId), | |
| 395 static_cast<MessageType>(messageType), | |
| 396 static_cast<MessageLevel>(messageLevel), | |
| 397 message, lineNumber, | |
| 398 sourceURL); | |
| 399 } | |
| 400 | |
| 401 void WebWorkerClientImpl::confirmMessageFromWorkerObjectTask(ScriptExecutionContext* context, | |
| 402 WebWorkerClientImpl* thisPtr) | |
| 403 { | |
| 404 thisPtr->m_unconfirmedMessageCount--; | |
| 405 } | |
| 406 | |
| 407 void WebWorkerClientImpl::reportPendingActivityTask(ScriptExecutionContext* context, | |
| 408 WebWorkerClientImpl* thisPtr, | |
| 409 bool hasPendingActivity) | |
| 410 { | |
| 411 thisPtr->m_workerContextHadPendingActivity = hasPendingActivity; | |
| 412 } | |
| 413 | |
| 414 } // namespace WebKit | |
| 415 | |
| 416 #endif | |
| OLD | NEW |