]> git.saurik.com Git - apple/javascriptcore.git/blob - heap/HeapTimer.cpp
JavaScriptCore-1218.33.tar.gz
[apple/javascriptcore.git] / heap / HeapTimer.cpp
1 /*
2 * Copyright (C) 2012 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 "HeapTimer.h"
28
29 #include "APIShims.h"
30 #include "JSObject.h"
31 #include "JSString.h"
32
33 #include <wtf/MainThread.h>
34 #include <wtf/Threading.h>
35
36 #if PLATFORM(QT)
37 #include <QCoreApplication>
38 #include <QMutexLocker>
39 #include <QThread>
40 #include <QTimerEvent>
41 #elif PLATFORM(EFL)
42 #include <Ecore.h>
43 #endif
44
45 namespace JSC {
46
47 #if USE(CF)
48
49 const CFTimeInterval HeapTimer::s_decade = 60 * 60 * 24 * 365 * 10;
50
51 static const void* retainAPILock(const void* info)
52 {
53 static_cast<JSLock*>(const_cast<void*>(info))->ref();
54 return info;
55 }
56
57 static void releaseAPILock(const void* info)
58 {
59 static_cast<JSLock*>(const_cast<void*>(info))->deref();
60 }
61
62 HeapTimer::HeapTimer(VM* vm, CFRunLoopRef runLoop)
63 : m_vm(vm)
64 , m_runLoop(runLoop)
65 {
66 memset(&m_context, 0, sizeof(CFRunLoopTimerContext));
67 m_context.info = &vm->apiLock();
68 m_context.retain = retainAPILock;
69 m_context.release = releaseAPILock;
70 m_timer = adoptCF(CFRunLoopTimerCreate(0, s_decade, s_decade, 0, 0, HeapTimer::timerDidFire, &m_context));
71 CFRunLoopAddTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes);
72 }
73
74 HeapTimer::~HeapTimer()
75 {
76 CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes);
77 CFRunLoopTimerInvalidate(m_timer.get());
78 }
79
80 void HeapTimer::timerDidFire(CFRunLoopTimerRef timer, void* context)
81 {
82 JSLock* apiLock = static_cast<JSLock*>(context);
83 apiLock->lock();
84
85 VM* vm = apiLock->vm();
86 // The VM has been destroyed, so we should just give up.
87 if (!vm) {
88 apiLock->unlock();
89 return;
90 }
91
92 HeapTimer* heapTimer = 0;
93 #if PLATFORM(IOS)
94 if (vm->heap.activityCallback() && vm->heap.activityCallback()->m_timer.get() == timer)
95 heapTimer = vm->heap.activityCallback();
96 #else
97 if (vm->heap.activityCallback()->m_timer.get() == timer)
98 heapTimer = vm->heap.activityCallback();
99 #endif // PLATFORM(IOS)
100 else if (vm->heap.sweeper()->m_timer.get() == timer)
101 heapTimer = vm->heap.sweeper();
102 else
103 RELEASE_ASSERT_NOT_REACHED();
104
105 {
106 APIEntryShim shim(vm);
107 heapTimer->doWork();
108 }
109
110 apiLock->unlock();
111 }
112
113 #elif PLATFORM(BLACKBERRY)
114
115 HeapTimer::HeapTimer(VM* vm)
116 : m_vm(vm)
117 , m_timer(this, &HeapTimer::timerDidFire)
118 {
119 // FIXME: Implement HeapTimer for other threads.
120 if (WTF::isMainThread() && !m_timer.tryCreateClient())
121 CRASH();
122 }
123
124 HeapTimer::~HeapTimer()
125 {
126 }
127
128 void HeapTimer::timerDidFire()
129 {
130 doWork();
131 }
132
133 void HeapTimer::invalidate()
134 {
135 }
136
137 #elif PLATFORM(QT)
138
139 HeapTimer::HeapTimer(VM* vm)
140 : m_vm(vm)
141 , m_newThread(0)
142 , m_mutex(QMutex::NonRecursive)
143 {
144 // The HeapTimer might be created before the runLoop is started,
145 // but we need to ensure the thread has an eventDispatcher already.
146 QEventLoop fakeLoop(this);
147 }
148
149 HeapTimer::~HeapTimer()
150 {
151 QMutexLocker lock(&m_mutex);
152 m_timer.stop();
153 }
154
155 void HeapTimer::timerEvent(QTimerEvent*)
156 {
157 QMutexLocker lock(&m_mutex);
158 if (m_newThread) {
159 // We need to wait with processing until we are on the right thread.
160 return;
161 }
162
163 APIEntryShim shim(m_vm);
164 doWork();
165 }
166
167 void HeapTimer::customEvent(QEvent*)
168 {
169 ASSERT(m_newThread);
170 QMutexLocker lock(&m_mutex);
171 moveToThread(m_newThread);
172 m_newThread = 0;
173 }
174
175 #elif PLATFORM(EFL)
176
177 HeapTimer::HeapTimer(VM* vm)
178 : m_vm(vm)
179 , m_timer(0)
180 {
181 }
182
183 HeapTimer::~HeapTimer()
184 {
185 stop();
186 }
187
188 Ecore_Timer* HeapTimer::add(double delay, void* agent)
189 {
190 return ecore_timer_add(delay, reinterpret_cast<Ecore_Task_Cb>(timerEvent), agent);
191 }
192
193 void HeapTimer::stop()
194 {
195 if (!m_timer)
196 return;
197
198 ecore_timer_del(m_timer);
199 m_timer = 0;
200 }
201
202 bool HeapTimer::timerEvent(void* info)
203 {
204 HeapTimer* agent = static_cast<HeapTimer*>(info);
205
206 APIEntryShim shim(agent->m_vm);
207 agent->doWork();
208 agent->m_timer = 0;
209
210 return ECORE_CALLBACK_CANCEL;
211 }
212
213 #else
214 HeapTimer::HeapTimer(VM* vm)
215 : m_vm(vm)
216 {
217 }
218
219 HeapTimer::~HeapTimer()
220 {
221 }
222
223 void HeapTimer::invalidate()
224 {
225 }
226
227 #endif
228
229
230 } // namespace JSC