1/*
2 * Copyright (C) 2010-2019 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#include <wtf/text/WTFString.h>
39
40#if USE(CF)
41#include <CoreFoundation/CFRunLoop.h>
42#endif
43
44#if USE(GLIB_EVENT_LOOP)
45#include <wtf/glib/GRefPtr.h>
46#endif
47
48namespace WTF {
49
50#if USE(CF)
51using RunLoopMode = CFStringRef;
52#define DefaultRunLoopMode kCFRunLoopDefaultMode
53#else
54using RunLoopMode = unsigned;
55#define DefaultRunLoopMode 0
56#endif
57
58class RunLoop : public FunctionDispatcher {
59 WTF_MAKE_NONCOPYABLE(RunLoop);
60public:
61 // Must be called from the main thread (except for the Mac platform, where it
62 // can be called from any thread).
63 WTF_EXPORT_PRIVATE static void initializeMainRunLoop();
64
65 WTF_EXPORT_PRIVATE static RunLoop& current();
66 WTF_EXPORT_PRIVATE static RunLoop& main();
67 WTF_EXPORT_PRIVATE static bool isMain();
68 ~RunLoop();
69
70 void dispatch(Function<void()>&&) override;
71
72 WTF_EXPORT_PRIVATE static void run();
73 WTF_EXPORT_PRIVATE void stop();
74 WTF_EXPORT_PRIVATE void wakeUp();
75
76 enum class CycleResult { Continue, Stop };
77 WTF_EXPORT_PRIVATE CycleResult static cycle(RunLoopMode = DefaultRunLoopMode);
78
79#if USE(COCOA_EVENT_LOOP)
80 WTF_EXPORT_PRIVATE void runForDuration(Seconds duration);
81#endif
82
83#if USE(GLIB_EVENT_LOOP)
84 WTF_EXPORT_PRIVATE GMainContext* mainContext() const { return m_mainContext.get(); }
85#endif
86
87#if USE(GENERIC_EVENT_LOOP) || USE(WINDOWS_EVENT_LOOP)
88 // Run the single iteration of the RunLoop. It consumes the pending tasks and expired timers, but it won't be blocked.
89 WTF_EXPORT_PRIVATE static void iterate();
90#endif
91
92#if USE(WINDOWS_EVENT_LOOP)
93 static void registerRunLoopMessageWindowClass();
94#endif
95
96#if USE(GLIB_EVENT_LOOP) || USE(GENERIC_EVENT_LOOP)
97 WTF_EXPORT_PRIVATE void dispatchAfter(Seconds, Function<void()>&&);
98#endif
99
100 class TimerBase {
101 WTF_MAKE_FAST_ALLOCATED;
102 friend class RunLoop;
103 public:
104 WTF_EXPORT_PRIVATE explicit TimerBase(RunLoop&);
105 WTF_EXPORT_PRIVATE virtual ~TimerBase();
106
107 void startRepeating(Seconds repeatInterval) { startInternal(repeatInterval, true); }
108 void startOneShot(Seconds interval) { startInternal(interval, false); }
109
110 WTF_EXPORT_PRIVATE void stop();
111 WTF_EXPORT_PRIVATE bool isActive() const;
112 WTF_EXPORT_PRIVATE Seconds secondsUntilFire() const;
113
114 virtual void fired() = 0;
115
116#if USE(GLIB_EVENT_LOOP)
117 void setName(const char*);
118 void setPriority(int);
119#endif
120
121 private:
122 void startInternal(Seconds nextFireInterval, bool repeat)
123 {
124 start(std::max(nextFireInterval, 0_s), repeat);
125 }
126
127 WTF_EXPORT_PRIVATE void start(Seconds nextFireInterval, bool repeat);
128
129 Ref<RunLoop> m_runLoop;
130
131#if USE(WINDOWS_EVENT_LOOP)
132 bool isActive(const AbstractLocker&) const;
133 void timerFired();
134 MonotonicTime m_nextFireDate;
135 Seconds m_interval;
136 bool m_isRepeating { false };
137 bool m_isActive { false };
138#elif USE(COCOA_EVENT_LOOP)
139 static void timerFired(CFRunLoopTimerRef, void*);
140 RetainPtr<CFRunLoopTimerRef> m_timer;
141#elif USE(GLIB_EVENT_LOOP)
142 void updateReadyTime();
143 GRefPtr<GSource> m_source;
144 bool m_isRepeating { false };
145 Seconds m_fireInterval { 0 };
146#elif USE(GENERIC_EVENT_LOOP)
147 bool isActive(const AbstractLocker&) const;
148 void stop(const AbstractLocker&);
149
150 class ScheduledTask;
151 RefPtr<ScheduledTask> m_scheduledTask;
152#endif
153 };
154
155 template <typename TimerFiredClass>
156 class Timer : public TimerBase {
157 public:
158 typedef void (TimerFiredClass::*TimerFiredFunction)();
159
160 Timer(RunLoop& runLoop, TimerFiredClass* o, TimerFiredFunction f)
161 : TimerBase(runLoop)
162 , m_function(f)
163 , m_object(o)
164 {
165 }
166
167 private:
168 void fired() override { (m_object->*m_function)(); }
169
170 // This order should be maintained due to MSVC bug.
171 // http://computer-programming-forum.com/7-vc.net/6fbc30265f860ad1.htm
172 TimerFiredFunction m_function;
173 TimerFiredClass* m_object;
174 };
175
176 class Holder;
177
178private:
179 RunLoop();
180
181 void performWork();
182
183 Lock m_functionQueueLock;
184 Deque<Function<void()>> m_functionQueue;
185
186#if USE(WINDOWS_EVENT_LOOP)
187 static LRESULT CALLBACK RunLoopWndProc(HWND, UINT, WPARAM, LPARAM);
188 LRESULT wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
189 HWND m_runLoopMessageWindow;
190
191 Lock m_loopLock;
192#elif USE(COCOA_EVENT_LOOP)
193 static void performWork(void*);
194 RetainPtr<CFRunLoopRef> m_runLoop;
195 RetainPtr<CFRunLoopSourceRef> m_runLoopSource;
196#elif USE(GLIB_EVENT_LOOP)
197 GRefPtr<GMainContext> m_mainContext;
198 Vector<GRefPtr<GMainLoop>> m_mainLoops;
199 GRefPtr<GSource> m_source;
200#elif USE(GENERIC_EVENT_LOOP)
201 void schedule(Ref<TimerBase::ScheduledTask>&&);
202 void schedule(const AbstractLocker&, Ref<TimerBase::ScheduledTask>&&);
203 void wakeUp(const AbstractLocker&);
204 void scheduleAndWakeUp(const AbstractLocker&, Ref<TimerBase::ScheduledTask>&&);
205
206 enum class RunMode {
207 Iterate,
208 Drain
209 };
210
211 enum class Status {
212 Clear,
213 Stopping,
214 };
215 void runImpl(RunMode);
216 bool populateTasks(RunMode, Status&, Deque<RefPtr<TimerBase::ScheduledTask>>&);
217
218 friend class TimerBase;
219
220 Lock m_loopLock;
221 Condition m_readyToRun;
222 Condition m_stopCondition;
223 Vector<RefPtr<TimerBase::ScheduledTask>> m_schedules;
224 Vector<Status*> m_mainLoops;
225 bool m_shutdown { false };
226 bool m_pendingTasks { false };
227#endif
228};
229
230} // namespace WTF
231
232using WTF::RunLoop;
233using WTF::RunLoopMode;
234