initial import
[vuplus_webkit] / Source / WebCore / workers / WorkerRunLoop.cpp
1 /*
2  * Copyright (C) 2009 Google Inc. All rights reserved.
3  * 
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  * 
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30  
31 #include "config.h"
32
33 #if ENABLE(WORKERS)
34
35 #include "ScriptExecutionContext.h"
36 #include "SharedTimer.h"
37 #include "ThreadGlobalData.h"
38 #include "ThreadTimers.h"
39 #include "WorkerRunLoop.h"
40 #include "WorkerContext.h"
41 #include "WorkerThread.h"
42 #include <wtf/CurrentTime.h>
43
44 namespace WebCore {
45
46 class WorkerSharedTimer : public SharedTimer {
47 public:
48     WorkerSharedTimer()
49         : m_sharedTimerFunction(0)
50         , m_nextFireTime(0)
51     {
52     }
53
54     // SharedTimer interface.
55     virtual void setFiredFunction(void (*function)()) { m_sharedTimerFunction = function; }
56     virtual void setFireInterval(double interval) { m_nextFireTime = interval + currentTime(); }
57     virtual void stop() { m_nextFireTime = 0; }
58
59     bool isActive() { return m_sharedTimerFunction && m_nextFireTime; }
60     double fireTime() { return m_nextFireTime; }
61     void fire() { m_sharedTimerFunction(); }
62
63 private:
64     void (*m_sharedTimerFunction)();
65     double m_nextFireTime;
66 };
67
68 class ModePredicate {
69 public:
70     ModePredicate(const String& mode)
71         : m_mode(mode)
72         , m_defaultMode(mode == WorkerRunLoop::defaultMode())
73     {
74     }
75
76     bool isDefaultMode() const
77     {
78         return m_defaultMode;
79     }
80
81     bool operator()(WorkerRunLoop::Task* task) const
82     {
83         return m_defaultMode || m_mode == task->mode();
84     }
85
86 private:
87     String m_mode;
88     bool m_defaultMode;
89 };
90
91 WorkerRunLoop::WorkerRunLoop()
92     : m_sharedTimer(adoptPtr(new WorkerSharedTimer))
93     , m_nestedCount(0)
94     , m_uniqueId(0)
95 {
96 }
97
98 WorkerRunLoop::~WorkerRunLoop()
99 {
100     ASSERT(!m_nestedCount);
101 }
102
103 String WorkerRunLoop::defaultMode()
104 {
105     return String();
106 }
107
108 class RunLoopSetup {
109     WTF_MAKE_NONCOPYABLE(RunLoopSetup);
110 public:
111     RunLoopSetup(WorkerRunLoop& runLoop)
112         : m_runLoop(runLoop)
113     {
114         if (!m_runLoop.m_nestedCount)
115             threadGlobalData().threadTimers().setSharedTimer(m_runLoop.m_sharedTimer.get());
116         m_runLoop.m_nestedCount++;
117     }
118
119     ~RunLoopSetup()
120     {
121         m_runLoop.m_nestedCount--;
122         if (!m_runLoop.m_nestedCount)
123             threadGlobalData().threadTimers().setSharedTimer(0);
124     }
125 private:
126     WorkerRunLoop& m_runLoop;
127 };
128
129 void WorkerRunLoop::run(WorkerContext* context)
130 {
131     RunLoopSetup setup(*this);
132     ModePredicate modePredicate(defaultMode());
133     MessageQueueWaitResult result;
134     do {
135         result = runInMode(context, modePredicate);
136     } while (result != MessageQueueTerminated);
137 }
138
139 MessageQueueWaitResult WorkerRunLoop::runInMode(WorkerContext* context, const String& mode)
140 {
141     RunLoopSetup setup(*this);
142     ModePredicate modePredicate(mode);
143     MessageQueueWaitResult result = runInMode(context, modePredicate);
144     return result;
145 }
146
147 MessageQueueWaitResult WorkerRunLoop::runInMode(WorkerContext* context, const ModePredicate& predicate)
148 {
149     ASSERT(context);
150     ASSERT(context->thread());
151     ASSERT(context->thread()->threadID() == currentThread());
152
153     double absoluteTime = (predicate.isDefaultMode() && m_sharedTimer->isActive()) ? m_sharedTimer->fireTime() : MessageQueue<Task>::infiniteTime();
154     MessageQueueWaitResult result;
155     OwnPtr<WorkerRunLoop::Task> task = m_messageQueue.waitForMessageFilteredWithTimeout(result, predicate, absoluteTime);
156
157     // If the context is closing, don't execute any further JavaScript tasks (per section 4.1.1 of the Web Workers spec).  However, there may be implementation cleanup tasks in the queue, so keep running through it.
158
159     switch (result) {
160     case MessageQueueTerminated:
161         break;
162
163     case MessageQueueMessageReceived:
164         task->performTask(context);
165         break;
166
167     case MessageQueueTimeout:
168         if (!context->isClosing())
169             m_sharedTimer->fire();
170         break;
171     }
172
173     return result;
174 }
175
176 void WorkerRunLoop::terminate()
177 {
178     m_messageQueue.kill();
179 }
180
181 void WorkerRunLoop::postTask(PassOwnPtr<ScriptExecutionContext::Task> task)
182 {
183     postTaskForMode(task, defaultMode());
184 }
185
186 void WorkerRunLoop::postTaskForMode(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
187 {
188     m_messageQueue.append(Task::create(task, mode.crossThreadString()));
189 }
190
191 PassOwnPtr<WorkerRunLoop::Task> WorkerRunLoop::Task::create(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
192 {
193     return adoptPtr(new Task(task, mode));
194 }
195
196 void WorkerRunLoop::Task::performTask(ScriptExecutionContext* context)
197 {
198     WorkerContext* workerContext = static_cast<WorkerContext *>(context);
199     if (!workerContext->isClosing() || m_task->isCleanupTask())
200         m_task->performTask(context);
201 }
202
203 WorkerRunLoop::Task::Task(PassOwnPtr<ScriptExecutionContext::Task> task, const String& mode)
204     : m_task(task)
205     , m_mode(mode.crossThreadString())
206 {
207 }
208
209
210 } // namespace WebCore
211
212 #endif // ENABLE(WORKERS)