1/*
2 * Copyright (C) 2012-2019 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 class PerVMData {
81 WTF_MAKE_FAST_ALLOCATED;
82 WTF_MAKE_NONCOPYABLE(PerVMData);
83 public:
84#if USE(CF)
85 PerVMData(Manager&) { }
86#else
87 PerVMData(Manager&);
88#endif
89 ~PerVMData();
90
91#if USE(CF)
92 void setRunLoop(Manager*, CFRunLoopRef);
93 RetainPtr<CFRunLoopTimerRef> timer;
94 RetainPtr<CFRunLoopRef> runLoop;
95 CFRunLoopTimerContext context;
96#else
97 RunLoop* runLoop;
98 std::unique_ptr<RunLoop::Timer<Manager>> timer;
99#endif
100 Vector<std::pair<Ref<JSRunLoopTimer>, EpochTime>> timers;
101 };
102
103 HashMap<Ref<JSLock>, std::unique_ptr<PerVMData>> m_mapping;
104 };
105
106 JSRunLoopTimer(VM&);
107 JS_EXPORT_PRIVATE virtual ~JSRunLoopTimer();
108 virtual void doWork(VM&) = 0;
109
110 void setTimeUntilFire(Seconds intervalInSeconds);
111 void cancelTimer();
112 bool isScheduled() const { return m_isScheduled; }
113
114 // Note: The only thing the timer notification callback cannot do is
115 // call setTimeUntilFire(). This will cause a deadlock. It would not
116 // be hard to make this work, however, there are no clients that need
117 // this behavior. We should implement it only if we find that we need it.
118 JS_EXPORT_PRIVATE void addTimerSetNotification(TimerNotificationCallback);
119 JS_EXPORT_PRIVATE void removeTimerSetNotification(TimerNotificationCallback);
120
121 JS_EXPORT_PRIVATE Optional<Seconds> timeUntilFire();
122
123protected:
124 static constexpr Seconds s_decade { 60 * 60 * 24 * 365 * 10 };
125 Ref<JSLock> m_apiLock;
126
127private:
128 friend class Manager;
129
130 void timerDidFire();
131
132 HashSet<TimerNotificationCallback> m_timerSetCallbacks;
133 Lock m_timerCallbacksLock;
134
135 Lock m_lock;
136 bool m_isScheduled { false };
137};
138
139} // namespace JSC
140