• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Apple Inc. All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  */
26 
27 #include "config.h"
28 
29 #if ENABLE(WORKERS)
30 
31 #include "WorkerThread.h"
32 
33 #include "DedicatedWorkerContext.h"
34 #include "KURL.h"
35 #include "PlatformString.h"
36 #include "ScriptSourceCode.h"
37 #include "ScriptValue.h"
38 
39 #include <utility>
40 #include <wtf/Noncopyable.h>
41 
42 namespace WebCore {
43 struct WorkerThreadStartupData : Noncopyable {
44 public:
createWebCore::WorkerThreadStartupData45     static std::auto_ptr<WorkerThreadStartupData> create(const KURL& scriptURL, const String& userAgent, const String& sourceCode)
46     {
47         return std::auto_ptr<WorkerThreadStartupData>(new WorkerThreadStartupData(scriptURL, userAgent, sourceCode));
48     }
49 
50     KURL m_scriptURL;
51     String m_userAgent;
52     String m_sourceCode;
53 private:
54     WorkerThreadStartupData(const KURL& scriptURL, const String& userAgent, const String& sourceCode);
55 };
56 
WorkerThreadStartupData(const KURL & scriptURL,const String & userAgent,const String & sourceCode)57 WorkerThreadStartupData::WorkerThreadStartupData(const KURL& scriptURL, const String& userAgent, const String& sourceCode)
58     : m_scriptURL(scriptURL.copy())
59     , m_userAgent(userAgent.copy())
60     , m_sourceCode(sourceCode.copy())
61 {
62 }
63 
WorkerThread(const KURL & scriptURL,const String & userAgent,const String & sourceCode,WorkerLoaderProxy & workerLoaderProxy)64 WorkerThread::WorkerThread(const KURL& scriptURL, const String& userAgent, const String& sourceCode, WorkerLoaderProxy& workerLoaderProxy)
65     : m_threadID(0)
66     , m_workerLoaderProxy(workerLoaderProxy)
67     , m_startupData(WorkerThreadStartupData::create(scriptURL, userAgent, sourceCode))
68 {
69 }
70 
~WorkerThread()71 WorkerThread::~WorkerThread()
72 {
73 }
74 
start()75 bool WorkerThread::start()
76 {
77     // Mutex protection is necessary to ensure that m_threadID is initialized when the thread starts.
78     MutexLocker lock(m_threadCreationMutex);
79 
80     if (m_threadID)
81         return true;
82 
83     m_threadID = createThread(WorkerThread::workerThreadStart, this, "WebCore: Worker");
84 
85     return m_threadID;
86 }
87 
workerThreadStart(void * thread)88 void* WorkerThread::workerThreadStart(void* thread)
89 {
90     return static_cast<WorkerThread*>(thread)->workerThread();
91 }
92 
workerThread()93 void* WorkerThread::workerThread()
94 {
95     {
96         MutexLocker lock(m_threadCreationMutex);
97         m_workerContext = createWorkerContext(m_startupData->m_scriptURL, m_startupData->m_userAgent);
98 
99         if (m_runLoop.terminated()) {
100             // The worker was terminated before the thread had a chance to run. Since the context didn't exist yet,
101             // forbidExecution() couldn't be called from stop().
102            m_workerContext->script()->forbidExecution();
103         }
104     }
105 
106     WorkerScriptController* script = m_workerContext->script();
107     script->evaluate(ScriptSourceCode(m_startupData->m_sourceCode, m_startupData->m_scriptURL));
108     // Free the startup data to cause its member variable deref's happen on the worker's thread (since
109     // all ref/derefs of these objects are happening on the thread at this point). Note that
110     // WorkerThread::~WorkerThread happens on a different thread where it was created.
111     m_startupData.clear();
112 
113     runEventLoop();
114 
115     ThreadIdentifier threadID = m_threadID;
116 
117     m_workerContext->stopActiveDOMObjects();
118     m_workerContext->clearScript();
119     ASSERT(m_workerContext->hasOneRef());
120     // The below assignment will destroy the context, which will in turn notify messaging proxy.
121     // We cannot let any objects survive past thread exit, because no other thread will run GC or otherwise destroy them.
122     m_workerContext = 0;
123 
124     // The thread object may be already destroyed from notification now, don't try to access "this".
125     detachThread(threadID);
126 
127     return 0;
128 }
129 
runEventLoop()130 void WorkerThread::runEventLoop()
131 {
132     // Does not return until terminated.
133     m_runLoop.run(m_workerContext.get());
134 }
135 
stop()136 void WorkerThread::stop()
137 {
138     // Mutex protection is necessary because stop() can be called before the context is fully created.
139     MutexLocker lock(m_threadCreationMutex);
140 
141     // 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.
142     if (m_workerContext)
143         m_workerContext->script()->forbidExecution();
144 
145     // FIXME: Rudely killing the thread won't work when we allow nested workers, because they will try to post notifications of their destruction.
146     m_runLoop.terminate();
147 }
148 
149 } // namespace WebCore
150 
151 #endif // ENABLE(WORKERS)
152