| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | static struct pe_watcher_vtbl pe_idle_vtbl; | 
| 2 |  |  |  |  |  |  | static pe_ring Idle; | 
| 3 |  |  |  |  |  |  |  | 
| 4 |  |  |  |  |  |  | /*#define D_IDLE(x) x  /**/ | 
| 5 |  |  |  |  |  |  | #define D_IDLE(x)  /**/ | 
| 6 |  |  |  |  |  |  |  | 
| 7 | 13 |  |  |  |  |  | static pe_watcher *pe_idle_allocate(HV *stash, SV *temple) { | 
| 8 |  |  |  |  |  |  | pe_idle *ev; | 
| 9 | 13 |  |  |  |  |  | EvNew(3, ev, 1, pe_idle); | 
| 10 | 13 |  |  |  |  |  | ev->base.vtbl = &pe_idle_vtbl; | 
| 11 | 13 |  |  |  |  |  | pe_watcher_init(&ev->base, stash, temple); | 
| 12 | 13 |  |  |  |  |  | PE_RING_INIT(&ev->tm.ring, ev); | 
| 13 | 13 |  |  |  |  |  | PE_RING_INIT(&ev->iring, ev); | 
| 14 | 13 |  |  |  |  |  | ev->max_interval = &PL_sv_undef; | 
| 15 | 13 |  |  |  |  |  | ev->min_interval = newSVnv(.01); | 
| 16 | 13 |  |  |  |  |  | return (pe_watcher*) ev; | 
| 17 |  |  |  |  |  |  | } | 
| 18 |  |  |  |  |  |  |  | 
| 19 | 13 |  |  |  |  |  | static void pe_idle_dtor(pe_watcher *ev) { | 
| 20 | 13 |  |  |  |  |  | pe_idle *ip = (pe_idle*) ev; | 
| 21 | 13 |  |  |  |  |  | SvREFCNT_dec(ip->max_interval); | 
| 22 | 13 |  |  |  |  |  | SvREFCNT_dec(ip->min_interval); | 
| 23 | 13 |  |  |  |  |  | pe_watcher_dtor(ev); | 
| 24 | 13 |  |  |  |  |  | EvFree(3, ev); | 
| 25 | 13 |  |  |  |  |  | } | 
| 26 |  |  |  |  |  |  |  | 
| 27 | 21 |  |  |  |  |  | static char *pe_idle_start(pe_watcher *ev, int repeating) { | 
| 28 |  |  |  |  |  |  | NV now; | 
| 29 |  |  |  |  |  |  | NV min,max; | 
| 30 | 21 |  |  |  |  |  | pe_idle *ip = (pe_idle*) ev; | 
| 31 | 21 | 50 |  |  |  |  | if (!ev->callback) | 
| 32 | 0 |  |  |  |  |  | return "without callback"; | 
| 33 | 21 | 100 |  |  |  |  | if (!repeating) ev->cbtime = NVtime(); | 
| 34 | 21 | 50 |  |  |  |  | now = WaHARD(ev)? ev->cbtime : NVtime(); | 
| 35 | 21 | 50 |  |  |  |  | if (sv_2interval("min", ip->min_interval, &min)) { | 
| 36 | 21 |  |  |  |  |  | ip->tm.at = min + now; | 
| 37 | 21 |  |  |  |  |  | pe_timeable_start(&ip->tm); | 
| 38 |  |  |  |  |  |  | D_IDLE(warn("min %.2f setup '%s'\n", min, SvPV(ev->desc,na))); | 
| 39 |  |  |  |  |  |  | } | 
| 40 |  |  |  |  |  |  | else { | 
| 41 | 0 |  |  |  |  |  | PE_RING_UNSHIFT(&ip->iring, &Idle); | 
| 42 |  |  |  |  |  |  | D_IDLE(warn("idle '%s'\n", SvPV(ev->desc,na))); | 
| 43 | 0 | 0 |  |  |  |  | if (sv_2interval("max", ip->max_interval, &max)) { | 
| 44 |  |  |  |  |  |  | D_IDLE(warn("max %.2f setup '%s'\n", max, SvPV(ev->desc,na))); | 
| 45 | 0 |  |  |  |  |  | ip->tm.at = max + now; | 
| 46 | 0 |  |  |  |  |  | pe_timeable_start(&ip->tm); | 
| 47 |  |  |  |  |  |  | } | 
| 48 |  |  |  |  |  |  | } | 
| 49 | 21 |  |  |  |  |  | return 0; | 
| 50 |  |  |  |  |  |  | } | 
| 51 |  |  |  |  |  |  |  | 
| 52 | 16 |  |  |  |  |  | static void pe_idle_alarm(pe_watcher *wa, pe_timeable *_ignore) { | 
| 53 | 16 |  |  |  |  |  | NV now = NVtime(); | 
| 54 |  |  |  |  |  |  | NV min,max,left; | 
| 55 | 16 |  |  |  |  |  | pe_idle *ip = (pe_idle*) wa; | 
| 56 | 16 |  |  |  |  |  | pe_timeable_stop(&ip->tm); | 
| 57 | 16 | 50 |  |  |  |  | if (sv_2interval("min", ip->min_interval, &min)) { | 
| 58 | 16 |  |  |  |  |  | left = wa->cbtime + min - now; | 
| 59 | 16 | 100 |  |  |  |  | if (left > IntervalEpsilon) { | 
| 60 | 1 |  |  |  |  |  | ++TimeoutTooEarly; | 
| 61 | 1 |  |  |  |  |  | ip->tm.at = now + left; | 
| 62 | 1 |  |  |  |  |  | pe_timeable_start(&ip->tm); | 
| 63 |  |  |  |  |  |  | D_IDLE(warn("min %.2f '%s'\n", left, SvPV(wa->desc,na))); | 
| 64 | 1 |  |  |  |  |  | return; | 
| 65 |  |  |  |  |  |  | } | 
| 66 |  |  |  |  |  |  | } | 
| 67 | 15 | 50 |  |  |  |  | if (PE_RING_EMPTY(&ip->iring)) { | 
| 68 | 15 |  |  |  |  |  | PE_RING_UNSHIFT(&ip->iring, &Idle); | 
| 69 |  |  |  |  |  |  | D_IDLE(warn("idle '%s'\n", SvPV(wa->desc,na))); | 
| 70 |  |  |  |  |  |  | } | 
| 71 | 15 | 50 |  |  |  |  | if (sv_2interval("max", ip->max_interval, &max)) { | 
| 72 | 0 |  |  |  |  |  | left = wa->cbtime + max - now; | 
| 73 | 0 | 0 |  |  |  |  | if (left < IntervalEpsilon) { | 
| 74 |  |  |  |  |  |  | pe_event *ev; | 
| 75 |  |  |  |  |  |  | D_IDLE(warn("max '%s'\n", SvPV(wa->desc,na))); | 
| 76 | 0 | 0 |  |  |  |  | PE_RING_DETACH(&ip->iring); | 
| 77 | 0 |  |  |  |  |  | ev = (*wa->vtbl->new_event)(wa); | 
| 78 | 0 |  |  |  |  |  | ++ev->hits; | 
| 79 | 0 |  |  |  |  |  | queueEvent(ev); | 
| 80 | 0 |  |  |  |  |  | return; | 
| 81 |  |  |  |  |  |  | } | 
| 82 |  |  |  |  |  |  | else { | 
| 83 | 0 |  |  |  |  |  | ++TimeoutTooEarly; | 
| 84 | 0 |  |  |  |  |  | ip->tm.at = now + left; | 
| 85 |  |  |  |  |  |  | D_IDLE(warn("max %.2f '%s'\n", left, SvPV(wa->desc,na))); | 
| 86 | 15 |  |  |  |  |  | pe_timeable_start(&ip->tm); | 
| 87 |  |  |  |  |  |  | } | 
| 88 |  |  |  |  |  |  | } | 
| 89 |  |  |  |  |  |  | } | 
| 90 |  |  |  |  |  |  |  | 
| 91 | 21 |  |  |  |  |  | static void pe_idle_stop(pe_watcher *ev) { | 
| 92 | 21 |  |  |  |  |  | pe_idle *ip = (pe_idle*) ev; | 
| 93 | 21 | 50 |  |  |  |  | PE_RING_DETACH(&ip->iring); | 
| 94 | 21 |  |  |  |  |  | pe_timeable_stop(&ip->tm); | 
| 95 | 21 |  |  |  |  |  | } | 
| 96 |  |  |  |  |  |  |  | 
| 97 | 1 |  |  |  |  |  | WKEYMETH(_idle_max_interval) { | 
| 98 | 1 |  |  |  |  |  | pe_idle *ip = (pe_idle*) ev; | 
| 99 | 1 | 50 |  |  |  |  | if (nval) { | 
| 100 | 0 |  |  |  |  |  | SV *old = ip->max_interval; | 
| 101 | 0 |  |  |  |  |  | ip->max_interval = SvREFCNT_inc(nval); | 
| 102 | 0 | 0 |  |  |  |  | if (old) SvREFCNT_dec(old); | 
| 103 | 0 |  |  |  |  |  | VERIFYINTERVAL("max", ip->max_interval); | 
| 104 |  |  |  |  |  |  | } | 
| 105 |  |  |  |  |  |  | { | 
| 106 | 1 |  |  |  |  |  | dSP; | 
| 107 | 1 | 50 |  |  |  |  | XPUSHs(ip->max_interval); | 
| 108 | 1 |  |  |  |  |  | PUTBACK; | 
| 109 |  |  |  |  |  |  | } | 
| 110 | 1 |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  |  | 
| 112 | 1 |  |  |  |  |  | WKEYMETH(_idle_min_interval) { | 
| 113 | 1 |  |  |  |  |  | pe_idle *ip = (pe_idle*) ev; | 
| 114 | 1 | 50 |  |  |  |  | if (nval) { | 
| 115 | 0 |  |  |  |  |  | SV *old = ip->min_interval; | 
| 116 | 0 |  |  |  |  |  | ip->min_interval = SvREFCNT_inc(nval); | 
| 117 | 0 | 0 |  |  |  |  | if (old) SvREFCNT_dec(old); | 
| 118 | 0 |  |  |  |  |  | VERIFYINTERVAL("min", ip->min_interval); | 
| 119 |  |  |  |  |  |  | } | 
| 120 |  |  |  |  |  |  | { | 
| 121 | 1 |  |  |  |  |  | dSP; | 
| 122 | 1 | 50 |  |  |  |  | XPUSHs(ip->min_interval); | 
| 123 | 1 |  |  |  |  |  | PUTBACK; | 
| 124 |  |  |  |  |  |  | } | 
| 125 | 1 |  |  |  |  |  | } | 
| 126 |  |  |  |  |  |  |  | 
| 127 | 25 |  |  |  |  |  | static void boot_idle() { | 
| 128 | 25 |  |  |  |  |  | pe_watcher_vtbl *vt = &pe_idle_vtbl; | 
| 129 | 25 |  |  |  |  |  | PE_RING_INIT(&Idle, 0); | 
| 130 | 25 |  |  |  |  |  | memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl)); | 
| 131 | 25 |  |  |  |  |  | vt->dtor = pe_idle_dtor; | 
| 132 | 25 |  |  |  |  |  | vt->start = pe_idle_start; | 
| 133 | 25 |  |  |  |  |  | vt->stop = pe_idle_stop; | 
| 134 | 25 |  |  |  |  |  | vt->alarm = pe_idle_alarm; | 
| 135 | 25 |  |  |  |  |  | pe_register_vtbl(vt, gv_stashpv("Event::idle",1), &event_vtbl); | 
| 136 | 25 |  |  |  |  |  | } |