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