static struct pe_watcher_vtbl pe_timer_vtbl; static pe_watcher *pe_timer_allocate(HV *stash, SV *temple) { pe_timer *ev; EvNew(7, ev, 1, pe_timer); assert(ev); ev->base.vtbl = &pe_timer_vtbl; PE_RING_INIT(&ev->tm.ring, ev); ev->tm.at = 0; ev->interval = &PL_sv_undef; pe_watcher_init(&ev->base, stash, temple); return (pe_watcher*) ev; } static void pe_timer_dtor(pe_watcher *ev) { pe_timer *tm = (pe_timer*) ev; SvREFCNT_dec(tm->interval); pe_watcher_dtor(ev); EvFree(7, ev); } static char *pe_timer_start(pe_watcher *ev, int repeat) { STRLEN n_a; pe_timer *tm = (pe_timer*) ev; if (!ev->callback) return "without callback"; if (repeat) { /* We just finished the callback and need to re-insert at the appropriate time increment. */ double interval; if (!sv_2interval("timer", tm->interval, &interval)) return "repeating timer has no interval"; tm->tm.at = interval + (WaHARD(ev)? tm->tm.at : NVtime()); } if (!tm->tm.at) return "timer unset"; pe_timeable_start(&tm->tm); return 0; } static void pe_timer_stop(pe_watcher *ev) { pe_timeable_stop(&((pe_timer*)ev)->tm); } static void pe_timer_alarm(pe_watcher *wa, pe_timeable *tm) { pe_event *ev = (*wa->vtbl->new_event)(wa); ++ev->hits; queueEvent(ev); } WKEYMETH(_timer_at) { pe_timer *tp = (pe_timer*)ev; if (nval) { int active = WaPOLLING(ev); if (active) pe_watcher_off(ev); tp->tm.at = SvNV(nval); if (active) pe_watcher_on(ev, 0); } { dSP; XPUSHs(sv_2mortal(newSVnv(tp->tm.at))); PUTBACK; } } WKEYMETH(_timer_interval) { pe_timer *tp = (pe_timer*)ev; if (nval) { SV *old = tp->interval; tp->interval = SvREFCNT_inc(nval); SvREFCNT_dec(old); VERIFYINTERVAL("timer", tp->interval); /* recalc expiration XXX */ } { dSP; XPUSHs(tp->interval); PUTBACK; } } static void boot_timer() { pe_watcher_vtbl *vt = &pe_timer_vtbl; memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl)); vt->dtor = pe_timer_dtor; vt->start = pe_timer_start; vt->stop = pe_timer_stop; vt->alarm = pe_timer_alarm; pe_register_vtbl(vt, gv_stashpv("Event::timer",1), &event_vtbl); }