File Coverage

c/group.c
Criterion Covered Total %
statement 76 110 69.0
branch 24 52 46.1
condition n/a
subroutine n/a
pod n/a
total 100 162 61.7


line stmt bran cond sub pod time code
1             static struct pe_watcher_vtbl pe_group_vtbl;
2              
3 1           static pe_watcher *pe_group_allocate(HV *stash, SV *temple) {
4             pe_group *ev;
5 1           EvNew(12, ev, 1, pe_group);
6 1           ev->base.vtbl = &pe_group_vtbl;
7 1           PE_RING_INIT(&ev->tm.ring, ev);
8 1           ev->tm.at = 0;
9 1           ev->timeout = &PL_sv_undef;
10 1           ev->members = 3;
11 1 50         EvNew(13, ev->member, ev->members, pe_watcher*);
12 1 50         Zero(ev->member, ev->members, pe_watcher*);
13 1           pe_watcher_init(&ev->base, stash, temple);
14 1           WaREPEAT_on(ev);
15 1           return (pe_watcher*) ev;
16             }
17              
18 1           static void pe_group_dtor(pe_watcher *ev) {
19             int xx;
20 1           pe_group *gp = (pe_group*) ev;
21 1           SvREFCNT_dec(gp->timeout);
22 13 100         for (xx=0; xx < gp->members; xx++) {
23 12           pe_watcher *mb = gp->member[xx];
24 12 100         if (mb)
25 10           --mb->refcnt;
26             }
27 1           EvFree(13, gp->member);
28 1           pe_watcher_dtor(ev);
29 1           EvFree(12, ev);
30 1           }
31              
32 1           static char *pe_group_start(pe_watcher *ev, int repeat) {
33 1           pe_group *gp = (pe_group*) ev;
34             NV timeout;
35              
36 1 50         if (!ev->callback)
37 0           return "without callback";
38 1 50         if (!sv_2interval("group", gp->timeout, &timeout))
39 0           return "repeating group has no timeout";
40              
41 1 50         gp->since = WaHARD(ev)? gp->tm.at : NVtime();
42 1           gp->tm.at = timeout + gp->since;
43 1           pe_timeable_start(&gp->tm);
44 1           return 0;
45             }
46              
47 1           static void pe_group_stop(pe_watcher *ev)
48 1           { pe_timeable_stop(&((pe_group*)ev)->tm); }
49              
50 0           static void pe_group_alarm(pe_watcher *wa, pe_timeable *tm) {
51             STRLEN n_a;
52 0           pe_group *gp = (pe_group*) wa;
53             NV timeout;
54             NV remaining;
55 0           NV now = NVtime();
56             int xx;
57 0 0         for (xx=0; xx < gp->members; xx++) {
58 0           pe_watcher *mb = gp->member[xx];
59 0 0         if (!mb) continue;
60 0 0         if (gp->since < mb->cbtime) {
61 0           gp->since = mb->cbtime;
62             }
63             }
64              
65 0 0         if (!sv_2interval("group", gp->timeout, &timeout))
66 0           croak("Event: can't extract timeout"); /* impossible */
67              
68 0           remaining = gp->since + timeout - now;
69 0 0         if (remaining > IntervalEpsilon) {
70 0           gp->tm.at = now + remaining;
71 0           pe_timeable_start(&gp->tm);
72             } else {
73 0           pe_event *ev = (*wa->vtbl->new_event)(wa);
74 0           ++ev->hits;
75 0           queueEvent(ev);
76             }
77 0           }
78              
79             /* publish C API XXX */
80 11           static void pe_group_add(pe_group *gp, pe_watcher *wa) {
81 11           int ok=0;
82             int xx;
83 11 100         if (gp == (pe_group*) wa) {
84             STRLEN n_a;
85 1 50         croak("Event: can't add group '%s' to itself",
86 2           SvPV(gp->base.desc, n_a));
87             }
88 10           ++wa->refcnt;
89 55 100         for (xx=0; xx < gp->members; xx++) {
90 53 100         if (!gp->member[xx]) {
91 8           gp->member[xx] = wa;
92 8           ok=1; break;
93             }
94             }
95 10 100         if (!ok) { /* expand array */
96             pe_watcher **ary;
97 2 50         EvNew(13, ary, gp->members*2, pe_watcher*);
98 2 50         Zero(ary, gp->members*2, pe_watcher*);
99 2 50         Copy(gp->member, ary, gp->members, sizeof(pe_watcher*));
100 2           EvFree(13, gp->member);
101 2           gp->member = ary;
102 2           gp->member[gp->members] = wa;
103 2           gp->members *= 2;
104             }
105 10           }
106              
107 0           static void pe_group_del(pe_group *gp, pe_watcher *target) {
108             int xx;
109 0 0         for (xx=0; xx < gp->members; xx++) {
110 0 0         if (gp->member[xx] != target)
111 0           continue;
112 0           --target->refcnt;
113 0           gp->member[xx] = 0;
114 0           break;
115             }
116 0           }
117              
118 1           WKEYMETH(_group_timeout) {
119 1           pe_group *gp = (pe_group*)ev;
120 1 50         if (nval) {
121 1           SV *old = gp->timeout;
122 1           gp->timeout = SvREFCNT_inc(nval);
123 1           SvREFCNT_dec(old);
124 1           VERIFYINTERVAL("group", gp->timeout);
125             /* recalc expiration XXX */
126             }
127             {
128 1           dSP;
129 1 50         XPUSHs(gp->timeout);
130 1           PUTBACK;
131             }
132 1           }
133              
134 13           WKEYMETH(_group_add) {
135 13           pe_group *gp = (pe_group*)ev;
136 13 50         if (!nval)
137 0           return;
138 13           pe_group_add(gp, sv_2watcher(nval));
139             }
140              
141 0           WKEYMETH(_group_del) {
142 0           pe_group *gp = (pe_group*)ev;
143 0 0         if (!nval)
144 0           return;
145 0           pe_group_del(gp, sv_2watcher(nval));
146             }
147              
148 24           static void boot_group() {
149 24           pe_watcher_vtbl *vt = &pe_group_vtbl;
150 24           memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl));
151 24           vt->dtor = pe_group_dtor;
152 24           vt->start = pe_group_start;
153 24           vt->stop = pe_group_stop;
154 24           vt->alarm = pe_group_alarm;
155 24           pe_register_vtbl(vt, gv_stashpv("Event::group",1), &event_vtbl);
156 24           }