#include "config.h"
#include "HeapTimer.h"
#include "APIShims.h"
#include "JSObject.h"
#include "JSString.h"
#include <wtf/MainThread.h>
#include <wtf/Threading.h>
#if PLATFORM(QT)
#include <QCoreApplication>
#include <QMutexLocker>
#include <QThread>
#include <QTimerEvent>
#elif PLATFORM(EFL)
#include <Ecore.h>
#endif
namespace JSC {
#if USE(CF)
const CFTimeInterval HeapTimer::s_decade = 60 * 60 * 24 * 365 * 10;
static const void* retainAPILock(const void* info)
{
static_cast<JSLock*>(const_cast<void*>(info))->ref();
return info;
}
static void releaseAPILock(const void* info)
{
static_cast<JSLock*>(const_cast<void*>(info))->deref();
}
HeapTimer::HeapTimer(VM* vm, CFRunLoopRef runLoop)
: m_vm(vm)
, m_runLoop(runLoop)
{
memset(&m_context, 0, sizeof(CFRunLoopTimerContext));
m_context.info = &vm->apiLock();
m_context.retain = retainAPILock;
m_context.release = releaseAPILock;
m_timer = adoptCF(CFRunLoopTimerCreate(0, s_decade, s_decade, 0, 0, HeapTimer::timerDidFire, &m_context));
CFRunLoopAddTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes);
}
HeapTimer::~HeapTimer()
{
CFRunLoopRemoveTimer(m_runLoop.get(), m_timer.get(), kCFRunLoopCommonModes);
CFRunLoopTimerInvalidate(m_timer.get());
}
void HeapTimer::timerDidFire(CFRunLoopTimerRef timer, void* context)
{
JSLock* apiLock = static_cast<JSLock*>(context);
apiLock->lock();
VM* vm = apiLock->vm();
if (!vm) {
apiLock->unlock();
return;
}
HeapTimer* heapTimer = 0;
if (vm->heap.activityCallback()->m_timer.get() == timer)
heapTimer = vm->heap.activityCallback();
else if (vm->heap.sweeper()->m_timer.get() == timer)
heapTimer = vm->heap.sweeper();
else
RELEASE_ASSERT_NOT_REACHED();
{
APIEntryShim shim(vm);
heapTimer->doWork();
}
apiLock->unlock();
}
#elif PLATFORM(BLACKBERRY)
HeapTimer::HeapTimer(VM* vm)
: m_vm(vm)
, m_timer(this, &HeapTimer::timerDidFire)
{
if (WTF::isMainThread() && !m_timer.tryCreateClient())
CRASH();
}
HeapTimer::~HeapTimer()
{
}
void HeapTimer::timerDidFire()
{
doWork();
}
void HeapTimer::invalidate()
{
}
#elif PLATFORM(QT)
HeapTimer::HeapTimer(VM* vm)
: m_vm(vm)
, m_newThread(0)
, m_mutex(QMutex::NonRecursive)
{
QEventLoop fakeLoop(this);
}
HeapTimer::~HeapTimer()
{
QMutexLocker lock(&m_mutex);
m_timer.stop();
}
void HeapTimer::timerEvent(QTimerEvent*)
{
QMutexLocker lock(&m_mutex);
if (m_newThread) {
return;
}
APIEntryShim shim(m_vm);
doWork();
}
void HeapTimer::customEvent(QEvent*)
{
ASSERT(m_newThread);
QMutexLocker lock(&m_mutex);
moveToThread(m_newThread);
m_newThread = 0;
}
#elif PLATFORM(EFL)
HeapTimer::HeapTimer(VM* vm)
: m_vm(vm)
, m_timer(0)
{
}
HeapTimer::~HeapTimer()
{
stop();
}
Ecore_Timer* HeapTimer::add(double delay, void* agent)
{
return ecore_timer_add(delay, reinterpret_cast<Ecore_Task_Cb>(timerEvent), agent);
}
void HeapTimer::stop()
{
if (!m_timer)
return;
ecore_timer_del(m_timer);
m_timer = 0;
}
bool HeapTimer::timerEvent(void* info)
{
HeapTimer* agent = static_cast<HeapTimer*>(info);
APIEntryShim shim(agent->m_vm);
agent->doWork();
agent->m_timer = 0;
return ECORE_CALLBACK_CANCEL;
}
#else
HeapTimer::HeapTimer(VM* vm)
: m_vm(vm)
{
}
HeapTimer::~HeapTimer()
{
}
void HeapTimer::invalidate()
{
}
#endif
}