|  | /* | 
|  | * Copyright (C) 2012-2017 Apple Inc. All rights reserved. | 
|  | * | 
|  | * Redistribution and use in source and binary forms, with or without | 
|  | * modification, are permitted provided that the following conditions | 
|  | * are met: | 
|  | * 1. Redistributions of source code must retain the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer. | 
|  | * 2. Redistributions in binary form must reproduce the above copyright | 
|  | *    notice, this list of conditions and the following disclaimer in the | 
|  | *    documentation and/or other materials provided with the distribution. | 
|  | * | 
|  | * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | 
|  | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | 
|  | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
|  | * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR | 
|  | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | 
|  | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | 
|  | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | 
|  | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | 
|  | * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "JSRunLoopTimer.h" | 
|  |  | 
|  | #include "GCActivityCallback.h" | 
|  | #include "IncrementalSweeper.h" | 
|  | #include "JSCInlines.h" | 
|  | #include "JSObject.h" | 
|  | #include "JSString.h" | 
|  |  | 
|  | #include <wtf/MainThread.h> | 
|  | #include <wtf/Threading.h> | 
|  |  | 
|  | #if USE(GLIB_EVENT_LOOP) | 
|  | #include <glib.h> | 
|  | #include <wtf/glib/RunLoopSourcePriority.h> | 
|  | #endif | 
|  |  | 
|  | #include <mutex> | 
|  |  | 
|  | namespace JSC { | 
|  |  | 
|  | const Seconds JSRunLoopTimer::s_decade { 60 * 60 * 24 * 365 * 10 }; | 
|  |  | 
|  | void JSRunLoopTimer::timerDidFire() | 
|  | { | 
|  | JSLock* apiLock = m_apiLock.get(); | 
|  | if (!apiLock) { | 
|  | // Likely a buggy usage: the timer fired while JSRunLoopTimer was being destroyed. | 
|  | return; | 
|  | } | 
|  |  | 
|  | std::lock_guard<JSLock> lock(*apiLock); | 
|  | RefPtr<VM> vm = apiLock->vm(); | 
|  | if (!vm) { | 
|  | // The VM has been destroyed, so we should just give up. | 
|  | return; | 
|  | } | 
|  |  | 
|  | doWork(); | 
|  | } | 
|  |  | 
|  | #if USE(CF) | 
|  |  | 
|  | JSRunLoopTimer::JSRunLoopTimer(VM* vm) | 
|  | : m_vm(vm) | 
|  | , m_apiLock(&vm->apiLock()) | 
|  | { | 
|  | m_vm->registerRunLoopTimer(this); | 
|  | } | 
|  |  | 
|  | void JSRunLoopTimer::setRunLoop(CFRunLoopRef runLoop) | 
|  | { | 
|  | if (m_runLoop) { | 
|  | CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); | 
|  | CFRunLoopTimerInvalidate(m_timer.get()); | 
|  | m_runLoop.clear(); | 
|  | m_timer.clear(); | 
|  | } | 
|  |  | 
|  | m_runLoop = runLoop; | 
|  | if (runLoop) { | 
|  | memset(&m_context, 0, sizeof(CFRunLoopTimerContext)); | 
|  | m_context.info = this; | 
|  | m_timer = adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + s_decade.seconds(), s_decade.seconds(), 0, 0, JSRunLoopTimer::timerDidFireCallback, &m_context)); | 
|  | CFRunLoopAddTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes); | 
|  | } | 
|  | } | 
|  |  | 
|  | JSRunLoopTimer::~JSRunLoopTimer() | 
|  | { | 
|  | JSLock* apiLock = m_apiLock.get(); | 
|  | std::lock_guard<JSLock> lock(*apiLock); | 
|  | m_vm->unregisterRunLoopTimer(this); | 
|  | m_apiLock = nullptr; | 
|  | } | 
|  |  | 
|  | void JSRunLoopTimer::timerDidFireCallback(CFRunLoopTimerRef, void* contextPtr) | 
|  | { | 
|  | static_cast<JSRunLoopTimer*>(contextPtr)->timerDidFire(); | 
|  | } | 
|  |  | 
|  | void JSRunLoopTimer::scheduleTimer(Seconds intervalInSeconds) | 
|  | { | 
|  | CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + intervalInSeconds.seconds()); | 
|  | m_isScheduled = true; | 
|  | auto locker = holdLock(m_timerCallbacksLock); | 
|  | for (auto& task : m_timerSetCallbacks) | 
|  | task->run(); | 
|  | } | 
|  |  | 
|  | void JSRunLoopTimer::cancelTimer() | 
|  | { | 
|  | CFRunLoopTimerSetNextFireDate(m_timer.get(), CFAbsoluteTimeGetCurrent() + s_decade.seconds()); | 
|  | m_isScheduled = false; | 
|  | } | 
|  |  | 
|  | #else | 
|  |  | 
|  | JSRunLoopTimer::JSRunLoopTimer(VM* vm) | 
|  | : m_vm(vm) | 
|  | , m_apiLock(&vm->apiLock()) | 
|  | , m_timer(RunLoop::current(), this, &JSRunLoopTimer::timerDidFireCallback) | 
|  | { | 
|  | #if USE(GLIB_EVENT_LOOP) | 
|  | m_timer.setPriority(RunLoopSourcePriority::JavascriptTimer); | 
|  | m_timer.setName("[JavaScriptCore] JSRunLoopTimer"); | 
|  | #endif | 
|  | m_timer.startOneShot(s_decade); | 
|  | } | 
|  |  | 
|  | JSRunLoopTimer::~JSRunLoopTimer() | 
|  | { | 
|  | } | 
|  |  | 
|  | void JSRunLoopTimer::timerDidFireCallback() | 
|  | { | 
|  | m_timer.startOneShot(s_decade); | 
|  | timerDidFire(); | 
|  | } | 
|  |  | 
|  | void JSRunLoopTimer::scheduleTimer(Seconds intervalInSeconds) | 
|  | { | 
|  | m_timer.startOneShot(intervalInSeconds); | 
|  | m_isScheduled = true; | 
|  |  | 
|  | auto locker = holdLock(m_timerCallbacksLock); | 
|  | for (auto& task : m_timerSetCallbacks) | 
|  | task->run(); | 
|  | } | 
|  |  | 
|  | void JSRunLoopTimer::cancelTimer() | 
|  | { | 
|  | m_timer.startOneShot(s_decade); | 
|  | m_isScheduled = false; | 
|  | } | 
|  |  | 
|  | #endif | 
|  |  | 
|  | void JSRunLoopTimer::addTimerSetNotification(TimerNotificationCallback callback) | 
|  | { | 
|  | auto locker = holdLock(m_timerCallbacksLock); | 
|  | m_timerSetCallbacks.add(callback); | 
|  | } | 
|  |  | 
|  | void JSRunLoopTimer::removeTimerSetNotification(TimerNotificationCallback callback) | 
|  | { | 
|  | auto locker = holdLock(m_timerCallbacksLock); | 
|  | m_timerSetCallbacks.remove(callback); | 
|  | } | 
|  |  | 
|  | } // namespace JSC |