| 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 |  |  |  |  |  | } |