1/*
2 * Copyright (C) 2012, 2015-2017 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 <wtf/HashSet.h>
29#include <wtf/Lock.h>
30#include <wtf/RefPtr.h>
31#include <wtf/RetainPtr.h>
32#include <wtf/RunLoop.h>
33#include <wtf/SharedTask.h>
34#include <wtf/ThreadSafeRefCounted.h>
35
36#if USE(CF)
37#include <CoreFoundation/CoreFoundation.h>
38#endif
39
40namespace JSC {
41
42class JSLock;
43class VM;
44
45class JSRunLoopTimer : public ThreadSafeRefCounted<JSRunLoopTimer> {
46public:
47 typedef void TimerNotificationType();
48 using TimerNotificationCallback = RefPtr<WTF::SharedTask<TimerNotificationType>>;
49
50 class Manager {
51 WTF_MAKE_FAST_ALLOCATED;
52 WTF_MAKE_NONCOPYABLE(Manager);
53#if USE(CF)
54 static void timerDidFireCallback(CFRunLoopTimerRef, void*);
55#else
56 void timerDidFireCallback();
57#endif
58 Manager() = default;
59
60 void timerDidFire();
61
62 public:
63 using EpochTime = Seconds;
64
65 static Manager& shared();
66 void registerVM(VM&);
67 void unregisterVM(VM&);
68 void scheduleTimer(JSRunLoopTimer&, Seconds nextFireTime);
69 void cancelTimer(JSRunLoopTimer&);
70
71 Optional<Seconds> timeUntilFire(JSRunLoopTimer&);
72
73#if USE(CF)
74 void didChangeRunLoop(VM&, CFRunLoopRef newRunLoop);
75#endif
76
77 private:
78 Lock m_lock;
79
80 struct PerVMData {
81#if USE(CF)
82 PerVMData(Manager&) { }
83#else
84 PerVMData(Manager&);
85#endif
86 ~PerVMData();
87
88#if USE(CF)
89 void setRunLoop(Manager*, CFRunLoopRef);
90 RetainPtr<CFRunLoopTimerRef> timer;
91 RetainPtr<CFRunLoopRef> runLoop;
92 CFRunLoopTimerContext context;
93#else
94 RunLoop* runLoop;
95 std::unique_ptr<RunLoop::Timer<Manager>> timer;
96#endif
97 Vector<std::pair<Ref<JSRunLoopTimer>, EpochTime>> timers;
98 };
99
100 HashMap<Ref<JSLock>, std::unique_ptr<PerVMData>> m_mapping;
101 };
102
103 JSRunLoopTimer(VM*);
104 JS_EXPORT_PRIVATE virtual ~JSRunLoopTimer();
105 virtual void doWork(VM&) = 0;
106
107 void setTimeUntilFire(Seconds intervalInSeconds);
108 void cancelTimer();
109 bool isScheduled() const { return m_isScheduled; }
110
111 // Note: The only thing the timer notification callback cannot do is
112 // call setTimeUntilFire(). This will cause a deadlock. It would not
113 // be hard to make this work, however, there are no clients that need
114 // this behavior. We should implement it only if we find that we need it.
115 JS_EXPORT_PRIVATE void addTimerSetNotification(TimerNotificationCallback);
116 JS_EXPORT_PRIVATE void removeTimerSetNotification(TimerNotificationCallback);
117
118 JS_EXPORT_PRIVATE Optional<Seconds> timeUntilFire();
119
120protected:
121 static const Seconds s_decade;
122 Ref<JSLock> m_apiLock;
123
124private:
125 friend class Manager;
126
127 void timerDidFire();
128
129 HashSet<TimerNotificationCallback> m_timerSetCallbacks;
130 Lock m_timerCallbacksLock;
131
132 Lock m_lock;
133 bool m_isScheduled { false };
134};
135
136} // namespace JSC
137