File: idle.c

package info (click to toggle)
libevent-perl 1.11-1
  • links: PTS, VCS
  • area: main
  • in suites: lenny
  • size: 712 kB
  • ctags: 593
  • sloc: ansic: 3,034; perl: 1,128; makefile: 50
file content (136 lines) | stat: -rw-r--r-- 3,561 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
static struct pe_watcher_vtbl pe_idle_vtbl;
static pe_ring Idle;

/*#define D_IDLE(x) x  /**/
#define D_IDLE(x)  /**/

static pe_watcher *pe_idle_allocate(HV *stash, SV *temple) {
    pe_idle *ev;
    EvNew(3, ev, 1, pe_idle);
    ev->base.vtbl = &pe_idle_vtbl;
    pe_watcher_init(&ev->base, stash, temple);
    PE_RING_INIT(&ev->tm.ring, ev);
    PE_RING_INIT(&ev->iring, ev);
    ev->max_interval = &PL_sv_undef;
    ev->min_interval = newSVnv(.01);
    return (pe_watcher*) ev;
}

static void pe_idle_dtor(pe_watcher *ev) {
    pe_idle *ip = (pe_idle*) ev;
    SvREFCNT_dec(ip->max_interval);
    SvREFCNT_dec(ip->min_interval);
    pe_watcher_dtor(ev);
    EvFree(3, ev);
}

static char *pe_idle_start(pe_watcher *ev, int repeating) {
    NV now;
    NV min,max;
    pe_idle *ip = (pe_idle*) ev;
    if (!ev->callback)
	return "without callback";
    if (!repeating) ev->cbtime = NVtime();
    now = WaHARD(ev)? ev->cbtime : NVtime();
    if (sv_2interval("min", ip->min_interval, &min)) {
	ip->tm.at = min + now;
	pe_timeable_start(&ip->tm);
	D_IDLE(warn("min %.2f setup '%s'\n", min, SvPV(ev->desc,na)));
    }
    else {
	PE_RING_UNSHIFT(&ip->iring, &Idle);
	D_IDLE(warn("idle '%s'\n", SvPV(ev->desc,na)));
	if (sv_2interval("max", ip->max_interval, &max)) {
	    D_IDLE(warn("max %.2f setup '%s'\n", max, SvPV(ev->desc,na)));
	    ip->tm.at = max + now;
	    pe_timeable_start(&ip->tm);
	}
    }
    return 0;
}

static void pe_idle_alarm(pe_watcher *wa, pe_timeable *_ignore) {
    NV now = NVtime();
    NV min,max,left;
    pe_idle *ip = (pe_idle*) wa;
    pe_timeable_stop(&ip->tm);
    if (sv_2interval("min", ip->min_interval, &min)) {
	left = wa->cbtime + min - now;
	if (left > IntervalEpsilon) {
	    ++TimeoutTooEarly;
	    ip->tm.at = now + left;
	    pe_timeable_start(&ip->tm);
	    D_IDLE(warn("min %.2f '%s'\n", left, SvPV(wa->desc,na)));
	    return;
	}
    }
    if (PE_RING_EMPTY(&ip->iring)) {
	PE_RING_UNSHIFT(&ip->iring, &Idle);
	D_IDLE(warn("idle '%s'\n", SvPV(wa->desc,na)));
    }
    if (sv_2interval("max", ip->max_interval, &max)) {
	left = wa->cbtime + max - now;
	if (left < IntervalEpsilon) {
	    pe_event *ev;
	    D_IDLE(warn("max '%s'\n", SvPV(wa->desc,na)));
	    PE_RING_DETACH(&ip->iring);
	    ev = (*wa->vtbl->new_event)(wa);
	    ++ev->hits;
	    queueEvent(ev);
	    return;
	}
	else {
	    ++TimeoutTooEarly;
	    ip->tm.at = now + left;
	    D_IDLE(warn("max %.2f '%s'\n", left, SvPV(wa->desc,na)));
	    pe_timeable_start(&ip->tm);
	}
    }
}

static void pe_idle_stop(pe_watcher *ev) {
    pe_idle *ip = (pe_idle*) ev;
    PE_RING_DETACH(&ip->iring);
    pe_timeable_stop(&ip->tm);
}

WKEYMETH(_idle_max_interval) {
    pe_idle *ip = (pe_idle*) ev;
    if (nval) {
	SV *old = ip->max_interval;
	ip->max_interval = SvREFCNT_inc(nval);
	if (old) SvREFCNT_dec(old);
	VERIFYINTERVAL("max", ip->max_interval);
    }
    {
	dSP;
	XPUSHs(ip->max_interval);
	PUTBACK;
    }
}

WKEYMETH(_idle_min_interval) {
    pe_idle *ip = (pe_idle*) ev;
    if (nval) {
	SV *old = ip->min_interval;
	ip->min_interval = SvREFCNT_inc(nval);
	if (old) SvREFCNT_dec(old);
	VERIFYINTERVAL("min", ip->min_interval);
    }
    {
	dSP;
	XPUSHs(ip->min_interval);
	PUTBACK;
    }
}

static void boot_idle() {
    pe_watcher_vtbl *vt = &pe_idle_vtbl;
    PE_RING_INIT(&Idle, 0);
    memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl));
    vt->dtor = pe_idle_dtor;
    vt->start = pe_idle_start;
    vt->stop = pe_idle_stop;
    vt->alarm = pe_idle_alarm;
    pe_register_vtbl(vt, gv_stashpv("Event::idle",1), &event_vtbl);
}