1/*
2 * Copyright (C) 2006 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 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 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#pragma once
27
28#include "ThreadTimers.h"
29#include <functional>
30#include <wtf/Function.h>
31#include <wtf/MonotonicTime.h>
32#include <wtf/Noncopyable.h>
33#include <wtf/Optional.h>
34#include <wtf/Seconds.h>
35#include <wtf/Threading.h>
36#include <wtf/Vector.h>
37#include <wtf/WeakPtr.h>
38
39#if PLATFORM(IOS_FAMILY)
40#include "WebCoreThread.h"
41#endif
42
43namespace WebCore {
44
45class TimerBase {
46 WTF_MAKE_NONCOPYABLE(TimerBase);
47 WTF_MAKE_FAST_ALLOCATED;
48public:
49 WEBCORE_EXPORT TimerBase();
50 WEBCORE_EXPORT virtual ~TimerBase();
51
52 WEBCORE_EXPORT void start(Seconds nextFireInterval, Seconds repeatInterval);
53
54 void startRepeating(Seconds repeatInterval) { start(repeatInterval, repeatInterval); }
55 void startOneShot(Seconds interval) { start(interval, 0_s); }
56
57 WEBCORE_EXPORT void stop();
58 bool isActive() const;
59
60 WEBCORE_EXPORT Seconds nextFireInterval() const;
61 Seconds nextUnalignedFireInterval() const;
62 Seconds repeatInterval() const { return m_repeatInterval; }
63
64 void augmentFireInterval(Seconds delta) { setNextFireTime(m_heapItem->time + delta); }
65 void augmentRepeatInterval(Seconds delta) { augmentFireInterval(delta); m_repeatInterval += delta; }
66
67 void didChangeAlignmentInterval();
68
69 static void fireTimersInNestedEventLoop();
70
71private:
72 virtual void fired() = 0;
73
74 virtual Optional<MonotonicTime> alignedFireTime(MonotonicTime) const { return WTF::nullopt; }
75
76 void checkConsistency() const;
77 void checkHeapIndex() const;
78
79 void setNextFireTime(MonotonicTime);
80
81 bool inHeap() const { return m_heapItem && m_heapItem->isInHeap(); }
82
83 bool hasValidHeapPosition() const;
84 void updateHeapIfNeeded(MonotonicTime oldTime);
85
86 void heapDecreaseKey();
87 void heapDelete();
88 void heapDeleteMin();
89 void heapIncreaseKey();
90 void heapInsert();
91 void heapPop();
92 void heapPopMin();
93 static void heapDeleteNullMin(ThreadTimerHeap&);
94
95 MonotonicTime nextFireTime() const { return m_heapItem ? m_heapItem->time : MonotonicTime { }; }
96
97 MonotonicTime m_unalignedNextFireTime; // m_nextFireTime not considering alignment interval
98 Seconds m_repeatInterval; // 0 if not repeating
99
100 RefPtr<ThreadTimerHeapItem> m_heapItem;
101 Ref<Thread> m_thread { Thread::current() };
102
103 friend class ThreadTimers;
104 friend class TimerHeapLessThanFunction;
105 friend class TimerHeapReference;
106};
107
108
109class Timer : public TimerBase {
110 WTF_MAKE_FAST_ALLOCATED;
111public:
112 template <typename TimerFiredClass, typename TimerFiredBaseClass>
113 Timer(TimerFiredClass& object, void (TimerFiredBaseClass::*function)())
114 : m_function(std::bind(function, &object))
115 {
116 }
117
118 Timer(WTF::Function<void ()>&& function)
119 : m_function(WTFMove(function))
120 {
121 }
122
123private:
124 void fired() override
125 {
126 m_function();
127 }
128
129 WTF::Function<void ()> m_function;
130};
131
132inline bool TimerBase::isActive() const
133{
134 // FIXME: Write this in terms of USE(WEB_THREAD) instead of PLATFORM(IOS_FAMILY).
135#if !PLATFORM(IOS_FAMILY)
136 ASSERT(m_thread.ptr() == &Thread::current());
137#else
138 ASSERT(WebThreadIsCurrent() || pthread_main_np() || m_thread.ptr() == &Thread::current());
139#endif // PLATFORM(IOS_FAMILY)
140 return static_cast<bool>(nextFireTime());
141}
142
143class DeferrableOneShotTimer : protected TimerBase {
144 WTF_MAKE_FAST_ALLOCATED;
145public:
146 template<typename TimerFiredClass>
147 DeferrableOneShotTimer(TimerFiredClass& object, void (TimerFiredClass::*function)(), Seconds delay)
148 : DeferrableOneShotTimer(std::bind(function, &object), delay)
149 {
150 }
151
152 DeferrableOneShotTimer(WTF::Function<void ()>&& function, Seconds delay)
153 : m_function(WTFMove(function))
154 , m_delay(delay)
155 , m_shouldRestartWhenTimerFires(false)
156 {
157 }
158
159 void restart()
160 {
161 // Setting this boolean is much more efficient than calling startOneShot
162 // again, which might result in rescheduling the system timer which
163 // can be quite expensive.
164
165 if (isActive()) {
166 m_shouldRestartWhenTimerFires = true;
167 return;
168 }
169 startOneShot(m_delay);
170 }
171
172 void stop()
173 {
174 m_shouldRestartWhenTimerFires = false;
175 TimerBase::stop();
176 }
177
178 using TimerBase::isActive;
179
180private:
181 void fired() override
182 {
183 if (m_shouldRestartWhenTimerFires) {
184 m_shouldRestartWhenTimerFires = false;
185 startOneShot(m_delay);
186 return;
187 }
188
189 m_function();
190 }
191
192 WTF::Function<void ()> m_function;
193
194 Seconds m_delay;
195 bool m_shouldRestartWhenTimerFires;
196};
197
198}
199