1 static pe_timeable Timeables;
2
3 /*#define D_TIMEABLE(x) x /**/
4 #define D_TIMEABLE(x) /**/
5
db_show_timeables()6 static void db_show_timeables()
7 {
8 pe_timeable *tm = (pe_timeable*) Timeables.ring.next;
9 warn("timeables at %.2f\n", NVtime() + IntervalEpsilon);
10 while (tm->ring.self) {
11 STRLEN n_a;
12 pe_watcher *wa = (pe_watcher*) tm->ring.self;
13 pe_timeable *next = (pe_timeable*) tm->ring.next;
14 warn(" %.2f '%s'\n", tm->at, SvPV(wa->desc, n_a));
15 tm = next;
16 }
17 }
18
pe_timeables_check()19 static void pe_timeables_check() {
20 pe_timeable *tm = (pe_timeable*) Timeables.ring.next;
21 NV now = NVtime() + IntervalEpsilon;
22 /*db_show_timeables();/**/
23 while (tm->ring.self && now >= tm->at) {
24 pe_watcher *ev = (pe_watcher*) tm->ring.self;
25 pe_timeable *next = (pe_timeable*) tm->ring.next;
26 D_TIMEABLE({
27 if (WaDEBUGx(ev) >= 4) {
28 STRLEN n_a;
29 warn("Event: timeable expire '%s'\n", SvPV(ev->desc, n_a));
30 }
31 })
32 assert(!WaSUSPEND(ev));
33 assert(WaACTIVE(ev));
34 PE_RING_DETACH(&tm->ring);
35 (*ev->vtbl->alarm)(ev, tm);
36 tm = next;
37 }
38 }
39
timeTillTimer()40 static NV timeTillTimer() {
41 pe_timeable *tm = (pe_timeable*) Timeables.ring.next;
42 if (!tm->ring.self)
43 return 3600;
44 return tm->at - NVtime();
45 }
46
pe_timeable_start(pe_timeable * tm)47 static void pe_timeable_start(pe_timeable *tm) {
48 /* OPTIMIZE! */
49 pe_watcher *ev = (pe_watcher*) tm->ring.self;
50 pe_timeable *rg = (pe_timeable*) Timeables.ring.next;
51 assert(!WaSUSPEND(ev));
52 assert(PE_RING_EMPTY(&tm->ring));
53 if (WaDEBUGx(ev)) {
54 NV left = tm->at - NVtime();
55 if (left < 0) {
56 STRLEN n_a;
57 warn("Event: timer for '%s' set to expire immediately (%.2f)",
58 SvPV(ev->desc, n_a), left);
59 }
60 }
61 while (rg->ring.self && rg->at < tm->at) {
62 rg = (pe_timeable*) rg->ring.next;
63 }
64 /*warn("-- adding 0x%x:\n", ev); db_show_timeables();/**/
65 PE_RING_ADD_BEFORE(&tm->ring, &rg->ring);
66 /*warn("T:\n"); db_show_timeables();/**/
67 D_TIMEABLE({
68 if (WaDEBUGx(ev) >= 4) {
69 STRLEN n_a;
70 warn("Event: timeable start '%s'\n", SvPV(ev->desc, n_a));
71 }
72 })
73 }
74
pe_timeable_stop(pe_timeable * tm)75 static void pe_timeable_stop(pe_timeable *tm) {
76 D_TIMEABLE({
77 pe_watcher *ev = (pe_watcher*) tm->ring.self;
78 if (WaDEBUGx(ev) >= 4) {
79 STRLEN n_a;
80 warn("Event: timeable stop '%s'\n", SvPV(ev->desc, n_a));
81 }
82 })
83 PE_RING_DETACH(&tm->ring);
84 }
85
pe_timeable_adjust(NV delta)86 static void pe_timeable_adjust(NV delta) {
87 pe_timeable *rg = (pe_timeable*) Timeables.ring.next;
88 while (rg != &Timeables) {
89 rg->at += delta;
90 rg = (pe_timeable*) rg->ring.next;
91 }
92 }
93
WKEYMETH(_timeable_hard)94 WKEYMETH(_timeable_hard) { /* applies to all timers in a watcher; is ok? */
95 if (nval) {
96 if (sv_true(nval)) WaHARD_on(ev); else WaHARD_off(ev);
97 }
98 {
99 dSP;
100 XPUSHs(boolSV(WaHARD(ev)));
101 PUTBACK;
102 }
103 }
104
boot_timeable()105 static void boot_timeable() {
106 PE_RING_INIT(&Timeables.ring, 0);
107 }
108