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