Unreviewed, rolling out r235107.
[WebKit-https.git] / Source / JavaScriptCore / runtime / JSRunLoopTimer.cpp
1 /*
2  * Copyright (C) 2012-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 #include "config.h"
27 #include "JSRunLoopTimer.h"
28
29 #include "GCActivityCallback.h"
30 #include "IncrementalSweeper.h"
31 #include "JSCInlines.h"
32 #include "JSObject.h"
33 #include "JSString.h"
34
35 #include <wtf/MainThread.h>
36 #include <wtf/Threading.h>
37
38 #if USE(GLIB_EVENT_LOOP)
39 #include <glib.h>
40 #include <wtf/glib/RunLoopSourcePriority.h>
41 #endif
42
43 #include <mutex>
44
45 namespace JSC {
46
47 const Seconds JSRunLoopTimer::s_decade { 60 * 60 * 24 * 365 * 10 };
48
49 void JSRunLoopTimer::timerDidFire()
50 {
51     JSLock* apiLock = m_apiLock.get();
52     if (!apiLock) {
53         // Likely a buggy usage: the timer fired while JSRunLoopTimer was being destroyed.
54         return;
55     }
56
57     std::lock_guard<JSLock> lock(*apiLock);
58     RefPtr<VM> vm = apiLock->vm();
59     if (!vm) {
60         // The VM has been destroyed, so we should just give up.
61         return;
62     }
63
64     doWork();
65 }
66
67 #if USE(CF)
68
69 JSRunLoopTimer::JSRunLoopTimer(VM* vm)
70     : m_vm(vm)
71     , m_apiLock(&vm->apiLock())
72 {
73     m_vm->registerRunLoopTimer(this);
74 }
75
76 void JSRunLoopTimer::setRunLoop(CFRunLoopRef runLoop)
77 {
78     if (m_runLoop) {
79         CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes);
80         CFRunLoopTimerInvalidate(m_timer.get());
81         m_runLoop.clear();
82         m_timer.clear();
83     }
84
85     m_runLoop = runLoop;
86     if (runLoop) {
87         memset(&m_context, 0, sizeof(CFRunLoopTimerContext));
88         m_context.info = this;
89         m_timer = adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + s_decade.seconds(), s_decade.seconds(), 0, 0, JSRunLoopTimer::timerDidFireCallback, &m_context));
90         CFRunLoopAddTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes);
91     }
92 }
93
94 JSRunLoopTimer::~JSRunLoopTimer()
95 {
96     JSLock* apiLock = m_apiLock.get();
97     std::lock_guard<JSLock> lock(*apiLock);
98     m_vm->unregisterRunLoopTimer(this);
99     m_apiLock = nullptr;
100 }
101
102 void JSRunLoopTimer::timerDidFireCallback(CFRunLoopTimerRef, void* contextPtr)
103 {
104     static_cast<JSRunLoopTimer*>(contextPtr)->timerDidFire();
105 }
106
107 void JSRunLoopTimer::scheduleTimer(Seconds intervalInSeconds)
108 {
109     CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + intervalInSeconds.seconds());
110     m_isScheduled = true;
111     auto locker = holdLock(m_timerCallbacksLock);
112     for (auto& task : m_timerSetCallbacks)
113         task->run();
114 }
115
116 void JSRunLoopTimer::cancelTimer()
117 {
118     CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade.seconds());
119     m_isScheduled = false;
120 }
121
122 #else
123
124 JSRunLoopTimer::JSRunLoopTimer(VM* vm)
125     : m_vm(vm)
126     , m_apiLock(&vm->apiLock())
127     , m_timer(RunLoop::current(), this, &JSRunLoopTimer::timerDidFireCallback)
128 {
129 #if USE(GLIB_EVENT_LOOP)
130     m_timer.setPriority(RunLoopSourcePriority::JavascriptTimer);
131     m_timer.setName("[JavaScriptCore] JSRunLoopTimer");
132 #endif
133     m_timer.startOneShot(s_decade);
134 }
135
136 JSRunLoopTimer::~JSRunLoopTimer()
137 {
138 }
139
140 void JSRunLoopTimer::timerDidFireCallback()
141 {
142     m_timer.startOneShot(s_decade);
143     timerDidFire();
144 }
145
146 void JSRunLoopTimer::scheduleTimer(Seconds intervalInSeconds)
147 {
148     m_timer.startOneShot(intervalInSeconds);
149     m_isScheduled = true;
150
151     auto locker = holdLock(m_timerCallbacksLock);
152     for (auto& task : m_timerSetCallbacks)
153         task->run();
154 }
155
156 void JSRunLoopTimer::cancelTimer()
157 {
158     m_timer.startOneShot(s_decade);
159     m_isScheduled = false;
160 }
161
162 #endif
163
164 void JSRunLoopTimer::addTimerSetNotification(TimerNotificationCallback callback)
165 {
166     auto locker = holdLock(m_timerCallbacksLock);
167     m_timerSetCallbacks.add(callback);
168 }
169
170 void JSRunLoopTimer::removeTimerSetNotification(TimerNotificationCallback callback)
171 {
172     auto locker = holdLock(m_timerCallbacksLock);
173     m_timerSetCallbacks.remove(callback);
174 }
175
176 } // namespace JSC