File Coverage

c/var.c
Criterion Covered Total %
statement 105 115 91.3
branch 40 66 60.6
condition n/a
subroutine n/a
pod n/a
total 145 181 80.1


line stmt bran cond sub pod time code
1             static struct pe_watcher_vtbl pe_var_vtbl;
2              
3 10           static pe_watcher *pe_var_allocate(HV *stash, SV *temple) {
4             pe_var *ev;
5 10           EvNew(10, ev, 1, pe_var);
6 10           ev->base.vtbl = &pe_var_vtbl;
7 10           pe_watcher_init(&ev->base, stash, temple);
8 10           ev->variable = &PL_sv_undef;
9 10           ev->events = PE_W;
10 10           WaREPEAT_on(ev);
11 10           WaINVOKE1_off(ev);
12 10           return (pe_watcher*) ev;
13             }
14              
15 10           static void pe_var_dtor(pe_watcher *ev) {
16 10           pe_var *wv = (pe_var *)ev;
17 10           SvREFCNT_dec(wv->variable);
18 10           pe_watcher_dtor(ev);
19 10           EvFree(10, ev);
20 10           }
21              
22 5           static void pe_tracevar(pe_watcher *wa, SV *sv, int got) {
23             /* Adapted from tkGlue.c
24              
25             We are a "magic" set processor.
26             So we are (I think) supposed to look at "private" flags
27             and set the public ones if appropriate.
28             e.g. "chop" sets SvPOKp as a hint but not SvPOK
29              
30             presumably other operators set other private bits.
31              
32             Question are successive "magics" called in correct order?
33              
34             i.e. if we are tracing a tied variable should we call
35             some magic list or be careful how we insert ourselves in the list?
36             */
37              
38             pe_ioevent *ev;
39              
40 5 50         if (SvPOKp(sv)) SvPOK_on(sv);
41 5 50         if (SvNOKp(sv)) SvNOK_on(sv);
42 5 50         if (SvIOKp(sv)) SvIOK_on(sv);
43              
44 5           ev = (pe_ioevent*) (*wa->vtbl->new_event)(wa);
45 5           ++ev->base.hits;
46 5           ev->got |= got;
47 5           queueEvent((pe_event*) ev);
48 5           }
49              
50 1           static I32 tracevar_r(pTHX_ IV ix, SV *sv)
51 1           { pe_tracevar(INT2PTR(pe_watcher *, ix), sv, PE_R); return 0; /*ignored*/ }
52 4           static I32 tracevar_w(pTHX_ IV ix, SV *sv)
53 4           { pe_tracevar(INT2PTR(pe_watcher *, ix), sv, PE_W); return 0; /*ignored*/ }
54              
55 8           static char *pe_var_start(pe_watcher *_ev, int repeat) {
56             STRLEN n_a;
57             struct ufuncs *ufp;
58             MAGIC **mgp;
59             MAGIC *mg;
60 8           pe_var *ev = (pe_var*) _ev;
61 8           SV *sv = ev->variable;
62              
63 8 50         if (!_ev->callback)
64 0           return "without callback";
65 8 50         if (!sv || !SvOK(sv))
    100          
    50          
    50          
66 1           return "watching what?";
67 7 100         if (!ev->events)
68 1           return "without poll events specified";
69 6           sv = SvRV(sv);
70 6 100         if (SvREADONLY(sv))
71 1           return "cannot trace read-only variable";
72 5 100         (void)SvUPGRADE(sv, SVt_PVMG);
73              
74 5           mgp = &SvMAGIC(sv);
75 6 100         while ((mg = *mgp)) {
76 1           mgp = &mg->mg_moremagic;
77             }
78              
79 5           EvNew(11, mg, 1, MAGIC);
80 5           Zero(mg, 1, MAGIC);
81 5           mg->mg_type = 'U';
82 5           mg->mg_virtual = &PL_vtbl_uvar;
83 5           *mgp = mg;
84            
85 5           EvNew(8, ufp, 1, struct ufuncs);
86 5 100         ufp->uf_val = ev->events & PE_R? tracevar_r : 0;
87 5 100         ufp->uf_set = ev->events & PE_W? tracevar_w : 0;
88 5           ufp->uf_index = PTR2IV(ev);
89 5           mg->mg_ptr = (char *) ufp;
90 5           mg->mg_obj = (SV*) ev;
91              
92 5           mg_magical(sv);
93 5 50         if (!SvMAGICAL(sv))
94 0           return "mg_magical didn't";
95 5           return 0;
96             }
97              
98 5           static void pe_var_stop(pe_watcher *_ev) {
99             MAGIC **mgp;
100             MAGIC *mg;
101 5           pe_var *ev = (pe_var*) _ev;
102 5           SV *sv = SvRV(ev->variable);
103              
104 5 50         if (SvTYPE(sv) < SVt_PVMG || !SvMAGIC(sv)) {
    50          
105 0           warn("Var unmagic'd already?");
106 0           return;
107             }
108              
109 5           mgp = &SvMAGIC(sv);
110 6 50         while ((mg = *mgp)) {
111 6 50         if (mg->mg_type == 'U' && mg->mg_obj == (SV*)ev)
    100          
112 5           break;
113 1           mgp = &mg->mg_moremagic;
114             }
115              
116 5 50         if(!mg) {
117 0           warn("Couldn't find var magic");
118 0           return;
119             }
120              
121 5           *mgp = mg->mg_moremagic;
122              
123 5           EvFree(8, mg->mg_ptr);
124 5           EvFree(11, mg);
125             }
126              
127 2           static void _var_restart(pe_watcher *ev) {
128 2 50         if (!WaPOLLING(ev)) return;
129 0           pe_watcher_off(ev);
130 0           pe_watcher_on(ev, 0);
131             }
132              
133 2           WKEYMETH(_var_events) {
134 2           pe_var *vp = (pe_var*)ev;
135 2 50         if (nval) {
136 2           vp->events = sv_2events_mask(nval, PE_R|PE_W);
137 2           _var_restart(ev);
138             }
139             {
140 2           dSP;
141 2 50         XPUSHs(sv_2mortal(events_mask_2sv(vp->events)));
142 2           PUTBACK;
143             }
144 2           }
145              
146 8           WKEYMETH(_var_variable) {
147 8           pe_var *vp = (pe_var*)ev;
148 8 100         if (nval) {
149 7           SV *old = vp->variable;
150 7           int active = WaPOLLING(ev);
151 7 50         if (SvOK(nval)) {
    0          
    0          
152 7 50         if (!SvROK(nval))
153 0           croak("Expecting a reference");
154 7 50         if (SvTYPE(SvRV(nval)) > SVt_PVMG)
155 0           croak("Var watchers can only watch plain vanilla scalars");
156             }
157 7 50         if (active) pe_watcher_off(ev);
158 7           vp->variable = SvREFCNT_inc(nval);
159 7 50         if (active) pe_watcher_on(ev, 0);
160 7           SvREFCNT_dec(old);
161             }
162             {
163 8           dSP;
164 8 50         XPUSHs(vp->variable);
165 8           PUTBACK;
166             }
167 8           }
168              
169 24           static void boot_var() {
170 24           pe_watcher_vtbl *vt = &pe_var_vtbl;
171 24           memcpy(vt, &pe_watcher_base_vtbl, sizeof(pe_watcher_base_vtbl));
172 24           vt->dtor = pe_var_dtor;
173 24           vt->start = pe_var_start;
174 24           vt->stop = pe_var_stop;
175 24           pe_register_vtbl(vt, gv_stashpv("Event::var",1), &ioevent_vtbl);
176 24           }