tizen beta release
[framework/web/webkit-efl.git] / Source / WebCore / workers / WorkerMessagingProxy.cpp
1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  * Copyright (C) 2009 Google Inc. All Rights Reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
25  *
26  */
27
28 #include "config.h"
29
30 #if ENABLE(WORKERS)
31
32 #include "WorkerMessagingProxy.h"
33
34 #include "CrossThreadTask.h"
35 #include "DedicatedWorkerContext.h"
36 #include "DedicatedWorkerThread.h"
37 #include "DOMWindow.h"
38 #include "Document.h"
39 #include "ErrorEvent.h"
40 #include "ExceptionCode.h"
41 #include "InspectorInstrumentation.h"
42 #include "MessageEvent.h"
43 #include "NotImplemented.h"
44 #include "ScriptCallStack.h"
45 #include "ScriptExecutionContext.h"
46 #include "Worker.h"
47 #include "WorkerDebuggerAgent.h"
48 #include "WorkerInspectorController.h"
49 #include <wtf/MainThread.h>
50
51 namespace WebCore {
52
53 class MessageWorkerContextTask : public ScriptExecutionContext::Task {
54 public:
55     static PassOwnPtr<MessageWorkerContextTask> create(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels)
56     {
57         return adoptPtr(new MessageWorkerContextTask(message, channels));
58     }
59
60 private:
61     MessageWorkerContextTask(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels)
62         : m_message(message)
63         , m_channels(channels)
64     {
65     }
66
67     virtual void performTask(ScriptExecutionContext* scriptContext)
68     {
69         ASSERT(scriptContext->isWorkerContext());
70         DedicatedWorkerContext* context = static_cast<DedicatedWorkerContext*>(scriptContext);
71         OwnPtr<MessagePortArray> ports = MessagePort::entanglePorts(*scriptContext, m_channels.release());
72         context->dispatchEvent(MessageEvent::create(ports.release(), m_message));
73         context->thread()->workerObjectProxy().confirmMessageFromWorkerObject(context->hasPendingActivity());
74     }
75
76 private:
77     RefPtr<SerializedScriptValue> m_message;
78     OwnPtr<MessagePortChannelArray> m_channels;
79 };
80
81 class MessageWorkerTask : public ScriptExecutionContext::Task {
82 public:
83     static PassOwnPtr<MessageWorkerTask> create(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels, WorkerMessagingProxy* messagingProxy)
84     {
85         return adoptPtr(new MessageWorkerTask(message, channels, messagingProxy));
86     }
87
88 private:
89     MessageWorkerTask(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels, WorkerMessagingProxy* messagingProxy)
90         : m_message(message)
91         , m_channels(channels)
92         , m_messagingProxy(messagingProxy)
93     {
94     }
95
96     virtual void performTask(ScriptExecutionContext* scriptContext)
97     {
98         Worker* workerObject = m_messagingProxy->workerObject();
99         if (!workerObject || m_messagingProxy->askedToTerminate())
100             return;
101
102         OwnPtr<MessagePortArray> ports = MessagePort::entanglePorts(*scriptContext, m_channels.release());
103         workerObject->dispatchEvent(MessageEvent::create(ports.release(), m_message));
104     }
105
106 private:
107     RefPtr<SerializedScriptValue> m_message;
108     OwnPtr<MessagePortChannelArray> m_channels;
109     WorkerMessagingProxy* m_messagingProxy;
110 };
111
112 class WorkerExceptionTask : public ScriptExecutionContext::Task {
113 public:
114     static PassOwnPtr<WorkerExceptionTask> create(const String& errorMessage, int lineNumber, const String& sourceURL, WorkerMessagingProxy* messagingProxy)
115     {
116         return adoptPtr(new WorkerExceptionTask(errorMessage, lineNumber, sourceURL, messagingProxy));
117     }
118
119 private:
120     WorkerExceptionTask(const String& errorMessage, int lineNumber, const String& sourceURL, WorkerMessagingProxy* messagingProxy)
121         : m_errorMessage(errorMessage.isolatedCopy())
122         , m_lineNumber(lineNumber)
123         , m_sourceURL(sourceURL.isolatedCopy())
124         , m_messagingProxy(messagingProxy)
125     {
126     }
127
128     virtual void performTask(ScriptExecutionContext* context)
129     {
130         Worker* workerObject = m_messagingProxy->workerObject();
131         if (!workerObject)
132             return;
133
134         // We don't bother checking the askedToTerminate() flag here, because exceptions should *always* be reported even if the thread is terminated.
135         // This is intentionally different than the behavior in MessageWorkerTask, because terminated workers no longer deliver messages (section 4.6 of the WebWorker spec), but they do report exceptions.
136
137         bool errorHandled = !workerObject->dispatchEvent(ErrorEvent::create(m_errorMessage, m_sourceURL, m_lineNumber));
138         if (!errorHandled)
139             context->reportException(m_errorMessage, m_lineNumber, m_sourceURL, 0);
140     }
141
142     String m_errorMessage;
143     int m_lineNumber;
144     String m_sourceURL;
145     WorkerMessagingProxy* m_messagingProxy;
146 };
147
148 class WorkerContextDestroyedTask : public ScriptExecutionContext::Task {
149 public:
150     static PassOwnPtr<WorkerContextDestroyedTask> create(WorkerMessagingProxy* messagingProxy)
151     {
152         return adoptPtr(new WorkerContextDestroyedTask(messagingProxy));
153     }
154
155 private:
156     WorkerContextDestroyedTask(WorkerMessagingProxy* messagingProxy)
157         : m_messagingProxy(messagingProxy)
158     {
159     }
160
161     virtual void performTask(ScriptExecutionContext*)
162     {
163         m_messagingProxy->workerContextDestroyedInternal();
164     }
165
166     WorkerMessagingProxy* m_messagingProxy;
167 };
168
169 class WorkerTerminateTask : public ScriptExecutionContext::Task {
170 public:
171     static PassOwnPtr<WorkerTerminateTask> create(WorkerMessagingProxy* messagingProxy)
172     {
173         return adoptPtr(new WorkerTerminateTask(messagingProxy));
174     }
175
176 private:
177     WorkerTerminateTask(WorkerMessagingProxy* messagingProxy)
178         : m_messagingProxy(messagingProxy)
179     {
180     }
181
182     virtual void performTask(ScriptExecutionContext*)
183     {
184         m_messagingProxy->terminateWorkerContext();
185     }
186
187     WorkerMessagingProxy* m_messagingProxy;
188 };
189
190 class WorkerThreadActivityReportTask : public ScriptExecutionContext::Task {
191 public:
192     static PassOwnPtr<WorkerThreadActivityReportTask> create(WorkerMessagingProxy* messagingProxy, bool confirmingMessage, bool hasPendingActivity)
193     {
194         return adoptPtr(new WorkerThreadActivityReportTask(messagingProxy, confirmingMessage, hasPendingActivity));
195     }
196
197 private:
198     WorkerThreadActivityReportTask(WorkerMessagingProxy* messagingProxy, bool confirmingMessage, bool hasPendingActivity)
199         : m_messagingProxy(messagingProxy)
200         , m_confirmingMessage(confirmingMessage)
201         , m_hasPendingActivity(hasPendingActivity)
202     {
203     }
204
205     virtual void performTask(ScriptExecutionContext*)
206     {
207         m_messagingProxy->reportPendingActivityInternal(m_confirmingMessage, m_hasPendingActivity);
208     }
209
210     WorkerMessagingProxy* m_messagingProxy;
211     bool m_confirmingMessage;
212     bool m_hasPendingActivity;
213 };
214
215 class PostMessageToPageInspectorTask : public ScriptExecutionContext::Task {
216 public:
217     static PassOwnPtr<PostMessageToPageInspectorTask> create(WorkerMessagingProxy* messagingProxy, const String& message)
218     {
219         return adoptPtr(new PostMessageToPageInspectorTask(messagingProxy, message));
220     }
221
222 private:
223     PostMessageToPageInspectorTask(WorkerMessagingProxy* messagingProxy, const String& message)
224         : m_messagingProxy(messagingProxy)
225         , m_message(message.isolatedCopy())
226     {
227     }
228
229     virtual void performTask(ScriptExecutionContext*)
230     {
231 #if ENABLE(INSPECTOR)
232         if (WorkerContextProxy::PageInspector* pageInspector = m_messagingProxy->m_pageInspector)
233             pageInspector->dispatchMessageFromWorker(m_message);
234 #endif
235     }
236
237     WorkerMessagingProxy* m_messagingProxy;
238     String m_message;
239 };
240
241
242 #if !PLATFORM(CHROMIUM)
243 WorkerContextProxy* WorkerContextProxy::create(Worker* worker)
244 {
245     return new WorkerMessagingProxy(worker);
246 }
247 #endif
248
249 WorkerMessagingProxy::WorkerMessagingProxy(Worker* workerObject)
250     : m_scriptExecutionContext(workerObject->scriptExecutionContext())
251     , m_workerObject(workerObject)
252     , m_unconfirmedMessageCount(0)
253     , m_workerThreadHadPendingActivity(false)
254     , m_askedToTerminate(false)
255 #if ENABLE(INSPECTOR)
256     , m_pageInspector(0)
257 #endif
258 {
259     ASSERT(m_workerObject);
260     ASSERT((m_scriptExecutionContext->isDocument() && isMainThread())
261            || (m_scriptExecutionContext->isWorkerContext() && currentThread() == static_cast<WorkerContext*>(m_scriptExecutionContext.get())->thread()->threadID()));
262 }
263
264 WorkerMessagingProxy::~WorkerMessagingProxy()
265 {
266     ASSERT(!m_workerObject);
267     ASSERT((m_scriptExecutionContext->isDocument() && isMainThread())
268            || (m_scriptExecutionContext->isWorkerContext() && currentThread() == static_cast<WorkerContext*>(m_scriptExecutionContext.get())->thread()->threadID()));
269 }
270
271 void WorkerMessagingProxy::startWorkerContext(const KURL& scriptURL, const String& userAgent, const String& sourceCode, WorkerThreadStartMode startMode)
272 {
273     RefPtr<DedicatedWorkerThread> thread = DedicatedWorkerThread::create(scriptURL, userAgent, sourceCode, *this, *this, startMode);
274     workerThreadCreated(thread);
275     thread->start();
276 }
277
278 void WorkerMessagingProxy::postMessageToWorkerObject(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels)
279 {
280     m_scriptExecutionContext->postTask(MessageWorkerTask::create(message, channels, this));
281 }
282
283 void WorkerMessagingProxy::postMessageToWorkerContext(PassRefPtr<SerializedScriptValue> message, PassOwnPtr<MessagePortChannelArray> channels)
284 {
285     if (m_askedToTerminate)
286         return;
287
288     if (m_workerThread) {
289         ++m_unconfirmedMessageCount;
290         m_workerThread->runLoop().postTask(MessageWorkerContextTask::create(message, channels));
291     } else
292         m_queuedEarlyTasks.append(MessageWorkerContextTask::create(message, channels));
293 }
294
295 void WorkerMessagingProxy::postTaskForModeToWorkerContext(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
296 {
297     if (m_askedToTerminate)
298         return;
299
300     ASSERT(m_workerThread);
301     m_workerThread->runLoop().postTaskForMode(task, mode);
302 }
303
304 void WorkerMessagingProxy::postTaskToLoader(PassOwnPtr<ScriptExecutionContext::Task> task)
305 {
306     // FIXME: In case of nested workers, this should go directly to the root Document context.
307     ASSERT(m_scriptExecutionContext->isDocument());
308     m_scriptExecutionContext->postTask(task);
309 }
310
311 void WorkerMessagingProxy::postExceptionToWorkerObject(const String& errorMessage, int lineNumber, const String& sourceURL)
312 {
313     m_scriptExecutionContext->postTask(WorkerExceptionTask::create(errorMessage, lineNumber, sourceURL, this));
314 }
315     
316 static void postConsoleMessageTask(ScriptExecutionContext* context, WorkerMessagingProxy* messagingProxy, MessageSource source, MessageType type, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL)
317 {
318     if (messagingProxy->askedToTerminate())
319         return;
320     context->addMessage(source, type, level, message, lineNumber, sourceURL, 0);
321 }
322
323 void WorkerMessagingProxy::postConsoleMessageToWorkerObject(MessageSource source, MessageType type, MessageLevel level, const String& message, int lineNumber, const String& sourceURL)
324 {
325     m_scriptExecutionContext->postTask(
326         createCallbackTask(&postConsoleMessageTask, AllowCrossThreadAccess(this),
327                            source, type, level, message, lineNumber, sourceURL));
328 }
329
330 void WorkerMessagingProxy::workerThreadCreated(PassRefPtr<DedicatedWorkerThread> workerThread)
331 {
332     m_workerThread = workerThread;
333
334     if (m_askedToTerminate) {
335         // Worker.terminate() could be called from JS before the thread was created.
336         m_workerThread->stop();
337     } else {
338         unsigned taskCount = m_queuedEarlyTasks.size();
339         ASSERT(!m_unconfirmedMessageCount);
340         m_unconfirmedMessageCount = taskCount;
341         m_workerThreadHadPendingActivity = true; // Worker initialization means a pending activity.
342
343         for (unsigned i = 0; i < taskCount; ++i)
344             m_workerThread->runLoop().postTask(m_queuedEarlyTasks[i].release());
345         m_queuedEarlyTasks.clear();
346     }
347 }
348
349 void WorkerMessagingProxy::workerObjectDestroyed()
350 {
351     m_workerObject = 0;
352     if (m_workerThread)
353         terminateWorkerContext();
354     else
355         workerContextDestroyedInternal();
356 }
357
358 #if ENABLE(INSPECTOR)
359 #if ENABLE(JAVASCRIPT_DEBUGGER)
360 static void connectToWorkerContextInspectorTask(ScriptExecutionContext* context, bool)
361 {
362     ASSERT(context->isWorkerContext());
363     static_cast<WorkerContext*>(context)->workerInspectorController()->connectFrontend();
364 }
365 #endif
366
367 void WorkerMessagingProxy::connectToInspector(WorkerContextProxy::PageInspector* pageInspector)
368 {
369     if (m_askedToTerminate)
370         return;
371     ASSERT(!m_pageInspector);
372     m_pageInspector = pageInspector;
373 #if ENABLE(JAVASCRIPT_DEBUGGER)
374     m_workerThread->runLoop().postTaskForMode(createCallbackTask(connectToWorkerContextInspectorTask, true), WorkerDebuggerAgent::debuggerTaskMode);
375 #endif
376 }
377
378 #if ENABLE(JAVASCRIPT_DEBUGGER)
379 static void disconnectFromWorkerContextInspectorTask(ScriptExecutionContext* context, bool)
380 {
381     ASSERT(context->isWorkerContext());
382     static_cast<WorkerContext*>(context)->workerInspectorController()->disconnectFrontend();
383 }
384 #endif
385
386 void WorkerMessagingProxy::disconnectFromInspector()
387 {
388     m_pageInspector = 0;
389     if (m_askedToTerminate)
390         return;
391 #if ENABLE(JAVASCRIPT_DEBUGGER)
392     m_workerThread->runLoop().postTaskForMode(createCallbackTask(disconnectFromWorkerContextInspectorTask, true), WorkerDebuggerAgent::debuggerTaskMode);
393 #endif
394 }
395
396 #if ENABLE(JAVASCRIPT_DEBUGGER)
397 static void dispatchOnInspectorBackendTask(ScriptExecutionContext* context, const String& message)
398 {
399     ASSERT(context->isWorkerContext());
400     static_cast<WorkerContext*>(context)->workerInspectorController()->dispatchMessageFromFrontend(message);
401 }
402 #endif
403
404 void WorkerMessagingProxy::sendMessageToInspector(const String& message)
405 {
406     if (m_askedToTerminate)
407         return;
408 #if ENABLE(JAVASCRIPT_DEBUGGER)
409     m_workerThread->runLoop().postTaskForMode(createCallbackTask(dispatchOnInspectorBackendTask, String(message)), WorkerDebuggerAgent::debuggerTaskMode);
410 #endif
411 }
412 #endif
413
414 void WorkerMessagingProxy::workerContextDestroyed()
415 {
416     m_scriptExecutionContext->postTask(WorkerContextDestroyedTask::create(this));
417     // Will execute workerContextDestroyedInternal() on context's thread.
418 }
419
420 void WorkerMessagingProxy::workerContextClosed()
421 {
422     // Executes terminateWorkerContext() on parent context's thread.
423     m_scriptExecutionContext->postTask(WorkerTerminateTask::create(this));
424 }
425
426 void WorkerMessagingProxy::workerContextDestroyedInternal()
427 {
428     // WorkerContextDestroyedTask is always the last to be performed, so the proxy is not needed for communication
429     // in either side any more. However, the Worker object may still exist, and it assumes that the proxy exists, too.
430     m_askedToTerminate = true;
431     m_workerThread = 0;
432
433     InspectorInstrumentation::workerContextTerminated(m_scriptExecutionContext.get(), this);
434
435     if (!m_workerObject)
436         delete this;
437 }
438
439 void WorkerMessagingProxy::terminateWorkerContext()
440 {
441     if (m_askedToTerminate)
442         return;
443     m_askedToTerminate = true;
444
445     if (m_workerThread)
446         m_workerThread->stop();
447
448     InspectorInstrumentation::workerContextTerminated(m_scriptExecutionContext.get(), this);
449 }
450
451 #if ENABLE(INSPECTOR)
452 void WorkerMessagingProxy::postMessageToPageInspector(const String& message)
453 {
454     m_scriptExecutionContext->postTask(PostMessageToPageInspectorTask::create(this, message));
455 }
456
457 void WorkerMessagingProxy::updateInspectorStateCookie(const String&)
458 {
459     notImplemented();
460 }
461 #endif
462
463 void WorkerMessagingProxy::confirmMessageFromWorkerObject(bool hasPendingActivity)
464 {
465     m_scriptExecutionContext->postTask(WorkerThreadActivityReportTask::create(this, true, hasPendingActivity));
466     // Will execute reportPendingActivityInternal() on context's thread.
467 }
468
469 void WorkerMessagingProxy::reportPendingActivity(bool hasPendingActivity)
470 {
471     m_scriptExecutionContext->postTask(WorkerThreadActivityReportTask::create(this, false, hasPendingActivity));
472     // Will execute reportPendingActivityInternal() on context's thread.
473 }
474
475 void WorkerMessagingProxy::reportPendingActivityInternal(bool confirmingMessage, bool hasPendingActivity)
476 {
477     if (confirmingMessage && !m_askedToTerminate) {
478         ASSERT(m_unconfirmedMessageCount);
479         --m_unconfirmedMessageCount;
480     }
481
482     m_workerThreadHadPendingActivity = hasPendingActivity;
483 }
484
485 bool WorkerMessagingProxy::hasPendingActivity() const
486 {
487     return (m_unconfirmedMessageCount || m_workerThreadHadPendingActivity) && !m_askedToTerminate;
488 }
489
490 } // namespace WebCore
491
492 #endif // ENABLE(WORKERS)