1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
4 * Portions Copyright (c) 2010 Motorola Mobility, Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
17 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
19 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
25 * THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28#pragma once
29
30#include <wtf/Condition.h>
31#include <wtf/Deque.h>
32#include <wtf/Forward.h>
33#include <wtf/FunctionDispatcher.h>
34#include <wtf/HashMap.h>
35#include <wtf/RetainPtr.h>
36#include <wtf/Seconds.h>
37#include <wtf/ThreadingPrimitives.h>
38
39#if USE(GLIB_EVENT_LOOP)
40#include <wtf/glib/GRefPtr.h>
41#endif
42
43namespace WTF {
44
45class RunLoop : public FunctionDispatcher {
46 WTF_MAKE_NONCOPYABLE(RunLoop);
47public:
48 // Must be called from the main thread (except for the Mac platform, where it
49 // can be called from any thread).
50 WTF_EXPORT_PRIVATE static void initializeMainRunLoop();
51
52 WTF_EXPORT_PRIVATE static RunLoop& current();
53 WTF_EXPORT_PRIVATE static RunLoop& main();
54 WTF_EXPORT_PRIVATE static bool isMain();
55 ~RunLoop();
56
57 void dispatch(Function<void()>&&) override;
58
59 WTF_EXPORT_PRIVATE static void run();
60 WTF_EXPORT_PRIVATE void stop();
61 WTF_EXPORT_PRIVATE void wakeUp();
62
63#if USE(COCOA_EVENT_LOOP)
64 WTF_EXPORT_PRIVATE void runForDuration(Seconds duration);
65#endif
66
67#if USE(GLIB_EVENT_LOOP)
68 WTF_EXPORT_PRIVATE GMainContext* mainContext() const { return m_mainContext.get(); }
69#endif
70
71#if USE(GENERIC_EVENT_LOOP) || USE(WINDOWS_EVENT_LOOP)
72 // Run the single iteration of the RunLoop. It consumes the pending tasks and expired timers, but it won't be blocked.
73 WTF_EXPORT_PRIVATE static void iterate();
74#endif
75
76#if USE(WINDOWS_EVENT_LOOP)
77 static void registerRunLoopMessageWindowClass();
78#endif
79
80#if USE(GLIB_EVENT_LOOP) || USE(GENERIC_EVENT_LOOP)
81 WTF_EXPORT_PRIVATE void dispatchAfter(Seconds, Function<void()>&&);
82#endif
83
84 class TimerBase {
85 WTF_MAKE_FAST_ALLOCATED;
86 friend class RunLoop;
87 public:
88 WTF_EXPORT_PRIVATE explicit TimerBase(RunLoop&);
89 WTF_EXPORT_PRIVATE virtual ~TimerBase();
90
91 void startRepeating(Seconds repeatInterval) { startInternal(repeatInterval, true); }
92 void startOneShot(Seconds interval) { startInternal(interval, false); }
93
94 WTF_EXPORT_PRIVATE void stop();
95 WTF_EXPORT_PRIVATE bool isActive() const;
96 WTF_EXPORT_PRIVATE Seconds secondsUntilFire() const;
97
98 virtual void fired() = 0;
99
100#if USE(GLIB_EVENT_LOOP)
101 void setName(const char*);
102 void setPriority(int);
103#endif
104
105 private:
106 void startInternal(Seconds nextFireInterval, bool repeat)
107 {
108 start(std::max(nextFireInterval, 0_s), repeat);
109 }
110
111 WTF_EXPORT_PRIVATE void start(Seconds nextFireInterval, bool repeat);
112
113 Ref<RunLoop> m_runLoop;
114
115#if USE(WINDOWS_EVENT_LOOP)
116 bool isActive(const AbstractLocker&) const;
117 void timerFired();
118 MonotonicTime m_nextFireDate;
119 Seconds m_interval;
120 bool m_isRepeating { false };
121 bool m_isActive { false };
122#elif USE(COCOA_EVENT_LOOP)
123 static void timerFired(CFRunLoopTimerRef, void*);
124 RetainPtr<CFRunLoopTimerRef> m_timer;
125#elif USE(GLIB_EVENT_LOOP)
126 void updateReadyTime();
127 GRefPtr<GSource> m_source;
128 bool m_isRepeating { false };
129 Seconds m_fireInterval { 0 };
130#elif USE(GENERIC_EVENT_LOOP)
131 bool isActive(const AbstractLocker&) const;
132 void stop(const AbstractLocker&);
133
134 class ScheduledTask;
135 RefPtr<ScheduledTask> m_scheduledTask;
136#endif
137 };
138
139 template <typename TimerFiredClass>
140 class Timer : public TimerBase {
141 public:
142 typedef void (TimerFiredClass::*TimerFiredFunction)();
143
144 Timer(RunLoop& runLoop, TimerFiredClass* o, TimerFiredFunction f)
145 : TimerBase(runLoop)
146 , m_function(f)
147 , m_object(o)
148 {
149 }
150
151 private:
152 void fired() override { (m_object->*m_function)(); }
153
154 // This order should be maintained due to MSVC bug.
155 // http://computer-programming-forum.com/7-vc.net/6fbc30265f860ad1.htm
156 TimerFiredFunction m_function;
157 TimerFiredClass* m_object;
158 };
159
160 class Holder;
161
162private:
163 RunLoop();
164
165 void performWork();
166
167 Lock m_functionQueueLock;
168 Deque<Function<void()>> m_functionQueue;
169
170#if USE(WINDOWS_EVENT_LOOP)
171 static LRESULT CALLBACK RunLoopWndProc(HWND, UINT, WPARAM, LPARAM);
172 LRESULT wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
173 HWND m_runLoopMessageWindow;
174
175 Lock m_loopLock;
176#elif USE(COCOA_EVENT_LOOP)
177 static void performWork(void*);
178 RetainPtr<CFRunLoopRef> m_runLoop;
179 RetainPtr<CFRunLoopSourceRef> m_runLoopSource;
180#elif USE(GLIB_EVENT_LOOP)
181 GRefPtr<GMainContext> m_mainContext;
182 Vector<GRefPtr<GMainLoop>> m_mainLoops;
183 GRefPtr<GSource> m_source;
184#elif USE(GENERIC_EVENT_LOOP)
185 void schedule(Ref<TimerBase::ScheduledTask>&&);
186 void schedule(const AbstractLocker&, Ref<TimerBase::ScheduledTask>&&);
187 void wakeUp(const AbstractLocker&);
188 void scheduleAndWakeUp(const AbstractLocker&, Ref<TimerBase::ScheduledTask>&&);
189
190 enum class RunMode {
191 Iterate,
192 Drain
193 };
194
195 enum class Status {
196 Clear,
197 Stopping,
198 };
199 void runImpl(RunMode);
200 bool populateTasks(RunMode, Status&, Deque<RefPtr<TimerBase::ScheduledTask>>&);
201
202 friend class TimerBase;
203
204 Lock m_loopLock;
205 Condition m_readyToRun;
206 Condition m_stopCondition;
207 Vector<RefPtr<TimerBase::ScheduledTask>> m_schedules;
208 Vector<Status*> m_mainLoops;
209 bool m_shutdown { false };
210 bool m_pendingTasks { false };
211#endif
212};
213
214} // namespace WTF
215
216using WTF::RunLoop;
217