Exemplo n.º 1
0
namespace WTF {

GMainLoopSource& GMainLoopSource::create()
{
    return *new GMainLoopSource(DeleteOnDestroy);
}

GMainLoopSource::GMainLoopSource()
    : m_deleteOnDestroy(DoNotDeleteOnDestroy)
    , m_status(Ready)
{
}

GMainLoopSource::GMainLoopSource(DeleteOnDestroyType deleteOnDestroy)
    : m_deleteOnDestroy(deleteOnDestroy)
    , m_status(Ready)
{
}

GMainLoopSource::~GMainLoopSource()
{
    cancel();
}

bool GMainLoopSource::isScheduled() const
{
    return m_status == Scheduled;
}

bool GMainLoopSource::isActive() const
{
    return m_status != Ready;
}

void GMainLoopSource::cancel()
{
    // Delete-on-destroy GMainLoopSource objects can't be cancelled.
    if (m_deleteOnDestroy == DeleteOnDestroy)
        return;

    // A valid context should only be present if GMainLoopSource is in the Scheduled or Dispatching state.
    ASSERT(!m_context.source || m_status == Scheduled || m_status == Dispatching);

    m_status = Ready;

    g_cancellable_cancel(m_context.socketCancellable.get());

    if (!m_context.source)
        return;

    Context context;
    context = WTF::move(m_context);
    context.destroySource();
}

void GMainLoopSource::scheduleIdleSource(const char* name, GSourceFunc sourceFunction, int priority, GMainContext* context)
{
    ASSERT(m_status == Ready);
    m_status = Scheduled;

    g_source_set_name(m_context.source.get(), name);
    if (priority != G_PRIORITY_DEFAULT_IDLE)
        g_source_set_priority(m_context.source.get(), priority);
    g_source_set_callback(m_context.source.get(), sourceFunction, this, nullptr);
    g_source_attach(m_context.source.get(), context);
}

void GMainLoopSource::schedule(const char* name, std::function<void ()> function, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(g_idle_source_new()),
        nullptr, // cancellable
        nullptr, // socketCancellable
        WTF::move(function),
        nullptr, // boolCallback
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleIdleSource(name, reinterpret_cast<GSourceFunc>(voidSourceCallback), priority, context);
}

void GMainLoopSource::schedule(const char* name, std::function<bool ()> function, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(g_idle_source_new()),
        nullptr, // cancellable
        nullptr, // socketCancellable
        nullptr, // voidCallback
        WTF::move(function),
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleIdleSource(name, reinterpret_cast<GSourceFunc>(boolSourceCallback), priority, context);
}

void GMainLoopSource::schedule(const char* name, std::function<bool (GIOCondition)> function, GSocket* socket, GIOCondition condition, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    GCancellable* socketCancellable = g_cancellable_new();
    m_context = {
        adoptGRef(g_socket_create_source(socket, condition, socketCancellable)),
        nullptr, // cancellable
        adoptGRef(socketCancellable),
        nullptr, // voidCallback
        nullptr, // boolCallback
        WTF::move(function),
        WTF::move(destroyFunction)
    };

    ASSERT(m_status == Ready);
    m_status = Scheduled;
    g_source_set_name(m_context.source.get(), name);
    g_source_set_callback(m_context.source.get(), reinterpret_cast<GSourceFunc>(socketSourceCallback), this, nullptr);
    g_source_attach(m_context.source.get(), context);
}

void GMainLoopSource::scheduleTimeoutSource(const char* name, GSourceFunc sourceFunction, int priority, GMainContext* context)
{
    ASSERT(m_status == Ready);
    m_status = Scheduled;

    g_source_set_name(m_context.source.get(), name);
    if (priority != G_PRIORITY_DEFAULT)
        g_source_set_priority(m_context.source.get(), priority);
    g_source_set_callback(m_context.source.get(), sourceFunction, this, nullptr);
    g_source_attach(m_context.source.get(), context);
}

void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<void ()> function, std::chrono::milliseconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(g_timeout_source_new(delay.count())),
        nullptr, // cancellable
        nullptr, // socketCancellable
        WTF::move(function),
        nullptr, // boolCallback
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(voidSourceCallback), priority, context);
}

void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<bool ()> function, std::chrono::milliseconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(g_timeout_source_new(delay.count())),
        nullptr, // cancellable
        nullptr, // socketCancellable
        nullptr, // voidCallback
        WTF::move(function),
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(boolSourceCallback), priority, context);
}

void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<void ()> function, std::chrono::seconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(g_timeout_source_new_seconds(delay.count())),
        nullptr, // cancellable
        nullptr, // socketCancellable
        WTF::move(function),
        nullptr, // boolCallback
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(voidSourceCallback), priority, context);
}

void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<bool ()> function, std::chrono::seconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(g_timeout_source_new_seconds(delay.count())),
        nullptr, // cancellable
        nullptr, // socketCancellable
        nullptr, // voidCallback
        WTF::move(function),
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(boolSourceCallback), priority, context);
}

struct MicrosecondsTimeoutSource {
    GSource source;
    uint64_t delay;
};

static GSourceFuncs microsecondsTimeoutSourceFunctions = {
    nullptr, // prepare
    nullptr, // check
    // dispatch
    [](GSource* source, GSourceFunc callback, gpointer userData) -> gboolean
    {
        bool repeat = callback(userData);
        if (repeat)
            g_source_set_ready_time(source, g_source_get_time(source) + reinterpret_cast<MicrosecondsTimeoutSource*>(source)->delay);
        return repeat;
    },
    nullptr, // finalize
    nullptr, // closure_callback
    nullptr // closure_marshall
};

static GSource* createMicrosecondsTimeoutSource(uint64_t delay)
{
    GSource* source = g_source_new(&microsecondsTimeoutSourceFunctions, sizeof(MicrosecondsTimeoutSource));
    reinterpret_cast<MicrosecondsTimeoutSource*>(source)->delay = delay;
    g_source_set_ready_time(source, g_get_monotonic_time() + delay);
    return source;
}

void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<void ()> function, std::chrono::microseconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(createMicrosecondsTimeoutSource(delay.count())),
        nullptr, // cancellable
        nullptr, // socketCancellable
        WTF::move(function),
        nullptr, // boolCallback
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(voidSourceCallback), priority, context);
}

void GMainLoopSource::scheduleAfterDelay(const char* name, std::function<bool ()> function, std::chrono::microseconds delay, int priority, std::function<void ()> destroyFunction, GMainContext* context)
{
    cancel();

    ASSERT(!m_context.source);
    m_context = {
        adoptGRef(createMicrosecondsTimeoutSource(delay.count())),
        nullptr, // cancellable
        nullptr, // socketCancellable
        nullptr, // voidCallback
        WTF::move(function),
        nullptr, // socketCallback
        WTF::move(destroyFunction)
    };
    scheduleTimeoutSource(name, reinterpret_cast<GSourceFunc>(boolSourceCallback), priority, context);
}

void GMainLoopSource::scheduleAndDeleteOnDestroy(const char* name, std::function<void()> function, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().schedule(name, function, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAndDeleteOnDestroy(const char* name, std::function<bool()> function, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().schedule(name, function, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy(const char* name, std::function<void()> function, std::chrono::milliseconds delay, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().scheduleAfterDelay(name, function, delay, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy(const char* name, std::function<bool()> function, std::chrono::milliseconds delay, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().scheduleAfterDelay(name, function, delay, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy(const char* name, std::function<void()> function, std::chrono::seconds delay, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().scheduleAfterDelay(name, function, delay, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy(const char* name, std::function<bool()> function, std::chrono::seconds delay, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().scheduleAfterDelay(name, function, delay, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy(const char* name, std::function<void()> function, std::chrono::microseconds delay, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().scheduleAfterDelay(name, function, delay, priority, destroyFunction, context);
}

void GMainLoopSource::scheduleAfterDelayAndDeleteOnDestroy(const char* name, std::function<bool()> function, std::chrono::microseconds delay, int priority, std::function<void()> destroyFunction, GMainContext* context)
{
    create().scheduleAfterDelay(name, function, delay, priority, destroyFunction, context);
}

bool GMainLoopSource::prepareVoidCallback(Context& context)
{
    if (!m_context.source)
        return false;

    context = WTF::move(m_context);

    ASSERT(context.voidCallback);
    ASSERT(m_status == Scheduled);
    m_status = Dispatching;

    return true;
}

void GMainLoopSource::finishVoidCallback()
{
    m_status = Ready;
}

void GMainLoopSource::voidCallback()
{
    Context context;
    if (!prepareVoidCallback(context))
        return;

    context.voidCallback();
    if (m_status != Ready && !m_context.source) {
        // Switch to Ready if it hasn't been re-scheduled or cancelled.
        finishVoidCallback();
    }

    context.destroySource();
    if (m_deleteOnDestroy == DeleteOnDestroy)
        delete this;
}

bool GMainLoopSource::prepareBoolCallback(Context& context)
{
    if (!m_context.source)
        return false;

    context = WTF::move(m_context);

    ASSERT(context.boolCallback);
    ASSERT(m_status == Scheduled || m_status == Dispatching);
    m_status = Dispatching;
    return true;
}

void GMainLoopSource::finishBoolCallback(bool retval, Context& context)
{
    // m_status should reflect whether the GMainLoopSource has been rescheduled during dispatch.
    ASSERT((!m_context.source && m_status == Dispatching) || m_status == Scheduled);
    if (retval && !m_context.source)
        m_context = WTF::move(context);
    else if (!retval)
        m_status = Ready;
}

bool GMainLoopSource::boolCallback()
{
    Context context;
    if (!prepareBoolCallback(context))
        return Stop;

    bool retval = context.boolCallback();
    if (m_status != Ready && !m_context.source) {
        // Prepare for a new iteration or switch to Ready if it hasn't been re-scheduled or cancelled.
        finishBoolCallback(retval, context);
    }

    if (context.source) {
        context.destroySource();
        if (m_deleteOnDestroy == DeleteOnDestroy)
            delete this;
    }

    return retval;
}

bool GMainLoopSource::socketCallback(GIOCondition condition)
{
    if (!m_context.source)
        return Stop;

    Context context;
    context = WTF::move(m_context);

    ASSERT(context.socketCallback);
    ASSERT(m_status == Scheduled || m_status == Dispatching);
    m_status = Dispatching;

    if (g_cancellable_is_cancelled(context.socketCancellable.get())) {
        context.destroySource();
        return Stop;
    }

    bool retval = context.socketCallback(condition);

    if (m_status != Ready && !m_context.source) {
        // m_status should reflect whether the GMainLoopSource has been rescheduled during dispatch.
        ASSERT((!m_context.source && m_status == Dispatching) || m_status == Scheduled);
        if (retval && !m_context.source)
            m_context = WTF::move(context);
        else if (!retval)
            m_status = Ready;
    }

    if (context.source)
        context.destroySource();

    return retval;
}

gboolean GMainLoopSource::voidSourceCallback(GMainLoopSource* source)
{
    source->voidCallback();
    return G_SOURCE_REMOVE;
}

gboolean GMainLoopSource::boolSourceCallback(GMainLoopSource* source)
{
    return source->boolCallback() == Continue;
}

gboolean GMainLoopSource::socketSourceCallback(GSocket*, GIOCondition condition, GMainLoopSource* source)
{
    return source->socketCallback(condition) == Continue;
}

void GMainLoopSource::Context::destroySource()
{
    g_source_destroy(source.get());
    if (destroyCallback)
        destroyCallback();
}

} // namespace WTF
Exemplo n.º 2
0
void GCActivityCallback::cancelTimer()
{
    m_delay = -1;
    g_source_set_ready_time(m_timer.get(), -1);
}
Exemplo n.º 3
0
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(kCFAllocatorDefault, 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();
    // The VM has been destroyed, so we should just give up.
    if (!vm) {
        apiLock->unlock();
        return;
    }

    HeapTimer* heapTimer = 0;
    if (vm->heap.fullActivityCallback() && vm->heap.fullActivityCallback()->m_timer.get() == timer)
        heapTimer = vm->heap.fullActivityCallback();
    else if (vm->heap.edenActivityCallback() && vm->heap.edenActivityCallback()->m_timer.get() == timer)
        heapTimer = vm->heap.edenActivityCallback();
    else if (vm->heap.sweeper()->m_timer.get() == timer)
        heapTimer = vm->heap.sweeper();
    else
        RELEASE_ASSERT_NOT_REACHED();

    {
        JSLockHolder locker(vm);
        heapTimer->doWork();
    }

    apiLock->unlock();
}

#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);
    
    JSLockHolder locker(agent->m_vm);
    agent->doWork();
    agent->m_timer = 0;
    
    return ECORE_CALLBACK_CANCEL;
}

#elif USE(GLIB)

static GSourceFuncs heapTimerSourceFunctions = {
    nullptr, // prepare
    nullptr, // check
    // dispatch
    [](GSource* source, GSourceFunc callback, gpointer userData) -> gboolean
    {
        if (g_source_get_ready_time(source) == -1)
            return G_SOURCE_CONTINUE;
        g_source_set_ready_time(source, -1);
        return callback(userData);
    },
    nullptr, // finalize
    nullptr, // closure_callback
    nullptr, // closure_marshall
};

HeapTimer::HeapTimer(VM* vm)
    : m_vm(vm)
    , m_apiLock(&vm->apiLock())
    , m_timer(adoptGRef(g_source_new(&heapTimerSourceFunctions, sizeof(GSource))))
{
    g_source_set_name(m_timer.get(), "[JavaScriptCore] HeapTimer");
    g_source_set_callback(m_timer.get(), [](gpointer userData) -> gboolean {
        static_cast<HeapTimer*>(userData)->timerDidFire();
        return G_SOURCE_CONTINUE;
    }, this, nullptr);
    g_source_attach(m_timer.get(), g_main_context_get_thread_default());
}

HeapTimer::~HeapTimer()
{
    g_source_destroy(m_timer.get());
}

void HeapTimer::timerDidFire()
{
    m_apiLock->lock();

    if (!m_apiLock->vm()) {
        // The VM has been destroyed, so we should just give up.
        m_apiLock->unlock();
        return;
    }

    {
        JSLockHolder locker(m_vm);
        doWork();
    }

    m_apiLock->unlock();
}

#else

HeapTimer::HeapTimer(VM* vm)
    : m_vm(vm)
{
}

HeapTimer::~HeapTimer()
{
}

void HeapTimer::invalidate()
{
}

#endif
    

} // namespace JSC
Exemplo n.º 4
0
static void
g_file_monitor_source_update_ready_time (GFileMonitorSource *fms)
{
  g_source_set_ready_time ((GSource *) fms, g_file_monitor_source_get_ready_time (fms));
}
void KeyboardEventRepeating::cancel()
{
    if (!!m_event.time)
        g_source_set_ready_time(m_source, -1);
    m_event = { 0, 0, 0 };
}