Add WTF::move()
[WebKit-https.git] / 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 #include "ScriptExecutionContext.h"
34 #include "SharedTimer.h"
35 #include "ThreadGlobalData.h"
36 #include "ThreadTimers.h"
37 #include "WorkerRunLoop.h"
38 #include "WorkerGlobalScope.h"
39 #include "WorkerThread.h"
40 #include <wtf/CurrentTime.h>
41
42 namespace WebCore {
43
44 class WorkerSharedTimer : public SharedTimer {
45 public:
46     WorkerSharedTimer()
47         : m_sharedTimerFunction(0)
48         , m_nextFireTime(0)
49     {
50     }
51
52     // SharedTimer interface.
53     virtual void setFiredFunction(void (*function)()) { m_sharedTimerFunction = function; }
54     virtual void setFireInterval(double interval) { m_nextFireTime = interval + currentTime(); }
55     virtual void stop() { m_nextFireTime = 0; }
56
57     bool isActive() { return m_sharedTimerFunction && m_nextFireTime; }
58     double fireTime() { return m_nextFireTime; }
59     void fire() { m_sharedTimerFunction(); }
60
61 private:
62     void (*m_sharedTimerFunction)();
63     double m_nextFireTime;
64 };
65
66 class ModePredicate {
67 public:
68     ModePredicate(const String& mode)
69         : m_mode(mode)
70         , m_defaultMode(mode == WorkerRunLoop::defaultMode())
71     {
72     }
73
74     bool isDefaultMode() const
75     {
76         return m_defaultMode;
77     }
78
79     bool operator()(const WorkerRunLoop::Task& task) const
80     {
81         return m_defaultMode || m_mode == task.mode();
82     }
83
84 private:
85     String m_mode;
86     bool m_defaultMode;
87 };
88
89 WorkerRunLoop::WorkerRunLoop()
90     : m_sharedTimer(std::make_unique<WorkerSharedTimer>())
91     , m_nestedCount(0)
92     , m_uniqueId(0)
93 {
94 }
95
96 WorkerRunLoop::~WorkerRunLoop()
97 {
98     ASSERT(!m_nestedCount);
99 }
100
101 String WorkerRunLoop::defaultMode()
102 {
103     return String();
104 }
105
106 class RunLoopSetup {
107     WTF_MAKE_NONCOPYABLE(RunLoopSetup);
108 public:
109     RunLoopSetup(WorkerRunLoop& runLoop)
110         : m_runLoop(runLoop)
111     {
112         if (!m_runLoop.m_nestedCount)
113             threadGlobalData().threadTimers().setSharedTimer(m_runLoop.m_sharedTimer.get());
114         m_runLoop.m_nestedCount++;
115     }
116
117     ~RunLoopSetup()
118     {
119         m_runLoop.m_nestedCount--;
120         if (!m_runLoop.m_nestedCount)
121             threadGlobalData().threadTimers().setSharedTimer(0);
122     }
123 private:
124     WorkerRunLoop& m_runLoop;
125 };
126
127 void WorkerRunLoop::run(WorkerGlobalScope* context)
128 {
129     RunLoopSetup setup(*this);
130     ModePredicate modePredicate(defaultMode());
131     MessageQueueWaitResult result;
132     do {
133         result = runInMode(context, modePredicate, WaitForMessage);
134     } while (result != MessageQueueTerminated);
135     runCleanupTasks(context);
136 }
137
138 MessageQueueWaitResult WorkerRunLoop::runInMode(WorkerGlobalScope* context, const String& mode, WaitMode waitMode)
139 {
140     RunLoopSetup setup(*this);
141     ModePredicate modePredicate(mode);
142     MessageQueueWaitResult result = runInMode(context, modePredicate, waitMode);
143     return result;
144 }
145
146 MessageQueueWaitResult WorkerRunLoop::runInMode(WorkerGlobalScope* context, const ModePredicate& predicate, WaitMode waitMode)
147 {
148     ASSERT(context);
149     ASSERT(context->thread().threadID() == currentThread());
150
151     double absoluteTime = 0.0;
152     if (waitMode == WaitForMessage)
153         absoluteTime = (predicate.isDefaultMode() && m_sharedTimer->isActive()) ? m_sharedTimer->fireTime() : MessageQueue<Task>::infiniteTime();
154     MessageQueueWaitResult result;
155     auto 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(*this, 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::runCleanupTasks(WorkerGlobalScope* context)
177 {
178     ASSERT(context);
179     ASSERT(context->thread().threadID() == currentThread());
180     ASSERT(m_messageQueue.killed());
181
182     while (true) {
183         auto task = m_messageQueue.tryGetMessageIgnoringKilled();
184         if (!task)
185             return;
186         task->performTask(*this, context);
187     }
188 }
189
190 void WorkerRunLoop::terminate()
191 {
192     m_messageQueue.kill();
193 }
194
195 void WorkerRunLoop::postTask(ScriptExecutionContext::Task task)
196 {
197     postTaskForMode(WTF::move(task), defaultMode());
198 }
199
200 void WorkerRunLoop::postTaskAndTerminate(ScriptExecutionContext::Task task)
201 {
202     m_messageQueue.appendAndKill(Task::create(WTF::move(task), defaultMode().isolatedCopy()));
203 }
204
205 void WorkerRunLoop::postTaskForMode(ScriptExecutionContext::Task task, const String& mode)
206 {
207     m_messageQueue.append(Task::create(WTF::move(task), mode.isolatedCopy()));
208 }
209
210 std::unique_ptr<WorkerRunLoop::Task> WorkerRunLoop::Task::create(ScriptExecutionContext::Task task, const String& mode)
211 {
212     return std::unique_ptr<Task>(new Task(WTF::move(task), mode));
213 }
214
215 void WorkerRunLoop::Task::performTask(const WorkerRunLoop& runLoop, WorkerGlobalScope* context)
216 {
217     if ((!context->isClosing() && !runLoop.terminated()) || m_task.isCleanupTask())
218         m_task.performTask(*context);
219 }
220
221 WorkerRunLoop::Task::Task(ScriptExecutionContext::Task task, const String& mode)
222     : m_task(WTF::move(task))
223     , m_mode(mode.isolatedCopy())
224 {
225 }
226
227 } // namespace WebCore