WebKit/chromium/src/WebWorkerClientImpl.cpp
changeset 0 4f2f89ce4247
equal deleted inserted replaced
-1:000000000000 0:4f2f89ce4247
       
     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 "CrossThreadTask.h"
       
    37 #include "DedicatedWorkerThread.h"
       
    38 #include "ErrorEvent.h"
       
    39 #include "Frame.h"
       
    40 #include "FrameLoaderClient.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 "WorkerScriptController.h"
       
    49 #include "WorkerMessagingProxy.h"
       
    50 #include <wtf/Threading.h>
       
    51 
       
    52 #include "FrameLoaderClientImpl.h"
       
    53 #include "PlatformMessagePortChannel.h"
       
    54 #include "WebFrameClient.h"
       
    55 #include "WebFrameImpl.h"
       
    56 #include "WebKit.h"
       
    57 #include "WebKitClient.h"
       
    58 #include "WebMessagePortChannel.h"
       
    59 #include "WebString.h"
       
    60 #include "WebURL.h"
       
    61 #include "WebViewImpl.h"
       
    62 #include "WebWorker.h"
       
    63 #include "WebWorkerImpl.h"
       
    64 
       
    65 using namespace WebCore;
       
    66 
       
    67 namespace WebKit {
       
    68 
       
    69 // When WebKit creates a WorkerContextProxy object, we check if we're in the
       
    70 // renderer or worker process.  If the latter, then we just use
       
    71 // WorkerMessagingProxy.
       
    72 //
       
    73 // If we're in the renderer process, then we need use the glue provided
       
    74 // WebWorker object to talk to the worker process over IPC.  The worker process
       
    75 // talks to Worker* using WorkerObjectProxy, which we implement on
       
    76 // WebWorkerClientImpl.
       
    77 //
       
    78 // Note that if we're running each worker in a separate process, then nested
       
    79 // workers end up using the same codepath as the renderer process.
       
    80 
       
    81 // static
       
    82 WorkerContextProxy* WebWorkerClientImpl::createWorkerContextProxy(Worker* worker)
       
    83 {
       
    84     // Special behavior for multiple workers per process.
       
    85     // FIXME: v8 doesn't support more than one workers per process.
       
    86     // if (!worker->scriptExecutionContext()->isDocument())
       
    87     //     return new WorkerMessagingProxy(worker);
       
    88 
       
    89     WebWorker* webWorker = 0;
       
    90     WebWorkerClientImpl* proxy = new WebWorkerClientImpl(worker);
       
    91 
       
    92     if (worker->scriptExecutionContext()->isDocument()) {
       
    93         Document* document = static_cast<Document*>(
       
    94             worker->scriptExecutionContext());
       
    95         WebFrameImpl* webFrame = WebFrameImpl::fromFrame(document->frame());
       
    96         webWorker = webFrame->client()->createWorker(webFrame, proxy);
       
    97     } else {
       
    98         WorkerScriptController* controller = WorkerScriptController::controllerForContext();
       
    99         if (!controller) {
       
   100             ASSERT_NOT_REACHED();
       
   101             return 0;
       
   102         }
       
   103 
       
   104         DedicatedWorkerThread* thread = static_cast<DedicatedWorkerThread*>(controller->workerContext()->thread());
       
   105         WorkerObjectProxy* workerObjectProxy = &thread->workerObjectProxy();
       
   106         WebWorkerImpl* impl = reinterpret_cast<WebWorkerImpl*>(workerObjectProxy);
       
   107         webWorker = impl->client()->createWorker(proxy);
       
   108     }
       
   109 
       
   110     proxy->setWebWorker(webWorker);
       
   111     return proxy;
       
   112 }
       
   113 
       
   114 WebWorkerClientImpl::WebWorkerClientImpl(Worker* worker)
       
   115     : m_scriptExecutionContext(worker->scriptExecutionContext())
       
   116     , m_worker(worker)
       
   117     , m_askedToTerminate(false)
       
   118     , m_unconfirmedMessageCount(0)
       
   119     , m_workerContextHadPendingActivity(false)
       
   120     , m_workerThreadId(currentThread())
       
   121 {
       
   122 }
       
   123 
       
   124 WebWorkerClientImpl::~WebWorkerClientImpl()
       
   125 {
       
   126 }
       
   127 
       
   128 void WebWorkerClientImpl::setWebWorker(WebWorker* webWorker)
       
   129 {
       
   130     m_webWorker = webWorker;
       
   131 }
       
   132 
       
   133 void WebWorkerClientImpl::startWorkerContext(const KURL& scriptURL,
       
   134                                              const String& userAgent,
       
   135                                              const String& sourceCode)
       
   136 {
       
   137     // Worker.terminate() could be called from JS before the context is started.
       
   138     if (m_askedToTerminate)
       
   139         return;
       
   140     if (!isMainThread()) {
       
   141         WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(
       
   142             &startWorkerContextTask,
       
   143             this,
       
   144             scriptURL.string(),
       
   145             userAgent,
       
   146             sourceCode));
       
   147         return;
       
   148     }
       
   149     m_webWorker->startWorkerContext(scriptURL, userAgent, sourceCode);
       
   150 }
       
   151 
       
   152 void WebWorkerClientImpl::terminateWorkerContext()
       
   153 {
       
   154     if (m_askedToTerminate)
       
   155         return;
       
   156     m_askedToTerminate = true;
       
   157     if (!isMainThread()) {
       
   158         WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&terminateWorkerContextTask, this));
       
   159         return;
       
   160     }
       
   161     m_webWorker->terminateWorkerContext();
       
   162 }
       
   163 
       
   164 void WebWorkerClientImpl::postMessageToWorkerContext(
       
   165     PassRefPtr<SerializedScriptValue> message,
       
   166     PassOwnPtr<MessagePortChannelArray> channels)
       
   167 {
       
   168     // Worker.terminate() could be called from JS before the context is started.
       
   169     if (m_askedToTerminate)
       
   170         return;
       
   171     ++m_unconfirmedMessageCount;
       
   172     if (!isMainThread()) {
       
   173         WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&postMessageToWorkerContextTask,
       
   174                                                                    this,
       
   175                                                                    message->toWireString(),
       
   176                                                                    channels));
       
   177         return;
       
   178     }
       
   179     WebMessagePortChannelArray webChannels(channels.get() ? channels->size() : 0);
       
   180     for (size_t i = 0; i < webChannels.size(); ++i) {
       
   181         WebMessagePortChannel* webchannel =
       
   182                         (*channels)[i]->channel()->webChannelRelease();
       
   183         webchannel->setClient(0);
       
   184         webChannels[i] = webchannel;
       
   185     }
       
   186     m_webWorker->postMessageToWorkerContext(message->toWireString(), webChannels);
       
   187 }
       
   188 
       
   189 bool WebWorkerClientImpl::hasPendingActivity() const
       
   190 {
       
   191     return !m_askedToTerminate
       
   192            && (m_unconfirmedMessageCount || m_workerContextHadPendingActivity);
       
   193 }
       
   194 
       
   195 void WebWorkerClientImpl::workerObjectDestroyed()
       
   196 {
       
   197     if (isMainThread()) {
       
   198         m_webWorker->workerObjectDestroyed();
       
   199         m_worker = 0;
       
   200     }
       
   201     // Even if this is called on the main thread, there could be a queued task for
       
   202     // this object, so don't delete it right away.
       
   203     WebWorkerBase::dispatchTaskToMainThread(createCallbackTask(&workerObjectDestroyedTask,
       
   204                                                                this));
       
   205 }
       
   206 
       
   207 void WebWorkerClientImpl::postMessageToWorkerObject(const WebString& message,
       
   208                                                     const WebMessagePortChannelArray& channels)
       
   209 {
       
   210     OwnPtr<MessagePortChannelArray> channels2;
       
   211     if (channels.size()) {
       
   212         channels2 = new MessagePortChannelArray(channels.size());
       
   213         for (size_t i = 0; i < channels.size(); ++i) {
       
   214             RefPtr<PlatformMessagePortChannel> platform_channel =
       
   215                             PlatformMessagePortChannel::create(channels[i]);
       
   216             channels[i]->setClient(platform_channel.get());
       
   217             (*channels2)[i] = MessagePortChannel::create(platform_channel);
       
   218         }
       
   219     }
       
   220 
       
   221     if (currentThread() != m_workerThreadId) {
       
   222         m_scriptExecutionContext->postTask(createCallbackTask(&postMessageToWorkerObjectTask,
       
   223                                                               this,
       
   224                                                               String(message),
       
   225                                                               channels2.release()));
       
   226         return;
       
   227     }
       
   228 
       
   229     postMessageToWorkerObjectTask(m_scriptExecutionContext.get(), this,
       
   230                                   message, channels2.release());
       
   231 }
       
   232 
       
   233 void WebWorkerClientImpl::postExceptionToWorkerObject(const WebString& errorMessage,
       
   234                                                       int lineNumber,
       
   235                                                       const WebString& sourceURL)
       
   236 {
       
   237     if (currentThread() != m_workerThreadId) {
       
   238         m_scriptExecutionContext->postTask(createCallbackTask(&postExceptionToWorkerObjectTask,
       
   239                                                               this,
       
   240                                                               String(errorMessage),
       
   241                                                               lineNumber,
       
   242                                                               String(sourceURL)));
       
   243         return;
       
   244     }
       
   245 
       
   246     bool unhandled = m_worker->dispatchEvent(ErrorEvent::create(errorMessage,
       
   247                                                                 sourceURL,
       
   248                                                                 lineNumber));
       
   249     if (unhandled)
       
   250         m_scriptExecutionContext->reportException(errorMessage, lineNumber, sourceURL);
       
   251 }
       
   252 
       
   253 void WebWorkerClientImpl::postConsoleMessageToWorkerObject(int destination,
       
   254                                                            int sourceId,
       
   255                                                            int messageType,
       
   256                                                            int messageLevel,
       
   257                                                            const WebString& message,
       
   258                                                            int lineNumber,
       
   259                                                            const WebString& sourceURL)
       
   260 {
       
   261     if (currentThread() != m_workerThreadId) {
       
   262         m_scriptExecutionContext->postTask(createCallbackTask(&postConsoleMessageToWorkerObjectTask,
       
   263                                                               this,
       
   264                                                               sourceId,
       
   265                                                               messageType,
       
   266                                                               messageLevel,
       
   267                                                               String(message),
       
   268                                                               lineNumber,
       
   269                                                               String(sourceURL)));
       
   270         return;
       
   271     }
       
   272 
       
   273     m_scriptExecutionContext->addMessage(static_cast<MessageSource>(sourceId),
       
   274                                          static_cast<MessageType>(messageType),
       
   275                                          static_cast<MessageLevel>(messageLevel),
       
   276                                          String(message), lineNumber,
       
   277                                          String(sourceURL));
       
   278 }
       
   279 
       
   280 void WebWorkerClientImpl::postConsoleMessageToWorkerObject(int sourceId,
       
   281                                                            int messageType,
       
   282                                                            int messageLevel,
       
   283                                                            const WebString& message,
       
   284                                                            int lineNumber,
       
   285                                                            const WebString& sourceURL)
       
   286 {
       
   287     postConsoleMessageToWorkerObject(0, sourceId, messageType, messageLevel, message, lineNumber, sourceURL);
       
   288 }
       
   289 
       
   290 void WebWorkerClientImpl::confirmMessageFromWorkerObject(bool hasPendingActivity)
       
   291 {
       
   292     // unconfirmed_message_count_ can only be updated on the thread where it's
       
   293     // accessed.  Otherwise there are race conditions with v8's garbage
       
   294     // collection.
       
   295     m_scriptExecutionContext->postTask(createCallbackTask(&confirmMessageFromWorkerObjectTask,
       
   296                                                           this));
       
   297 }
       
   298 
       
   299 void WebWorkerClientImpl::reportPendingActivity(bool hasPendingActivity)
       
   300 {
       
   301     // See above comment in confirmMessageFromWorkerObject.
       
   302     m_scriptExecutionContext->postTask(createCallbackTask(&reportPendingActivityTask,
       
   303                                                           this,
       
   304                                                           hasPendingActivity));
       
   305 }
       
   306 
       
   307 void WebWorkerClientImpl::workerContextDestroyed()
       
   308 {
       
   309 }
       
   310 
       
   311 void WebWorkerClientImpl::workerContextClosed()
       
   312 {
       
   313 }
       
   314 
       
   315 void WebWorkerClientImpl::startWorkerContextTask(ScriptExecutionContext* context,
       
   316                                                  WebWorkerClientImpl* thisPtr,
       
   317                                                  const String& scriptURL,
       
   318                                                  const String& userAgent,
       
   319                                                  const String& sourceCode)
       
   320 {
       
   321     thisPtr->m_webWorker->startWorkerContext(KURL(ParsedURLString, scriptURL),
       
   322                                              userAgent, sourceCode);
       
   323 }
       
   324 
       
   325 void WebWorkerClientImpl::terminateWorkerContextTask(ScriptExecutionContext* context,
       
   326                                                      WebWorkerClientImpl* thisPtr)
       
   327 {
       
   328     thisPtr->m_webWorker->terminateWorkerContext();
       
   329 }
       
   330 
       
   331 void WebWorkerClientImpl::postMessageToWorkerContextTask(ScriptExecutionContext* context,
       
   332                                                          WebWorkerClientImpl* thisPtr,
       
   333                                                          const String& message,
       
   334                                                          PassOwnPtr<MessagePortChannelArray> channels)
       
   335 {
       
   336     WebMessagePortChannelArray webChannels(channels.get() ? channels->size() : 0);
       
   337 
       
   338     for (size_t i = 0; i < webChannels.size(); ++i) {
       
   339         webChannels[i] = (*channels)[i]->channel()->webChannelRelease();
       
   340         webChannels[i]->setClient(0);
       
   341     }
       
   342 
       
   343     thisPtr->m_webWorker->postMessageToWorkerContext(message, webChannels);
       
   344 }
       
   345 
       
   346 void WebWorkerClientImpl::workerObjectDestroyedTask(ScriptExecutionContext* context,
       
   347                                                     WebWorkerClientImpl* thisPtr)
       
   348 {
       
   349     if (thisPtr->m_worker) // Check we haven't alread called this.
       
   350         thisPtr->m_webWorker->workerObjectDestroyed();
       
   351     delete thisPtr;
       
   352 }
       
   353 
       
   354 void WebWorkerClientImpl::postMessageToWorkerObjectTask(
       
   355                                                         ScriptExecutionContext* context,
       
   356                                                         WebWorkerClientImpl* thisPtr,
       
   357                                                         const String& message,
       
   358                                                         PassOwnPtr<MessagePortChannelArray> channels)
       
   359 {
       
   360 
       
   361     if (thisPtr->m_worker) {
       
   362         OwnPtr<MessagePortArray> ports =
       
   363             MessagePort::entanglePorts(*context, channels);
       
   364         RefPtr<SerializedScriptValue> serializedMessage =
       
   365             SerializedScriptValue::createFromWire(message);
       
   366         thisPtr->m_worker->dispatchEvent(MessageEvent::create(ports.release(),
       
   367                                                               serializedMessage.release()));
       
   368     }
       
   369 }
       
   370 
       
   371 void WebWorkerClientImpl::postExceptionToWorkerObjectTask(
       
   372                                                           ScriptExecutionContext* context,
       
   373                                                           WebWorkerClientImpl* thisPtr,
       
   374                                                           const String& errorMessage,
       
   375                                                           int lineNumber,
       
   376                                                           const String& sourceURL)
       
   377 {
       
   378     bool handled = false;
       
   379     if (thisPtr->m_worker)
       
   380         handled = thisPtr->m_worker->dispatchEvent(ErrorEvent::create(errorMessage,
       
   381                                                                       sourceURL,
       
   382                                                                       lineNumber));
       
   383     if (!handled)
       
   384         thisPtr->m_scriptExecutionContext->reportException(errorMessage,
       
   385                                                            lineNumber,
       
   386                                                            sourceURL);
       
   387 }
       
   388 
       
   389 void WebWorkerClientImpl::postConsoleMessageToWorkerObjectTask(ScriptExecutionContext* context,
       
   390                                                                WebWorkerClientImpl* thisPtr,
       
   391                                                                int sourceId,
       
   392                                                                int messageType,
       
   393                                                                int messageLevel,
       
   394                                                                const String& message,
       
   395                                                                int lineNumber,
       
   396                                                                const String& sourceURL)
       
   397 {
       
   398     thisPtr->m_scriptExecutionContext->addMessage(static_cast<MessageSource>(sourceId),
       
   399                                                   static_cast<MessageType>(messageType),
       
   400                                                   static_cast<MessageLevel>(messageLevel),
       
   401                                                   message, lineNumber,
       
   402                                                   sourceURL);
       
   403 }
       
   404 
       
   405 void WebWorkerClientImpl::confirmMessageFromWorkerObjectTask(ScriptExecutionContext* context,
       
   406                                                              WebWorkerClientImpl* thisPtr)
       
   407 {
       
   408     thisPtr->m_unconfirmedMessageCount--;
       
   409 }
       
   410 
       
   411 void WebWorkerClientImpl::reportPendingActivityTask(ScriptExecutionContext* context,
       
   412                                                     WebWorkerClientImpl* thisPtr,
       
   413                                                     bool hasPendingActivity)
       
   414 {
       
   415     thisPtr->m_workerContextHadPendingActivity = hasPendingActivity;
       
   416 }
       
   417 
       
   418 } // namespace WebKit
       
   419 
       
   420 #endif