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