diff options
author | Feng Qian <> | 2009-04-10 18:11:29 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-04-10 18:11:29 -0700 |
commit | 8f72e70a9fd78eec56623b3a62e68f16b7b27e28 (patch) | |
tree | 181bf9a400c30a1bf34ea6d72560e8d00111d549 /WebCore/workers | |
parent | 7ed56f225e0ade046e1c2178977f72b2d896f196 (diff) | |
download | external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.zip external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.tar.gz external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.tar.bz2 |
AI 145796: Land the WebKit merge @r42026.
Automated import of CL 145796
Diffstat (limited to 'WebCore/workers')
-rw-r--r-- | WebCore/workers/GenericWorkerTask.h | 415 | ||||
-rw-r--r-- | WebCore/workers/Worker.cpp | 212 | ||||
-rw-r--r-- | WebCore/workers/Worker.h | 111 | ||||
-rw-r--r-- | WebCore/workers/Worker.idl | 48 | ||||
-rw-r--r-- | WebCore/workers/WorkerContext.cpp | 269 | ||||
-rw-r--r-- | WebCore/workers/WorkerContext.h | 134 | ||||
-rw-r--r-- | WebCore/workers/WorkerContext.idl | 71 | ||||
-rw-r--r-- | WebCore/workers/WorkerContextProxy.h | 64 | ||||
-rw-r--r-- | WebCore/workers/WorkerImportScriptsClient.cpp | 96 | ||||
-rw-r--r-- | WebCore/workers/WorkerImportScriptsClient.h | 77 | ||||
-rw-r--r-- | WebCore/workers/WorkerLocation.cpp | 85 | ||||
-rw-r--r-- | WebCore/workers/WorkerLocation.h | 73 | ||||
-rw-r--r-- | WebCore/workers/WorkerLocation.idl | 48 | ||||
-rw-r--r-- | WebCore/workers/WorkerMessagingProxy.cpp | 343 | ||||
-rw-r--r-- | WebCore/workers/WorkerMessagingProxy.h | 104 | ||||
-rw-r--r-- | WebCore/workers/WorkerObjectProxy.h | 64 | ||||
-rw-r--r-- | WebCore/workers/WorkerRunLoop.cpp | 210 | ||||
-rw-r--r-- | WebCore/workers/WorkerRunLoop.h | 82 | ||||
-rw-r--r-- | WebCore/workers/WorkerThread.cpp | 153 | ||||
-rw-r--r-- | WebCore/workers/WorkerThread.h | 78 |
20 files changed, 2737 insertions, 0 deletions
diff --git a/WebCore/workers/GenericWorkerTask.h b/WebCore/workers/GenericWorkerTask.h new file mode 100644 index 0000000..96b0e70 --- /dev/null +++ b/WebCore/workers/GenericWorkerTask.h @@ -0,0 +1,415 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef GenericWorkerTask_h +#define GenericWorkerTask_h + +#if ENABLE(WORKERS) + +#include "CrossThreadCopier.h" +#include "ScriptExecutionContext.h" +#include <memory> +#include <wtf/PassRefPtr.h> +#include <wtf/TypeTraits.h> + +namespace WebCore { + + // Traits for the GenericWorkerTask. + template<typename T> struct GenericWorkerTaskTraits { + typedef const T& ParamType; + }; + + template<typename T> struct GenericWorkerTaskTraits<T*> { + typedef T* ParamType; + }; + + template<typename T> struct GenericWorkerTaskTraits<std::auto_ptr<T> > { + typedef std::auto_ptr<T> ParamType; + }; + + template<typename T> struct GenericWorkerTaskTraits<PassRefPtr<T> > { + typedef PassRefPtr<T> ParamType; + }; + + template<typename P1, typename MP1> + class GenericWorkerTask1 : public ScriptExecutionContext::Task { + public: + typedef void (*Method)(ScriptExecutionContext*, MP1); + typedef GenericWorkerTask1<P1, MP1> GenericWorkerTask; + typedef typename GenericWorkerTaskTraits<P1>::ParamType Param1; + + static PassRefPtr<GenericWorkerTask> create(Method method, Param1 parameter1) + { + return adoptRef(new GenericWorkerTask(method, parameter1)); + } + + private: + GenericWorkerTask1(Method method, Param1 parameter1) + : m_method(method) + , m_parameter1(parameter1) + { + } + + virtual void performTask(ScriptExecutionContext* context) + { + (*m_method)(context, m_parameter1); + } + + private: + Method m_method; + P1 m_parameter1; + }; + + template<typename P1, typename MP1, typename P2, typename MP2> + class GenericWorkerTask2 : public ScriptExecutionContext::Task { + public: + typedef void (*Method)(ScriptExecutionContext*, MP1, MP2); + typedef GenericWorkerTask2<P1, MP1, P2, MP2> GenericWorkerTask; + typedef typename GenericWorkerTaskTraits<P1>::ParamType Param1; + typedef typename GenericWorkerTaskTraits<P2>::ParamType Param2; + + static PassRefPtr<GenericWorkerTask> create(Method method, Param1 parameter1, Param2 parameter2) + { + return adoptRef(new GenericWorkerTask(method, parameter1, parameter2)); + } + + private: + GenericWorkerTask2(Method method, Param1 parameter1, Param2 parameter2) + : m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + { + } + + virtual void performTask(ScriptExecutionContext* context) + { + (*m_method)(context, m_parameter1, m_parameter2); + } + + private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; + }; + + template<typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> + class GenericWorkerTask3 : public ScriptExecutionContext::Task { + public: + typedef void (*Method)(ScriptExecutionContext*, MP1, MP2, MP3); + typedef GenericWorkerTask3<P1, MP1, P2, MP2, P3, MP3> GenericWorkerTask; + typedef typename GenericWorkerTaskTraits<P1>::ParamType Param1; + typedef typename GenericWorkerTaskTraits<P2>::ParamType Param2; + typedef typename GenericWorkerTaskTraits<P3>::ParamType Param3; + + static PassRefPtr<GenericWorkerTask> create(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) + { + return adoptRef(new GenericWorkerTask(method, parameter1, parameter2, parameter3)); + } + + private: + GenericWorkerTask3(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3) + : m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + , m_parameter3(parameter3) + { + } + + virtual void performTask(ScriptExecutionContext* context) + { + (*m_method)(context, m_parameter1, m_parameter2, m_parameter3); + } + + private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; + P3 m_parameter3; + }; + + template<typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3, typename P4, typename MP4> + class GenericWorkerTask4 : public ScriptExecutionContext::Task { + public: + typedef void (*Method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4); + typedef GenericWorkerTask4<P1, MP1, P2, MP2, P3, MP3, P4, MP4> GenericWorkerTask; + typedef typename GenericWorkerTaskTraits<P1>::ParamType Param1; + typedef typename GenericWorkerTaskTraits<P2>::ParamType Param2; + typedef typename GenericWorkerTaskTraits<P3>::ParamType Param3; + typedef typename GenericWorkerTaskTraits<P4>::ParamType Param4; + + static PassRefPtr<GenericWorkerTask> create(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4) + { + return adoptRef(new GenericWorkerTask(method, parameter1, parameter2, parameter3, parameter4)); + } + + private: + GenericWorkerTask4(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4) + : m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + , m_parameter3(parameter3) + , m_parameter4(parameter4) + { + } + + virtual void performTask(ScriptExecutionContext* context) + { + (*m_method)(context, m_parameter1, m_parameter2, m_parameter3, m_parameter4); + } + + private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; + P3 m_parameter3; + P4 m_parameter4; + }; + + template<typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3, typename P4, typename MP4, typename P5, typename MP5> + class GenericWorkerTask5 : public ScriptExecutionContext::Task { + public: + typedef void (*Method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5); + typedef GenericWorkerTask5<P1, MP1, P2, MP2, P3, MP3, P4, MP4, P5, MP5> GenericWorkerTask; + typedef typename GenericWorkerTaskTraits<P1>::ParamType Param1; + typedef typename GenericWorkerTaskTraits<P2>::ParamType Param2; + typedef typename GenericWorkerTaskTraits<P3>::ParamType Param3; + typedef typename GenericWorkerTaskTraits<P4>::ParamType Param4; + typedef typename GenericWorkerTaskTraits<P5>::ParamType Param5; + + static PassRefPtr<GenericWorkerTask> create(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5) + { + return adoptRef(new GenericWorkerTask(method, parameter1, parameter2, parameter3, parameter4, parameter5)); + } + + private: + GenericWorkerTask5(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5) + : m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + , m_parameter3(parameter3) + , m_parameter4(parameter4) + , m_parameter5(parameter5) + { + } + + virtual void performTask(ScriptExecutionContext* context) + { + (*m_method)(context, m_parameter1, m_parameter2, m_parameter3, m_parameter4, m_parameter5); + } + + private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; + P3 m_parameter3; + P4 m_parameter4; + P5 m_parameter5; + }; + + template<typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3, typename P4, typename MP4, typename P5, typename MP5, typename P6, typename MP6> + class GenericWorkerTask6 : public ScriptExecutionContext::Task { + public: + typedef void (*Method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5, MP6); + typedef GenericWorkerTask6<P1, MP1, P2, MP2, P3, MP3, P4, MP4, P5, MP5, P6, MP6> GenericWorkerTask; + typedef typename GenericWorkerTaskTraits<P1>::ParamType Param1; + typedef typename GenericWorkerTaskTraits<P2>::ParamType Param2; + typedef typename GenericWorkerTaskTraits<P3>::ParamType Param3; + typedef typename GenericWorkerTaskTraits<P4>::ParamType Param4; + typedef typename GenericWorkerTaskTraits<P5>::ParamType Param5; + typedef typename GenericWorkerTaskTraits<P6>::ParamType Param6; + + static PassRefPtr<GenericWorkerTask> create(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5, Param6 parameter6) + { + return adoptRef(new GenericWorkerTask(method, parameter1, parameter2, parameter3, parameter4, parameter5, parameter6)); + } + + private: + GenericWorkerTask6(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5, Param6 parameter6) + : m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + , m_parameter3(parameter3) + , m_parameter4(parameter4) + , m_parameter5(parameter5) + , m_parameter6(parameter6) + { + } + + virtual void performTask(ScriptExecutionContext* context) + { + (*m_method)(context, m_parameter1, m_parameter2, m_parameter3, m_parameter4, m_parameter5, m_parameter6); + } + + private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; + P3 m_parameter3; + P4 m_parameter4; + P5 m_parameter5; + P6 m_parameter6; + }; + + template<typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3, typename P4, typename MP4, typename P5, typename MP5, typename P6, typename MP6, typename P7, typename MP7> + class GenericWorkerTask7 : public ScriptExecutionContext::Task { + public: + typedef void (*Method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5, MP6, MP7); + typedef GenericWorkerTask7<P1, MP1, P2, MP2, P3, MP3, P4, MP4, P5, MP5, P6, MP6, P7, MP7> GenericWorkerTask; + typedef typename GenericWorkerTaskTraits<P1>::ParamType Param1; + typedef typename GenericWorkerTaskTraits<P2>::ParamType Param2; + typedef typename GenericWorkerTaskTraits<P3>::ParamType Param3; + typedef typename GenericWorkerTaskTraits<P4>::ParamType Param4; + typedef typename GenericWorkerTaskTraits<P5>::ParamType Param5; + typedef typename GenericWorkerTaskTraits<P6>::ParamType Param6; + typedef typename GenericWorkerTaskTraits<P7>::ParamType Param7; + + static PassRefPtr<GenericWorkerTask> create(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5, Param6 parameter6, Param7 parameter7) + { + return adoptRef(new GenericWorkerTask(method, parameter1, parameter2, parameter3, parameter4, parameter5, parameter6, parameter7)); + } + + private: + GenericWorkerTask7(Method method, Param1 parameter1, Param2 parameter2, Param3 parameter3, Param4 parameter4, Param5 parameter5, Param6 parameter6, Param7 parameter7) + : m_method(method) + , m_parameter1(parameter1) + , m_parameter2(parameter2) + , m_parameter3(parameter3) + , m_parameter4(parameter4) + , m_parameter5(parameter5) + , m_parameter6(parameter6) + , m_parameter7(parameter7) + { + } + + virtual void performTask(ScriptExecutionContext* context) + { + (*m_method)(context, m_parameter1, m_parameter2, m_parameter3, m_parameter4, m_parameter5, m_parameter6, m_parameter7); + } + + private: + Method m_method; + P1 m_parameter1; + P2 m_parameter2; + P3 m_parameter3; + P4 m_parameter4; + P5 m_parameter5; + P6 m_parameter6; + P7 m_parameter7; + }; + + template<typename P1, typename MP1> + PassRefPtr<ScriptExecutionContext::Task> createCallbackTask( + void (*method)(ScriptExecutionContext*, MP1), + const P1& parameter1) + { + return GenericWorkerTask1<typename CrossThreadCopier<P1>::Type, MP1>::create( + method, + CrossThreadCopier<P1>::copy(parameter1)); + } + + template<typename P1, typename MP1, typename P2, typename MP2> + PassRefPtr<ScriptExecutionContext::Task> createCallbackTask( + void (*method)(ScriptExecutionContext*, MP1, MP2), + const P1& parameter1, const P2& parameter2) + { + return GenericWorkerTask2<typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2>::create( + method, + CrossThreadCopier<P1>::copy(parameter1), CrossThreadCopier<P2>::copy(parameter2)); + } + + template<typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3> + PassRefPtr<ScriptExecutionContext::Task> createCallbackTask( + void (*method)(ScriptExecutionContext*, MP1, MP2, MP3), + const P1& parameter1, const P2& parameter2, const P3& parameter3) + { + return GenericWorkerTask3<typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3>::create( + method, + CrossThreadCopier<P1>::copy(parameter1), CrossThreadCopier<P2>::copy(parameter2), + CrossThreadCopier<P3>::copy(parameter3)); + } + + template<typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3, typename P4, typename MP4> + PassRefPtr<ScriptExecutionContext::Task> createCallbackTask( + void (*method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4), + const P1& parameter1, const P2& parameter2, const P3& parameter3, const P4& parameter4) + { + return GenericWorkerTask4<typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3, + typename CrossThreadCopier<P4>::Type, MP4>::create( + method, + CrossThreadCopier<P1>::copy(parameter1), CrossThreadCopier<P2>::copy(parameter2), + CrossThreadCopier<P3>::copy(parameter3), CrossThreadCopier<P4>::copy(parameter4)); + } + + template<typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3, typename P4, typename MP4, typename P5, typename MP5> + PassRefPtr<ScriptExecutionContext::Task> createCallbackTask( + void (*method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5), + const P1& parameter1, const P2& parameter2, const P3& parameter3, const P4& parameter4, const P5& parameter5) + { + return GenericWorkerTask5<typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3, + typename CrossThreadCopier<P4>::Type, MP4, typename CrossThreadCopier<P5>::Type, MP5>::create( + method, + CrossThreadCopier<P1>::copy(parameter1), CrossThreadCopier<P2>::copy(parameter2), + CrossThreadCopier<P3>::copy(parameter3), CrossThreadCopier<P4>::copy(parameter4), + CrossThreadCopier<P5>::copy(parameter5)); + } + + template<typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3, typename P4, typename MP4, typename P5, typename MP5, typename P6, typename MP6> + PassRefPtr<ScriptExecutionContext::Task> createCallbackTask( + void (*method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5, MP6), + const P1& parameter1, const P2& parameter2, const P3& parameter3, const P4& parameter4, const P5& parameter5, const P6& parameter6) + { + return GenericWorkerTask6<typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3, + typename CrossThreadCopier<P4>::Type, MP4, typename CrossThreadCopier<P5>::Type, MP5, typename CrossThreadCopier<P6>::Type, MP6>::create( + method, + CrossThreadCopier<P1>::copy(parameter1), CrossThreadCopier<P2>::copy(parameter2), + CrossThreadCopier<P3>::copy(parameter3), CrossThreadCopier<P4>::copy(parameter4), + CrossThreadCopier<P5>::copy(parameter5), CrossThreadCopier<P6>::copy(parameter6)); + } + + template<typename P1, typename MP1, typename P2, typename MP2, typename P3, typename MP3, typename P4, typename MP4, typename P5, typename MP5, typename P6, typename MP6, typename P7, typename MP7> + PassRefPtr<ScriptExecutionContext::Task> createCallbackTask( + void (*method)(ScriptExecutionContext*, MP1, MP2, MP3, MP4, MP5, MP6, MP7), + const P1& parameter1, const P2& parameter2, const P3& parameter3, const P4& parameter4, const P5& parameter5, const P6& parameter6, const P7& parameter7) + { + return GenericWorkerTask7<typename CrossThreadCopier<P1>::Type, MP1, typename CrossThreadCopier<P2>::Type, MP2, typename CrossThreadCopier<P3>::Type, MP3, + typename CrossThreadCopier<P4>::Type, MP4, typename CrossThreadCopier<P5>::Type, MP5, typename CrossThreadCopier<P6>::Type, MP6, + typename CrossThreadCopier<P7>::Type, MP7>::create( + method, + CrossThreadCopier<P1>::copy(parameter1), CrossThreadCopier<P2>::copy(parameter2), + CrossThreadCopier<P3>::copy(parameter3), CrossThreadCopier<P4>::copy(parameter4), + CrossThreadCopier<P5>::copy(parameter5), CrossThreadCopier<P6>::copy(parameter6), + CrossThreadCopier<P7>::copy(parameter7)); + } + +} // namespace WebCore + +#endif // ENABLE(WORKERS) + +#endif // GenericWorkerTask_h diff --git a/WebCore/workers/Worker.cpp b/WebCore/workers/Worker.cpp new file mode 100644 index 0000000..85ba690 --- /dev/null +++ b/WebCore/workers/Worker.cpp @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Google Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" + +#if ENABLE(WORKERS) + +#include "Worker.h" + +#include "CachedScript.h" +#include "DOMWindow.h" +#include "DocLoader.h" +#include "Document.h" +#include "EventException.h" +#include "EventListener.h" +#include "EventNames.h" +#include "ExceptionCode.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "MessageEvent.h" +#include "SecurityOrigin.h" +#include "TextEncoding.h" +#include "WorkerContextProxy.h" +#include "WorkerThread.h" +#include <wtf/MainThread.h> + +namespace WebCore { + +Worker::Worker(const String& url, ScriptExecutionContext* context, ExceptionCode& ec) + : ActiveDOMObject(context, this) + , m_contextProxy(WorkerContextProxy::create(this)) +{ + m_scriptURL = context->completeURL(url); + if (url.isEmpty() || !m_scriptURL.isValid()) { + ec = SYNTAX_ERR; + return; + } + + if (!context->securityOrigin()->canAccess(SecurityOrigin::create(m_scriptURL).get())) { + ec = SECURITY_ERR; + return; + } + + // FIXME: Nested workers need loading support. Consider adopting ThreadableLoader here. + ASSERT(scriptExecutionContext()->isDocument()); + Document* document = static_cast<Document*>(scriptExecutionContext()); + + m_cachedScript = document->docLoader()->requestScript(m_scriptURL, "UTF-8"); + if (!m_cachedScript) { + dispatchErrorEvent(); + return; + } + + setPendingActivity(this); // The worker context does not exist while loading, so we must ensure that the worker object is not collected, as well as its event listeners. + m_cachedScript->addClient(this); +} + +Worker::~Worker() +{ + ASSERT(isMainThread()); + ASSERT(scriptExecutionContext()); // The context is protected by worker context proxy, so it cannot be destroyed while a Worker exists. + m_contextProxy->workerObjectDestroyed(); +} + +void Worker::postMessage(const String& message) +{ + m_contextProxy->postMessageToWorkerContext(message); +} + +void Worker::terminate() +{ + m_contextProxy->terminateWorkerContext(); +} + +bool Worker::canSuspend() const +{ + // FIXME: It is not currently possible to suspend a worker, so pages with workers can not go into page cache. + return false; +} + +void Worker::stop() +{ + terminate(); +} + +bool Worker::hasPendingActivity() const +{ + return m_contextProxy->hasPendingActivity() || ActiveDOMObject::hasPendingActivity(); +} + +void Worker::notifyFinished(CachedResource* unusedResource) +{ + ASSERT_UNUSED(unusedResource, unusedResource == m_cachedScript); + + if (m_cachedScript->errorOccurred()) + dispatchErrorEvent(); + else + m_contextProxy->startWorkerContext(m_scriptURL, scriptExecutionContext()->userAgent(m_scriptURL), m_cachedScript->script()); + + m_cachedScript->removeClient(this); + m_cachedScript = 0; + + unsetPendingActivity(this); +} + +void Worker::dispatchErrorEvent() +{ + RefPtr<Event> evt = Event::create(eventNames().errorEvent, false, true); + if (m_onErrorListener) { + evt->setTarget(this); + evt->setCurrentTarget(this); + m_onErrorListener->handleEvent(evt.get(), true); + } + + ExceptionCode ec = 0; + dispatchEvent(evt.release(), ec); + ASSERT(!ec); +} + +void Worker::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> eventListener, bool) +{ + EventListenersMap::iterator iter = m_eventListeners.find(eventType); + if (iter == m_eventListeners.end()) { + ListenerVector listeners; + listeners.append(eventListener); + m_eventListeners.add(eventType, listeners); + } else { + ListenerVector& listeners = iter->second; + for (ListenerVector::iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) { + if (*listenerIter == eventListener) + return; + } + + listeners.append(eventListener); + m_eventListeners.add(eventType, listeners); + } +} + +void Worker::removeEventListener(const AtomicString& eventType, EventListener* eventListener, bool) +{ + EventListenersMap::iterator iter = m_eventListeners.find(eventType); + if (iter == m_eventListeners.end()) + return; + + ListenerVector& listeners = iter->second; + for (ListenerVector::const_iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) { + if (*listenerIter == eventListener) { + listeners.remove(listenerIter - listeners.begin()); + return; + } + } +} + +bool Worker::dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec) +{ + if (!event || event->type().isEmpty()) { + ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR; + return true; + } + + ListenerVector listenersCopy = m_eventListeners.get(event->type()); + for (ListenerVector::const_iterator listenerIter = listenersCopy.begin(); listenerIter != listenersCopy.end(); ++listenerIter) { + event->setTarget(this); + event->setCurrentTarget(this); + listenerIter->get()->handleEvent(event.get(), false); + } + + return !event->defaultPrevented(); +} + +void Worker::dispatchMessage(const String& message) +{ + RefPtr<Event> evt = MessageEvent::create(message, "", "", 0, 0); + + if (m_onMessageListener.get()) { + evt->setTarget(this); + evt->setCurrentTarget(this); + m_onMessageListener->handleEvent(evt.get(), false); + } + + ExceptionCode ec = 0; + dispatchEvent(evt.release(), ec); + ASSERT(!ec); +} + +} // namespace WebCore + +#endif // ENABLE(WORKERS) diff --git a/WebCore/workers/Worker.h b/WebCore/workers/Worker.h new file mode 100644 index 0000000..d05f9d5 --- /dev/null +++ b/WebCore/workers/Worker.h @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef Worker_h +#define Worker_h + +#if ENABLE(WORKERS) + +#include "AtomicStringHash.h" +#include "ActiveDOMObject.h" +#include "CachedResourceClient.h" +#include "CachedResourceHandle.h" +#include "EventListener.h" +#include "EventTarget.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class CachedResource; + class CachedScript; + class ScriptExecutionContext; + class String; + class WorkerContextProxy; + + typedef int ExceptionCode; + + class Worker : public RefCounted<Worker>, public ActiveDOMObject, private CachedResourceClient, public EventTarget { + public: + static PassRefPtr<Worker> create(const String& url, ScriptExecutionContext* context, ExceptionCode& ec) { return adoptRef(new Worker(url, context, ec)); } + ~Worker(); + + virtual ScriptExecutionContext* scriptExecutionContext() const { return ActiveDOMObject::scriptExecutionContext(); } + + virtual Worker* toWorker() { return this; } + + void postMessage(const String& message); + + void terminate(); + + void dispatchMessage(const String&); + void dispatchErrorEvent(); + + virtual bool canSuspend() const; + virtual void stop(); + virtual bool hasPendingActivity() const; + + virtual void addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture); + virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture); + virtual bool dispatchEvent(PassRefPtr<Event>, ExceptionCode&); + + typedef Vector<RefPtr<EventListener> > ListenerVector; + typedef HashMap<AtomicString, ListenerVector> EventListenersMap; + EventListenersMap& eventListeners() { return m_eventListeners; } + + using RefCounted<Worker>::ref; + using RefCounted<Worker>::deref; + + void setOnmessage(PassRefPtr<EventListener> eventListener) { m_onMessageListener = eventListener; } + EventListener* onmessage() const { return m_onMessageListener.get(); } + + void setOnerror(PassRefPtr<EventListener> eventListener) { m_onErrorListener = eventListener; } + EventListener* onerror() const { return m_onErrorListener.get(); } + + private: + Worker(const String&, ScriptExecutionContext*, ExceptionCode&); + + virtual void notifyFinished(CachedResource*); + + virtual void refEventTarget() { ref(); } + virtual void derefEventTarget() { deref(); } + + KURL m_scriptURL; + CachedResourceHandle<CachedScript> m_cachedScript; + + WorkerContextProxy* m_contextProxy; // The proxy outlives the worker to perform thread shutdown. + + RefPtr<EventListener> m_onMessageListener; + RefPtr<EventListener> m_onErrorListener; + EventListenersMap m_eventListeners; + }; + +} // namespace WebCore + +#endif // ENABLE(WORKERS) + +#endif // Worker_h diff --git a/WebCore/workers/Worker.idl b/WebCore/workers/Worker.idl new file mode 100644 index 0000000..2ef9b62 --- /dev/null +++ b/WebCore/workers/Worker.idl @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +module threads { + + interface [CustomMarkFunction, Conditional=WORKERS] Worker { + + attribute EventListener onerror; + attribute EventListener onmessage; + void postMessage(in DOMString message); + + void terminate(); + + // EventTarget interface + [Custom] void addEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); + [Custom] void removeEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); + boolean dispatchEvent(in Event evt) + raises(EventException); + }; + +} diff --git a/WebCore/workers/WorkerContext.cpp b/WebCore/workers/WorkerContext.cpp new file mode 100644 index 0000000..69ef472 --- /dev/null +++ b/WebCore/workers/WorkerContext.cpp @@ -0,0 +1,269 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Google Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" + +#if ENABLE(WORKERS) + +#include "WorkerContext.h" + +#include "ActiveDOMObject.h" +#include "DOMTimer.h" +#include "DOMWindow.h" +#include "Event.h" +#include "EventException.h" +#include "MessageEvent.h" +#include "NotImplemented.h" +#include "ResourceRequest.h" +#include "ScriptSourceCode.h" +#include "ScriptValue.h" +#include "SecurityOrigin.h" +#include "ThreadableLoader.h" +#include "WorkerImportScriptsClient.h" +#include "WorkerLocation.h" +#include "WorkerNavigator.h" +#include "WorkerObjectProxy.h" +#include "WorkerThread.h" +#include "XMLHttpRequestException.h" +#include <wtf/RefPtr.h> + +namespace WebCore { + +WorkerContext::WorkerContext(const KURL& url, const String& userAgent, WorkerThread* thread) + : m_url(url) + , m_userAgent(userAgent) + , m_location(WorkerLocation::create(url)) + , m_script(new WorkerScriptController(this)) + , m_thread(thread) +{ + setSecurityOrigin(SecurityOrigin::create(url)); +} + +WorkerContext::~WorkerContext() +{ + ASSERT(currentThread() == m_thread->threadID()); + + m_thread->workerObjectProxy()->workerContextDestroyed(); +} + +ScriptExecutionContext* WorkerContext::scriptExecutionContext() const +{ + return const_cast<WorkerContext*>(this); +} + +const KURL& WorkerContext::virtualURL() const +{ + return m_url; +} + +KURL WorkerContext::virtualCompleteURL(const String& url) const +{ + return completeURL(url); +} + +KURL WorkerContext::completeURL(const String& url) const +{ + // Always return a null URL when passed a null string. + // FIXME: Should we change the KURL constructor to have this behavior? + if (url.isNull()) + return KURL(); + // Always use UTF-8 in Workers. + return KURL(m_location->url(), url); +} + +String WorkerContext::userAgent(const KURL&) const +{ + return m_userAgent; +} + +WorkerNavigator* WorkerContext::navigator() const +{ + if (!m_navigator) + m_navigator = WorkerNavigator::create(m_userAgent); + return m_navigator.get(); +} + +bool WorkerContext::hasPendingActivity() const +{ + ActiveDOMObjectsMap& activeObjects = activeDOMObjects(); + ActiveDOMObjectsMap::const_iterator activeObjectsEnd = activeObjects.end(); + for (ActiveDOMObjectsMap::const_iterator iter = activeObjects.begin(); iter != activeObjectsEnd; ++iter) { + if (iter->first->hasPendingActivity()) + return true; + } + return false; +} + +void WorkerContext::reportException(const String& errorMessage, int lineNumber, const String& sourceURL) +{ + m_thread->workerObjectProxy()->postExceptionToWorkerObject(errorMessage, lineNumber, sourceURL); +} + +void WorkerContext::addMessage(MessageDestination destination, MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL) +{ + m_thread->workerObjectProxy()->postConsoleMessageToWorkerObject(destination, source, level, message, lineNumber, sourceURL); +} + +void WorkerContext::resourceRetrievedByXMLHttpRequest(unsigned long, const ScriptString&) +{ + // FIXME: The implementation is pending the fixes in https://bugs.webkit.org/show_bug.cgi?id=23175 + notImplemented(); +} + +void WorkerContext::scriptImported(unsigned long, const String&) +{ + // FIXME: The implementation is pending the fixes in https://bugs.webkit.org/show_bug.cgi?id=23175 + notImplemented(); +} + +void WorkerContext::postMessage(const String& message) +{ + m_thread->workerObjectProxy()->postMessageToWorkerObject(message); +} + +void WorkerContext::addEventListener(const AtomicString& eventType, PassRefPtr<EventListener> eventListener, bool) +{ + EventListenersMap::iterator iter = m_eventListeners.find(eventType); + if (iter == m_eventListeners.end()) { + ListenerVector listeners; + listeners.append(eventListener); + m_eventListeners.add(eventType, listeners); + } else { + ListenerVector& listeners = iter->second; + for (ListenerVector::iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) { + if (*listenerIter == eventListener) + return; + } + + listeners.append(eventListener); + m_eventListeners.add(eventType, listeners); + } +} + +void WorkerContext::removeEventListener(const AtomicString& eventType, EventListener* eventListener, bool) +{ + EventListenersMap::iterator iter = m_eventListeners.find(eventType); + if (iter == m_eventListeners.end()) + return; + + ListenerVector& listeners = iter->second; + for (ListenerVector::const_iterator listenerIter = listeners.begin(); listenerIter != listeners.end(); ++listenerIter) { + if (*listenerIter == eventListener) { + listeners.remove(listenerIter - listeners.begin()); + return; + } + } +} + +bool WorkerContext::dispatchEvent(PassRefPtr<Event> event, ExceptionCode& ec) +{ + if (!event || event->type().isEmpty()) { + ec = EventException::UNSPECIFIED_EVENT_TYPE_ERR; + return true; + } + + ListenerVector listenersCopy = m_eventListeners.get(event->type()); + for (ListenerVector::const_iterator listenerIter = listenersCopy.begin(); listenerIter != listenersCopy.end(); ++listenerIter) { + event->setTarget(this); + event->setCurrentTarget(this); + listenerIter->get()->handleEvent(event.get(), false); + } + + return !event->defaultPrevented(); +} + +void WorkerContext::postTask(PassRefPtr<Task> task) +{ + thread()->runLoop().postTask(task); +} + +int WorkerContext::installTimeout(ScheduledAction* action, int timeout, bool singleShot) +{ + return DOMTimer::install(scriptExecutionContext(), action, timeout, singleShot); +} + +void WorkerContext::removeTimeout(int timeoutId) +{ + DOMTimer::removeById(scriptExecutionContext(), timeoutId); +} + +void WorkerContext::dispatchMessage(const String& message) +{ + RefPtr<Event> evt = MessageEvent::create(message, "", "", 0, 0); + + if (m_onmessageListener.get()) { + evt->setTarget(this); + evt->setCurrentTarget(this); + m_onmessageListener->handleEvent(evt.get(), false); + } + + ExceptionCode ec = 0; + dispatchEvent(evt.release(), ec); + ASSERT(!ec); +} + +void WorkerContext::importScripts(const Vector<String>& urls, const String& callerURL, int callerLine, ExceptionCode& ec) +{ + ec = 0; + Vector<String>::const_iterator urlsEnd = urls.end(); + Vector<KURL> completedURLs; + for (Vector<String>::const_iterator it = urls.begin(); it != urlsEnd; ++it) { + const KURL& url = scriptExecutionContext()->completeURL(*it); + if (!url.isValid()) { + ec = SYNTAX_ERR; + return; + } + completedURLs.append(url); + } + String securityOrigin = scriptExecutionContext()->securityOrigin()->toString(); + Vector<KURL>::const_iterator end = completedURLs.end(); + + for (Vector<KURL>::const_iterator it = completedURLs.begin(); it != end; ++it) { + ResourceRequest request(*it); + request.setHTTPMethod("GET"); + request.setHTTPOrigin(securityOrigin); + WorkerImportScriptsClient client(scriptExecutionContext(), *it, callerURL, callerLine); + ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, client); + + // If the fetching attempt failed, throw a NETWORK_ERR exception and abort all these steps. + if (client.failed()) { + ec = XMLHttpRequestException::NETWORK_ERR; + return; + } + + ScriptValue exception; + m_script->evaluate(ScriptSourceCode(client.script(), *it), &exception); + if (!exception.hasNoValue()) { + m_script->setException(exception); + return; + } + } +} + +} // namespace WebCore + +#endif // ENABLE(WORKERS) diff --git a/WebCore/workers/WorkerContext.h b/WebCore/workers/WorkerContext.h new file mode 100644 index 0000000..39a5b9b --- /dev/null +++ b/WebCore/workers/WorkerContext.h @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WorkerContext_h +#define WorkerContext_h + +#if ENABLE(WORKERS) + +#include "AtomicStringHash.h" +#include "EventListener.h" +#include "EventTarget.h" +#include "ScriptExecutionContext.h" +#include "WorkerScriptController.h" +#include <wtf/OwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class ScheduledAction; + class WorkerLocation; + class WorkerNavigator; + class WorkerThread; + + class WorkerContext : public RefCounted<WorkerContext>, public ScriptExecutionContext, public EventTarget { + public: + static PassRefPtr<WorkerContext> create(const KURL& url, const String& userAgent, WorkerThread* thread) + { + return adoptRef(new WorkerContext(url, userAgent, thread)); + } + + virtual ~WorkerContext(); + + virtual bool isWorkerContext() const { return true; } + + virtual ScriptExecutionContext* scriptExecutionContext() const; + + const KURL& url() const { return m_url; } + KURL completeURL(const String&) const; + + virtual String userAgent(const KURL&) const; + + WorkerLocation* location() const { return m_location.get(); } + WorkerNavigator* navigator() const; + + WorkerScriptController* script() { return m_script.get(); } + void clearScript() { return m_script.clear(); } + WorkerThread* thread() { return m_thread; } + + bool hasPendingActivity() const; + + virtual void reportException(const String& errorMessage, int lineNumber, const String& sourceURL); + virtual void addMessage(MessageDestination, MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String& sourceURL); + virtual void resourceRetrievedByXMLHttpRequest(unsigned long identifier, const ScriptString& sourceString); + virtual void scriptImported(unsigned long identifier, const String& sourceString); + + virtual WorkerContext* toWorkerContext() { return this; } + + void postMessage(const String& message); + virtual void postTask(PassRefPtr<Task>); // Executes the task on context's thread asynchronously. + + int installTimeout(ScheduledAction*, int timeout, bool singleShot); + void removeTimeout(int timeoutId); + + void dispatchMessage(const String&); + + virtual void addEventListener(const AtomicString& eventType, PassRefPtr<EventListener>, bool useCapture); + virtual void removeEventListener(const AtomicString& eventType, EventListener*, bool useCapture); + virtual bool dispatchEvent(PassRefPtr<Event>, ExceptionCode&); + + void setOnmessage(PassRefPtr<EventListener> eventListener) { m_onmessageListener = eventListener; } + EventListener* onmessage() const { return m_onmessageListener.get(); } + + typedef Vector<RefPtr<EventListener> > ListenerVector; + typedef HashMap<AtomicString, ListenerVector> EventListenersMap; + EventListenersMap& eventListeners() { return m_eventListeners; } + + void importScripts(const Vector<String>& urls, const String& callerURL, int callerLine, ExceptionCode&); + + using RefCounted<WorkerContext>::ref; + using RefCounted<WorkerContext>::deref; + + private: + virtual void refScriptExecutionContext() { ref(); } + virtual void derefScriptExecutionContext() { deref(); } + virtual void refEventTarget() { ref(); } + virtual void derefEventTarget() { deref(); } + + WorkerContext(const KURL&, const String&, WorkerThread*); + + virtual const KURL& virtualURL() const; + virtual KURL virtualCompleteURL(const String&) const; + + KURL m_url; + String m_userAgent; + RefPtr<WorkerLocation> m_location; + mutable RefPtr<WorkerNavigator> m_navigator; + + OwnPtr<WorkerScriptController> m_script; + WorkerThread* m_thread; + + RefPtr<EventListener> m_onmessageListener; + EventListenersMap m_eventListeners; + }; + +} // namespace WebCore + +#endif // ENABLE(WORKERS) + +#endif // WorkerContext_h diff --git a/WebCore/workers/WorkerContext.idl b/WebCore/workers/WorkerContext.idl new file mode 100644 index 0000000..bbfca63 --- /dev/null +++ b/WebCore/workers/WorkerContext.idl @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +module threads { + + interface [ + Conditional=WORKERS, + CustomGetOwnPropertySlot, + CustomMarkFunction, + ExtendsDOMGlobalObject, + LegacyParent=JSWorkerContextBase, + NoStaticTables + ] WorkerContext { +#if defined(LANGUAGE_JAVASCRIPT) + attribute [Custom] WorkerContext self; +#endif + + attribute EventListener onmessage; + void postMessage(in DOMString message); + [Custom] void importScripts(/* urls */); + + attribute [Replaceable] WorkerLocation location; + attribute [Replaceable] WorkerNavigator navigator; + + attribute MessageEventConstructor MessageEvent; + attribute WorkerLocationConstructor WorkerLocation; + + // Timers + [Custom] long setTimeout(in TimeoutHandler handler, in long timeout); + // [Custom] long setTimeout(in DOMString code, in long timeout); + [Custom] void clearTimeout(in long handle); + + [Custom] long setInterval(in TimeoutHandler handler, in long timeout); + // [Custom] long setInterval(in DOMString code, in long timeout); + [Custom] void clearInterval(in long handle); + + // EventTarget interface + [Custom] void addEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); + [Custom] void removeEventListener(in DOMString type, + in EventListener listener, + in boolean useCapture); + boolean dispatchEvent(in Event evt) + raises(EventException); + }; + +} diff --git a/WebCore/workers/WorkerContextProxy.h b/WebCore/workers/WorkerContextProxy.h new file mode 100644 index 0000000..c8f5761 --- /dev/null +++ b/WebCore/workers/WorkerContextProxy.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WorkerContextProxy_h +#define WorkerContextProxy_h + +#if ENABLE(WORKERS) + +namespace WebCore { + + class KURL; + class String; + class Worker; + + // A proxy to talk to the worker context. + class WorkerContextProxy { + public: + static WorkerContextProxy* create(Worker*); + + virtual ~WorkerContextProxy() {} + + virtual void startWorkerContext(const KURL& scriptURL, const String& userAgent, const String& sourceCode) = 0; + + virtual void terminateWorkerContext() = 0; + + virtual void postMessageToWorkerContext(const String&) = 0; + + virtual bool hasPendingActivity() const = 0; + + virtual void workerObjectDestroyed() = 0; + }; + +} // namespace WebCore + +#endif // ENABLE(WORKERS) + +#endif // WorkerContextProxy_h diff --git a/WebCore/workers/WorkerImportScriptsClient.cpp b/WebCore/workers/WorkerImportScriptsClient.cpp new file mode 100644 index 0000000..7b8061b --- /dev/null +++ b/WebCore/workers/WorkerImportScriptsClient.cpp @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" + +#if ENABLE(WORKERS) + +#include "WorkerImportScriptsClient.h" + +#include "ScriptExecutionContext.h" + +namespace WebCore { + +void WorkerImportScriptsClient::didReceiveResponse(const ResourceResponse& response) +{ + if (response.httpStatusCode() / 100 != 2 && response.httpStatusCode() != 0) { + m_failed = true; + return; + } + m_responseEncoding = response.textEncodingName(); +} + +void WorkerImportScriptsClient::didReceiveData(const char* data, int len) +{ + if (m_failed) + return; + + if (!m_decoder) { + if (!m_responseEncoding.isEmpty()) + m_decoder = TextResourceDecoder::create("text/javascript", m_responseEncoding); + else + m_decoder = TextResourceDecoder::create("text/javascript", "UTF-8"); + } + + if (!len) + return; + + if (len == -1) + len = strlen(data); + + m_script += m_decoder->decode(data, len); +} + +void WorkerImportScriptsClient::didFinishLoading(unsigned long identifier) +{ + if (m_failed) + return; + + if (m_decoder) + m_script += m_decoder->flush(); + + m_scriptExecutionContext->scriptImported(identifier, m_script); + m_scriptExecutionContext->addMessage(InspectorControllerDestination, JSMessageSource, LogMessageLevel, "Worker script imported: \"" + m_url + "\".", m_callerLineNumber, m_callerURL); +} + +void WorkerImportScriptsClient::didFail(const ResourceError&) +{ + m_failed = true; +} + +void WorkerImportScriptsClient::didFailRedirectCheck() +{ + m_failed = true; +} + +void WorkerImportScriptsClient::didReceiveAuthenticationCancellation(const ResourceResponse&) +{ + m_failed = true; +} + +} + +#endif // ENABLE(WORKERS) diff --git a/WebCore/workers/WorkerImportScriptsClient.h b/WebCore/workers/WorkerImportScriptsClient.h new file mode 100644 index 0000000..ec27054 --- /dev/null +++ b/WebCore/workers/WorkerImportScriptsClient.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WorkerImportScriptsClient_h +#define WorkerImportScriptsClient_h + +#if ENABLE(WORKERS) + +#include "ResourceResponse.h" +#include "ScriptString.h" +#include "TextResourceDecoder.h" +#include "ThreadableLoaderClient.h" + +namespace WebCore { + + class ScriptExecutionContext; + + class WorkerImportScriptsClient : public ThreadableLoaderClient { + public: + WorkerImportScriptsClient(ScriptExecutionContext* scriptExecutionContext, const String& url, const String& callerURL, int callerLineNumber) + : m_scriptExecutionContext(scriptExecutionContext) + , m_url(url) + , m_callerURL(callerURL) + , m_callerLineNumber(callerLineNumber) + , m_failed(false) + { + } + + const String& script() const { return m_script; } + bool failed() const { return m_failed; } + + virtual void didReceiveResponse(const ResourceResponse& response); + virtual void didReceiveData(const char* data, int lengthReceived); + virtual void didFinishLoading(unsigned long identifier); + virtual void didFail(const ResourceError&); + virtual void didFailRedirectCheck(); + virtual void didReceiveAuthenticationCancellation(const ResourceResponse&); + + private: + ScriptExecutionContext* m_scriptExecutionContext; + String m_url; + String m_callerURL; + int m_callerLineNumber; + String m_responseEncoding; + RefPtr<TextResourceDecoder> m_decoder; + String m_script; + bool m_failed; + }; + +} + +#endif // ENABLE(WORKERS) +#endif + diff --git a/WebCore/workers/WorkerLocation.cpp b/WebCore/workers/WorkerLocation.cpp new file mode 100644 index 0000000..e84bf93 --- /dev/null +++ b/WebCore/workers/WorkerLocation.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" + +#if ENABLE(WORKERS) + +#include "WorkerLocation.h" + +#include "PlatformString.h" + +namespace WebCore { + +String WorkerLocation::href() const +{ + return m_url.hasPath() ? m_url.prettyURL() : m_url.prettyURL() + "/"; +} + +String WorkerLocation::protocol() const +{ + return m_url.protocol() + ":"; +} + +String WorkerLocation::host() const +{ + return m_url.port() ? m_url.host() + ":" + String::number((static_cast<int>(m_url.port()))) : m_url.host(); +} + +String WorkerLocation::hostname() const +{ + return m_url.host(); +} + +String WorkerLocation::port() const +{ + return m_url.port() ? String::number(static_cast<int>(m_url.port())) : ""; +} + +String WorkerLocation::pathname() const +{ + return m_url.path().isEmpty() ? "/" : m_url.path(); +} + +String WorkerLocation::search() const +{ + return m_url.query().isEmpty() ? "" : "?" + m_url.query(); +} + +String WorkerLocation::hash() const +{ + return m_url.ref().isEmpty() ? "" : "#" + m_url.ref(); +} + +String WorkerLocation::toString() const +{ + return m_url.hasPath() ? m_url.prettyURL() : m_url.prettyURL() + "/"; +} + + +} // namespace WebCore + +#endif // ENABLE(WORKERS) diff --git a/WebCore/workers/WorkerLocation.h b/WebCore/workers/WorkerLocation.h new file mode 100644 index 0000000..52c31ad --- /dev/null +++ b/WebCore/workers/WorkerLocation.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WorkerLocation_h +#define WorkerLocation_h + +#if ENABLE(WORKERS) + +#include "KURL.h" +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class String; + + class WorkerLocation : public RefCounted<WorkerLocation> { + public: + static PassRefPtr<WorkerLocation> create(const KURL& url) + { + return adoptRef(new WorkerLocation(url)); + } + + const KURL& url() const { return m_url; } + + String href() const; + + // URI decomposition attributes + String protocol() const; + String host() const; + String hostname() const; + String port() const; + String pathname() const; + String search() const; + String hash() const; + + String toString() const; + + private: + WorkerLocation(const KURL& url) : m_url(url) { } + + KURL m_url; + }; + +} // namespace WebCore + +#endif // ENABLE(WORKERS) + +#endif // WorkerLocation_h diff --git a/WebCore/workers/WorkerLocation.idl b/WebCore/workers/WorkerLocation.idl new file mode 100644 index 0000000..5551f18 --- /dev/null +++ b/WebCore/workers/WorkerLocation.idl @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +module threads { + + interface [ + Conditional=WORKERS, + GenerateConstructor, + NoStaticTables + ] WorkerLocation { + readonly attribute DOMString href; + readonly attribute DOMString protocol; + readonly attribute DOMString host; + readonly attribute DOMString hostname; + readonly attribute DOMString port; + readonly attribute DOMString pathname; + readonly attribute DOMString search; + readonly attribute DOMString hash; + + [DontEnum] DOMString toString(); + }; + +} diff --git a/WebCore/workers/WorkerMessagingProxy.cpp b/WebCore/workers/WorkerMessagingProxy.cpp new file mode 100644 index 0000000..4b34658 --- /dev/null +++ b/WebCore/workers/WorkerMessagingProxy.cpp @@ -0,0 +1,343 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2009 Google Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" + +#if ENABLE(WORKERS) + +#include "WorkerMessagingProxy.h" + +#include "DOMWindow.h" +#include "Document.h" +#include "GenericWorkerTask.h" +#include "MessageEvent.h" +#include "ScriptExecutionContext.h" +#include "Worker.h" +#include "WorkerContext.h" +#include "WorkerThread.h" + +namespace WebCore { + +class MessageWorkerContextTask : public ScriptExecutionContext::Task { +public: + static PassRefPtr<MessageWorkerContextTask> create(const String& message) + { + return adoptRef(new MessageWorkerContextTask(message)); + } + +private: + MessageWorkerContextTask(const String& message) + : m_message(message.copy()) + { + } + + virtual void performTask(ScriptExecutionContext* scriptContext) + { + ASSERT(scriptContext->isWorkerContext()); + WorkerContext* context = static_cast<WorkerContext*>(scriptContext); + + context->dispatchMessage(m_message); + + context->thread()->workerObjectProxy()->confirmMessageFromWorkerObject(context->hasPendingActivity()); + } + +private: + String m_message; +}; + +class MessageWorkerTask : public ScriptExecutionContext::Task { +public: + static PassRefPtr<MessageWorkerTask> create(const String& message, WorkerMessagingProxy* messagingProxy) + { + return adoptRef(new MessageWorkerTask(message, messagingProxy)); + } + +private: + MessageWorkerTask(const String& message, WorkerMessagingProxy* messagingProxy) + : m_message(message.copy()) + , m_messagingProxy(messagingProxy) + { + } + + virtual void performTask(ScriptExecutionContext*) + { + Worker* workerObject = m_messagingProxy->workerObject(); + if (!workerObject || m_messagingProxy->askedToTerminate()) + return; + + workerObject->dispatchMessage(m_message); + } + +private: + String m_message; + WorkerMessagingProxy* m_messagingProxy; +}; + +class WorkerExceptionTask : public ScriptExecutionContext::Task { +public: + static PassRefPtr<WorkerExceptionTask> create(const String& errorMessage, int lineNumber, const String& sourceURL, WorkerMessagingProxy* messagingProxy) + { + return adoptRef(new WorkerExceptionTask(errorMessage, lineNumber, sourceURL, messagingProxy)); + } + +private: + WorkerExceptionTask(const String& errorMessage, int lineNumber, const String& sourceURL, WorkerMessagingProxy* messagingProxy) + : m_errorMessage(errorMessage.copy()) + , m_lineNumber(lineNumber) + , m_sourceURL(sourceURL.copy()) + , m_messagingProxy(messagingProxy) + { + } + + virtual void performTask(ScriptExecutionContext* context) + { + if (!m_messagingProxy->askedToTerminate()) + context->reportException(m_errorMessage, m_lineNumber, m_sourceURL); + } + + String m_errorMessage; + int m_lineNumber; + String m_sourceURL; + WorkerMessagingProxy* m_messagingProxy; +}; + +class WorkerContextDestroyedTask : public ScriptExecutionContext::Task { +public: + static PassRefPtr<WorkerContextDestroyedTask> create(WorkerMessagingProxy* messagingProxy) + { + return adoptRef(new WorkerContextDestroyedTask(messagingProxy)); + } + +private: + WorkerContextDestroyedTask(WorkerMessagingProxy* messagingProxy) + : m_messagingProxy(messagingProxy) + { + } + + virtual void performTask(ScriptExecutionContext*) + { + m_messagingProxy->workerContextDestroyedInternal(); + } + + WorkerMessagingProxy* m_messagingProxy; +}; + +class WorkerThreadActivityReportTask : public ScriptExecutionContext::Task { +public: + static PassRefPtr<WorkerThreadActivityReportTask> create(WorkerMessagingProxy* messagingProxy, bool confirmingMessage, bool hasPendingActivity) + { + return adoptRef(new WorkerThreadActivityReportTask(messagingProxy, confirmingMessage, hasPendingActivity)); + } + +private: + WorkerThreadActivityReportTask(WorkerMessagingProxy* messagingProxy, bool confirmingMessage, bool hasPendingActivity) + : m_messagingProxy(messagingProxy) + , m_confirmingMessage(confirmingMessage) + , m_hasPendingActivity(hasPendingActivity) + { + } + + virtual void performTask(ScriptExecutionContext*) + { + m_messagingProxy->reportPendingActivityInternal(m_confirmingMessage, m_hasPendingActivity); + } + + WorkerMessagingProxy* m_messagingProxy; + bool m_confirmingMessage; + bool m_hasPendingActivity; +}; + + +#if !PLATFORM(CHROMIUM) +WorkerContextProxy* WorkerContextProxy::create(Worker* worker) +{ + return new WorkerMessagingProxy(worker); +} +#endif + +WorkerMessagingProxy::WorkerMessagingProxy(Worker* workerObject) + : m_scriptExecutionContext(workerObject->scriptExecutionContext()) + , m_workerObject(workerObject) + , m_unconfirmedMessageCount(0) + , m_workerThreadHadPendingActivity(false) + , m_askedToTerminate(false) +{ + ASSERT(m_workerObject); + ASSERT((m_scriptExecutionContext->isDocument() && isMainThread()) + || (m_scriptExecutionContext->isWorkerContext() && currentThread() == static_cast<WorkerContext*>(m_scriptExecutionContext.get())->thread()->threadID())); +} + +WorkerMessagingProxy::~WorkerMessagingProxy() +{ + ASSERT(!m_workerObject); + ASSERT((m_scriptExecutionContext->isDocument() && isMainThread()) + || (m_scriptExecutionContext->isWorkerContext() && currentThread() == static_cast<WorkerContext*>(m_scriptExecutionContext.get())->thread()->threadID())); +} + +void WorkerMessagingProxy::startWorkerContext(const KURL& scriptURL, const String& userAgent, const String& sourceCode) +{ + RefPtr<WorkerThread> thread = WorkerThread::create(scriptURL, userAgent, sourceCode, this); + workerThreadCreated(thread); + thread->start(); +} + +void WorkerMessagingProxy::postMessageToWorkerObject(const String& message) +{ + m_scriptExecutionContext->postTask(MessageWorkerTask::create(message, this)); +} + +void WorkerMessagingProxy::postMessageToWorkerContext(const String& message) +{ + if (m_askedToTerminate) + return; + + if (m_workerThread) { + ++m_unconfirmedMessageCount; + m_workerThread->runLoop().postTask(MessageWorkerContextTask::create(message)); + } else + m_queuedEarlyTasks.append(MessageWorkerContextTask::create(message)); +} + +void WorkerMessagingProxy::postTaskToWorkerContext(PassRefPtr<ScriptExecutionContext::Task> task) +{ + postTaskForModeToWorkerContext(task, WorkerRunLoop::defaultMode()); +} + +void WorkerMessagingProxy::postTaskForModeToWorkerContext(PassRefPtr<ScriptExecutionContext::Task> task, const String& mode) +{ + if (m_askedToTerminate) + return; + + ASSERT(m_workerThread); + m_workerThread->runLoop().postTaskForMode(task, mode); +} + +void WorkerMessagingProxy::postTaskToWorkerObject(PassRefPtr<ScriptExecutionContext::Task> task) +{ + m_scriptExecutionContext->postTask(task); +} + +void WorkerMessagingProxy::postExceptionToWorkerObject(const String& errorMessage, int lineNumber, const String& sourceURL) +{ + m_scriptExecutionContext->postTask(WorkerExceptionTask::create(errorMessage, lineNumber, sourceURL, this)); +} + +static void postConsoleMessageTask(ScriptExecutionContext* context, WorkerMessagingProxy* messagingProxy, MessageDestination destination, MessageSource source, MessageLevel level, const String& message, unsigned lineNumber, const String& sourceURL) +{ + if (messagingProxy->askedToTerminate()) + return; + context->addMessage(destination, source, level, message, lineNumber, sourceURL); +} + +void WorkerMessagingProxy::postConsoleMessageToWorkerObject(MessageDestination destination, MessageSource source, MessageLevel level, const String& message, int lineNumber, const String& sourceURL) +{ + m_scriptExecutionContext->postTask(createCallbackTask(&postConsoleMessageTask, this, destination, source, level, message, lineNumber, sourceURL)); +} + +void WorkerMessagingProxy::workerThreadCreated(PassRefPtr<WorkerThread> workerThread) +{ + m_workerThread = workerThread; + + if (m_askedToTerminate) { + // Worker.terminate() could be called from JS before the thread was created. + m_workerThread->stop(); + } else { + unsigned taskCount = m_queuedEarlyTasks.size(); + ASSERT(!m_unconfirmedMessageCount); + m_unconfirmedMessageCount = taskCount; + m_workerThreadHadPendingActivity = true; // Worker initialization means a pending activity. + + for (unsigned i = 0; i < taskCount; ++i) + m_workerThread->runLoop().postTask(m_queuedEarlyTasks[i]); + m_queuedEarlyTasks.clear(); + } +} + +void WorkerMessagingProxy::workerObjectDestroyed() +{ + m_workerObject = 0; + if (m_workerThread) + terminateWorkerContext(); + else + workerContextDestroyedInternal(); +} + +void WorkerMessagingProxy::workerContextDestroyed() +{ + m_scriptExecutionContext->postTask(WorkerContextDestroyedTask::create(this)); + // Will execute workerContextDestroyedInternal() on context's thread. +} + +void WorkerMessagingProxy::workerContextDestroyedInternal() +{ + // WorkerContextDestroyedTask is always the last to be performed, so the proxy is not needed for communication + // in either side any more. However, the Worker object may still exist, and it assumes that the proxy exists, too. + m_workerThread = 0; + if (!m_workerObject) + delete this; +} + +void WorkerMessagingProxy::terminateWorkerContext() +{ + if (m_askedToTerminate) + return; + m_askedToTerminate = true; + + if (m_workerThread) + m_workerThread->stop(); +} + +void WorkerMessagingProxy::confirmMessageFromWorkerObject(bool hasPendingActivity) +{ + m_scriptExecutionContext->postTask(WorkerThreadActivityReportTask::create(this, true, hasPendingActivity)); + // Will execute reportPendingActivityInternal() on context's thread. +} + +void WorkerMessagingProxy::reportPendingActivity(bool hasPendingActivity) +{ + m_scriptExecutionContext->postTask(WorkerThreadActivityReportTask::create(this, false, hasPendingActivity)); + // Will execute reportPendingActivityInternal() on context's thread. +} + +void WorkerMessagingProxy::reportPendingActivityInternal(bool confirmingMessage, bool hasPendingActivity) +{ + if (confirmingMessage && !m_askedToTerminate) { + ASSERT(m_unconfirmedMessageCount); + --m_unconfirmedMessageCount; + } + + m_workerThreadHadPendingActivity = hasPendingActivity; +} + +bool WorkerMessagingProxy::hasPendingActivity() const +{ + return (m_unconfirmedMessageCount || m_workerThreadHadPendingActivity) && !m_askedToTerminate; +} + +} // namespace WebCore + +#endif // ENABLE(WORKERS) diff --git a/WebCore/workers/WorkerMessagingProxy.h b/WebCore/workers/WorkerMessagingProxy.h new file mode 100644 index 0000000..8d81deb --- /dev/null +++ b/WebCore/workers/WorkerMessagingProxy.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WorkerMessagingProxy_h +#define WorkerMessagingProxy_h + +#if ENABLE(WORKERS) + +#include "ScriptExecutionContext.h" +#include "WorkerContextProxy.h" +#include "WorkerObjectProxy.h" +#include <wtf/Noncopyable.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace WebCore { + + class ScriptExecutionContext; + class String; + class Worker; + class WorkerThread; + + class WorkerMessagingProxy : public WorkerContextProxy, public WorkerObjectProxy, Noncopyable { + public: + WorkerMessagingProxy(Worker*); + + // Implementations of WorkerContextProxy. + // (Only use these methods in the worker object thread.) + virtual void startWorkerContext(const KURL& scriptURL, const String& userAgent, const String& sourceCode); + virtual void terminateWorkerContext(); + virtual void postMessageToWorkerContext(const String& message); + virtual bool hasPendingActivity() const; + virtual void workerObjectDestroyed(); + + // Implementations of WorkerObjectProxy. + // (Only use these methods in the worker context thread.) + virtual void postMessageToWorkerObject(const String& message); + virtual void postExceptionToWorkerObject(const String& errorMessage, int lineNumber, const String& sourceURL); + virtual void postConsoleMessageToWorkerObject(MessageDestination, MessageSource, MessageLevel, const String& message, int lineNumber, const String& sourceURL); + virtual void confirmMessageFromWorkerObject(bool hasPendingActivity); + virtual void reportPendingActivity(bool hasPendingActivity); + virtual void workerContextDestroyed(); + + void postTaskToWorkerObject(PassRefPtr<ScriptExecutionContext::Task>); + void postTaskToWorkerContext(PassRefPtr<ScriptExecutionContext::Task>); + void postTaskForModeToWorkerContext(PassRefPtr<ScriptExecutionContext::Task>, const String& mode); + + void workerThreadCreated(PassRefPtr<WorkerThread>); + + // Only use this method on the worker object thread. + bool askedToTerminate() const { return m_askedToTerminate; } + + private: + friend class MessageWorkerTask; + friend class WorkerContextDestroyedTask; + friend class WorkerThreadActivityReportTask; + + virtual ~WorkerMessagingProxy(); + + void workerContextDestroyedInternal(); + void reportPendingActivityInternal(bool confirmingMessage, bool hasPendingActivity); + Worker* workerObject() const { return m_workerObject; } + + RefPtr<ScriptExecutionContext> m_scriptExecutionContext; + Worker* m_workerObject; + RefPtr<WorkerThread> m_workerThread; + + unsigned m_unconfirmedMessageCount; // Unconfirmed messages from worker object to worker thread. + bool m_workerThreadHadPendingActivity; // The latest confirmation from worker thread reported that it was still active. + + bool m_askedToTerminate; + + Vector<RefPtr<ScriptExecutionContext::Task> > m_queuedEarlyTasks; // Tasks are queued here until there's a thread object created. + }; + +} // namespace WebCore + +#endif // ENABLE(WORKERS) + +#endif // WorkerMessagingProxy_h diff --git a/WebCore/workers/WorkerObjectProxy.h b/WebCore/workers/WorkerObjectProxy.h new file mode 100644 index 0000000..3b86028 --- /dev/null +++ b/WebCore/workers/WorkerObjectProxy.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WorkerObjectProxy_h +#define WorkerObjectProxy_h + +#if ENABLE(WORKERS) + +#include "Console.h" + +namespace WebCore { + + class String; + + // A proxy to talk to the worker object. + class WorkerObjectProxy { + public: + virtual ~WorkerObjectProxy() {} + + virtual void postMessageToWorkerObject(const String&) = 0; + + virtual void postExceptionToWorkerObject(const String& errorMessage, int lineNumber, const String& sourceURL) = 0; + + virtual void postConsoleMessageToWorkerObject(MessageDestination, MessageSource, MessageLevel, const String& message, int lineNumber, const String& sourceURL) = 0; + + virtual void confirmMessageFromWorkerObject(bool hasPendingActivity) = 0; + + virtual void reportPendingActivity(bool hasPendingActivity) = 0; + + virtual void workerContextDestroyed() = 0; + }; + +} // namespace WebCore + +#endif // ENABLE(WORKERS) + +#endif // WorkerObjectProxy_h diff --git a/WebCore/workers/WorkerRunLoop.cpp b/WebCore/workers/WorkerRunLoop.cpp new file mode 100644 index 0000000..1e5e510 --- /dev/null +++ b/WebCore/workers/WorkerRunLoop.cpp @@ -0,0 +1,210 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(WORKERS) + +#include "ScriptExecutionContext.h" +#include "SharedTimer.h" +#include "ThreadGlobalData.h" +#include "ThreadTimers.h" +#include "WorkerRunLoop.h" +#include "WorkerContext.h" +#include "WorkerThread.h" + +namespace WebCore { + +class WorkerSharedTimer : public SharedTimer { +public: + WorkerSharedTimer() + : m_sharedTimerFunction(0) + , m_nextFireTime(0) + { + } + + // SharedTimer interface. + virtual void setFiredFunction(void (*function)()) { m_sharedTimerFunction = function; } + virtual void setFireTime(double fireTime) { m_nextFireTime = fireTime; } + virtual void stop() { m_nextFireTime = 0; } + + bool isActive() { return m_sharedTimerFunction && m_nextFireTime; } + double fireTime() { return m_nextFireTime; } + void fire() { m_sharedTimerFunction(); } + +private: + void (*m_sharedTimerFunction)(); + double m_nextFireTime; +}; + +class WorkerRunLoop::Task : public RefCounted<Task> { +public: + static PassRefPtr<Task> create(PassRefPtr<ScriptExecutionContext::Task> task, const String& mode) + { + return adoptRef(new Task(task, mode)); + } + + const String& mode() const { return m_mode; } + void performTask(ScriptExecutionContext* context) { m_task->performTask(context); } + +private: + Task(PassRefPtr<ScriptExecutionContext::Task> task, const String& mode) + : m_task(task) + , m_mode(mode.copy()) + { + } + + RefPtr<ScriptExecutionContext::Task> m_task; + String m_mode; +}; + +class ModePredicate { +public: + ModePredicate(const String& mode) + : m_mode(mode) + , m_defaultMode(mode == WorkerRunLoop::defaultMode()) + { + } + + bool isDefaultMode() const + { + return m_defaultMode; + } + + bool operator()(PassRefPtr<WorkerRunLoop::Task> task) const + { + return m_defaultMode || m_mode == task->mode(); + } + +private: + String m_mode; + bool m_defaultMode; +}; + +WorkerRunLoop::WorkerRunLoop() + : m_sharedTimer(new WorkerSharedTimer) + , m_nestedCount(0) + , m_uniqueId(0) +{ +} + +WorkerRunLoop::~WorkerRunLoop() +{ + ASSERT(!m_nestedCount); +} + +String WorkerRunLoop::defaultMode() +{ + return String(); +} + +class RunLoopSetup : Noncopyable +{ +public: + RunLoopSetup(WorkerRunLoop& runLoop) + : m_runLoop(runLoop) + { + if (!m_runLoop.m_nestedCount) + threadGlobalData().threadTimers().setSharedTimer(m_runLoop.m_sharedTimer.get()); + m_runLoop.m_nestedCount++; + } + + ~RunLoopSetup() + { + m_runLoop.m_nestedCount--; + if (!m_runLoop.m_nestedCount) + threadGlobalData().threadTimers().setSharedTimer(0); + } +private: + WorkerRunLoop& m_runLoop; +}; + +void WorkerRunLoop::run(WorkerContext* context) +{ + RunLoopSetup setup(*this); + ModePredicate modePredicate(defaultMode()); + MessageQueueWaitResult result; + do { + result = runInMode(context, modePredicate); + } while (result != MessageQueueTerminated); +} + +MessageQueueWaitResult WorkerRunLoop::runInMode(WorkerContext* context, const String& mode) +{ + RunLoopSetup setup(*this); + ModePredicate modePredicate(mode); + MessageQueueWaitResult result = runInMode(context, modePredicate); + return result; +} + +MessageQueueWaitResult WorkerRunLoop::runInMode(WorkerContext* context, const ModePredicate& predicate) +{ + ASSERT(context); + ASSERT(context->thread()); + ASSERT(context->thread()->threadID() == currentThread()); + + double absoluteTime = (predicate.isDefaultMode() && m_sharedTimer->isActive()) ? m_sharedTimer->fireTime() : MessageQueue<RefPtr<Task> >::infiniteTime(); + RefPtr<Task> task; + MessageQueueWaitResult result = m_messageQueue.waitForMessageFilteredWithTimeout(task, predicate, absoluteTime); + + switch (result) { + case MessageQueueTerminated: + break; + + case MessageQueueMessageReceived: + task->performTask(context); + break; + + case MessageQueueTimeout: + m_sharedTimer->fire(); + break; + } + + return result; +} + +void WorkerRunLoop::terminate() +{ + m_messageQueue.kill(); +} + +void WorkerRunLoop::postTask(PassRefPtr<ScriptExecutionContext::Task> task) +{ + postTaskForMode(task, defaultMode()); +} + +void WorkerRunLoop::postTaskForMode(PassRefPtr<ScriptExecutionContext::Task> task, const String& mode) +{ + m_messageQueue.append(Task::create(task, mode.copy())); +} + +} // namespace WebCore + +#endif // ENABLE(WORKERS) diff --git a/WebCore/workers/WorkerRunLoop.h b/WebCore/workers/WorkerRunLoop.h new file mode 100644 index 0000000..5f74f01 --- /dev/null +++ b/WebCore/workers/WorkerRunLoop.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2009 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef WorkerRunLoop_h +#define WorkerRunLoop_h + +#if ENABLE(WORKERS) + +#include "ScriptExecutionContext.h" +#include <wtf/MessageQueue.h> +#include <wtf/OwnPtr.h> +#include <wtf/PassRefPtr.h> + +namespace WebCore { + + class ModePredicate; + class WorkerContext; + class WorkerSharedTimer; + + class WorkerRunLoop { + public: + WorkerRunLoop(); + ~WorkerRunLoop(); + + // Blocking call. Waits for tasks and timers, invokes the callbacks. + void run(WorkerContext*); + + // Waits for a single task and returns. + MessageQueueWaitResult runInMode(WorkerContext*, const String& mode); + + void terminate(); + bool terminated() { return m_messageQueue.killed(); } + + void postTask(PassRefPtr<ScriptExecutionContext::Task>); + void postTaskForMode(PassRefPtr<ScriptExecutionContext::Task>, const String& mode); + + unsigned long createUniqueId() { return ++m_uniqueId; } + + static String defaultMode(); + class Task; + private: + friend class RunLoopSetup; + MessageQueueWaitResult runInMode(WorkerContext*, const ModePredicate&); + + MessageQueue<RefPtr<Task> > m_messageQueue; + OwnPtr<WorkerSharedTimer> m_sharedTimer; + int m_nestedCount; + unsigned long m_uniqueId; + }; + +} // namespace WebCore + +#endif // ENABLE(WORKERS) + +#endif // WorkerRunLoop_h diff --git a/WebCore/workers/WorkerThread.cpp b/WebCore/workers/WorkerThread.cpp new file mode 100644 index 0000000..d1026b1 --- /dev/null +++ b/WebCore/workers/WorkerThread.cpp @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#include "config.h" + +#if ENABLE(WORKERS) + +#include "WorkerThread.h" + +#include "KURL.h" +#include "PlatformString.h" +#include "ScriptSourceCode.h" +#include "ScriptValue.h" +#include "WorkerContext.h" +#include "WorkerObjectProxy.h" + +#include <utility> +#include <wtf/Noncopyable.h> + +namespace WebCore { +struct WorkerThreadStartupData : Noncopyable { +public: + static std::auto_ptr<WorkerThreadStartupData> create(const KURL& scriptURL, const String& userAgent, const String& sourceCode) + { + return std::auto_ptr<WorkerThreadStartupData>(new WorkerThreadStartupData(scriptURL, userAgent, sourceCode)); + } + + KURL m_scriptURL; + String m_userAgent; + String m_sourceCode; +private: + WorkerThreadStartupData(const KURL& scriptURL, const String& userAgent, const String& sourceCode); +}; + +WorkerThreadStartupData::WorkerThreadStartupData(const KURL& scriptURL, const String& userAgent, const String& sourceCode) + : m_scriptURL(scriptURL.copy()) + , m_userAgent(userAgent.copy()) + , m_sourceCode(sourceCode.copy()) +{ +} + +PassRefPtr<WorkerThread> WorkerThread::create(const KURL& scriptURL, const String& userAgent, const String& sourceCode, WorkerObjectProxy* workerObjectProxy) +{ + return adoptRef(new WorkerThread(scriptURL, userAgent, sourceCode, workerObjectProxy)); +} + +WorkerThread::WorkerThread(const KURL& scriptURL, const String& userAgent, const String& sourceCode, WorkerObjectProxy* workerObjectProxy) + : m_threadID(0) + , m_workerObjectProxy(workerObjectProxy) + , m_startupData(WorkerThreadStartupData::create(scriptURL, userAgent, sourceCode)) +{ +} + +WorkerThread::~WorkerThread() +{ +} + +bool WorkerThread::start() +{ + // Mutex protection is necessary to ensure that m_threadID is initialized when the thread starts. + MutexLocker lock(m_threadCreationMutex); + + if (m_threadID) + return true; + + m_threadID = createThread(WorkerThread::workerThreadStart, this, "WebCore: Worker"); + + return m_threadID; +} + +void* WorkerThread::workerThreadStart(void* thread) +{ + return static_cast<WorkerThread*>(thread)->workerThread(); +} + +void* WorkerThread::workerThread() +{ + { + MutexLocker lock(m_threadCreationMutex); + m_workerContext = WorkerContext::create(m_startupData->m_scriptURL, m_startupData->m_userAgent, this); + if (m_runLoop.terminated()) { + // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet, + // forbidExecution() couldn't be called from stop(). + m_workerContext->script()->forbidExecution(); + } + } + + WorkerScriptController* script = m_workerContext->script(); + script->evaluate(ScriptSourceCode(m_startupData->m_sourceCode, m_startupData->m_scriptURL)); + // Free the startup data to cause its member variable deref's happen on the worker's thread (since + // all ref/derefs of these objects are happening on the thread at this point). Note that + // WorkerThread::~WorkerThread happens on a different thread where it was created. + m_startupData.clear(); + + m_workerObjectProxy->reportPendingActivity(m_workerContext->hasPendingActivity()); + + // Blocks until terminated. + m_runLoop.run(m_workerContext.get()); + + ThreadIdentifier threadID = m_threadID; + + m_workerContext->stopActiveDOMObjects(); + m_workerContext->clearScript(); + ASSERT(m_workerContext->hasOneRef()); + // The below assignment will destroy the context, which will in turn notify messaging proxy. + // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them. + m_workerContext = 0; + + // The thread object may be already destroyed from notification now, don't try to access "this". + detachThread(threadID); + + return 0; +} + +void WorkerThread::stop() +{ + // Mutex protection is necessary because stop() can be called before the context is fully created. + MutexLocker lock(m_threadCreationMutex); + + // Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever. + if (m_workerContext) + m_workerContext->script()->forbidExecution(); + + // FIXME: Rudely killing the thread won't work when we allow nested workers, because they will try to post notifications of their destruction. + m_runLoop.terminate(); +} + +} // namespace WebCore + +#endif // ENABLE(WORKERS) diff --git a/WebCore/workers/WorkerThread.h b/WebCore/workers/WorkerThread.h new file mode 100644 index 0000000..f1a8a52 --- /dev/null +++ b/WebCore/workers/WorkerThread.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef WorkerThread_h +#define WorkerThread_h + +#if ENABLE(WORKERS) + +#include "WorkerRunLoop.h" +#include <wtf/OwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace WebCore { + + class KURL; + class String; + class WorkerContext; + class WorkerObjectProxy; + struct WorkerThreadStartupData; + + class WorkerThread : public RefCounted<WorkerThread> { + public: + static PassRefPtr<WorkerThread> create(const KURL& scriptURL, const String& userAgent, const String& sourceCode, WorkerObjectProxy*); + ~WorkerThread(); + + bool start(); + void stop(); + + ThreadIdentifier threadID() const { return m_threadID; } + WorkerRunLoop& runLoop() { return m_runLoop; } + WorkerObjectProxy* workerObjectProxy() const { return m_workerObjectProxy; } + + private: + WorkerThread(const KURL&, const String& userAgent, const String& sourceCode, WorkerObjectProxy*); + + static void* workerThreadStart(void*); + void* workerThread(); + + ThreadIdentifier m_threadID; + WorkerRunLoop m_runLoop; + WorkerObjectProxy* m_workerObjectProxy; + + RefPtr<WorkerContext> m_workerContext; + Mutex m_threadCreationMutex; + + OwnPtr<WorkerThreadStartupData> m_startupData; + }; + +} // namespace WebCore + +#endif // ENABLE(WORKERS) + +#endif // WorkerThread_h + |