File Coverage

probe.xs
Criterion Covered Total %
statement 127 142 89.4
branch 61 140 43.5
condition n/a
subroutine n/a
pod n/a
total 188 282 66.6


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT /* we want efficiency */
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5             #include "ppport.h"
6              
7             static Perl_ppaddr_t probe_nextstate_orig = 0;
8             static int probe_installed = 0;
9             static int probe_enabled = 0;
10             static HV* probe_hash = 0;
11             static SV* probe_trigger_cb = 0;
12              
13             static int probe_is_enabled(void);
14             static void probe_enable(void);
15             static void probe_disable(void);
16             static int probe_is_installed(void);
17             static void probe_install(void);
18             static void probe_remove(void);
19              
20             #define DEBUG 0
21              
22             #define INFO(x) do { if (DEBUG > 0) dbg_printf x; } while (0)
23             #define TRACE(x) do { if (DEBUG > 1) dbg_printf x; } while (0)
24              
25 0           void dbg_printf(const char *fmt, ...)
26             {
27             va_list args;
28 0           va_start(args, fmt);
29 0           vfprintf(stderr, fmt, args);
30 0           va_end(args);
31 0           }
32              
33 2           static inline void probe_invoke_callback(const char* file, int line, SV* callback)
34             {
35             int count;
36              
37 2           dSP;
38              
39 2           ENTER;
40 2           SAVETMPS;
41              
42 2 50         PUSHMARK (SP);
43 2 50         EXTEND(SP, 2);
44 2 50         XPUSHs(sv_2mortal(newSVpv(file, 0)));
45 2 50         XPUSHs(sv_2mortal(newSViv(line)));
46 2           PUTBACK;
47              
48 2           count = call_sv(callback, G_VOID|G_DISCARD);
49 2 50         if (count != 0) {
50 0           croak("probe trigger should have zero return values");
51             }
52              
53 2 50         FREETMPS;
54 2           LEAVE;
55 2           }
56              
57 63           static int probe_lookup(const char* file, int line, int create)
58             {
59 63           U32 klen = strlen(file);
60 63           SV** rlines = hv_fetch(probe_hash, file, klen, 0);
61 63           HV* lines = 0;
62             char kstr[20];
63              
64 63 100         if (rlines) {
65 19           lines = (HV*) SvRV(*rlines);
66             TRACE(("PROBE found entry for file [%s]: %p\n", file, lines));
67 44 100         } else if (!create) {
68 43           return 0;
69             } else {
70 1           SV* slines = 0;
71 1           lines = newHV();
72 1           slines = (SV*) newRV((SV*) lines);
73 1           hv_store(probe_hash, file, klen, slines, 0);
74             TRACE(("PROBE created entry for file [%s]: %p\n", file, lines));
75             }
76              
77 20           klen = sprintf(kstr, "%d", line);
78 20 100         if (!create) {
79 18           SV** rflag = hv_fetch(lines, kstr, klen, 0);
80 18 100         return rflag && SvTRUE(*rflag);
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
81             } else {
82 2           SV* flag = &PL_sv_yes;
83 2           hv_store(lines, kstr, klen, flag, 0);
84             TRACE(("PROBE created entry for line [%s]\n", kstr));
85             }
86              
87 63           return 1;
88             }
89              
90 2454           static OP* probe_nextstate(pTHX)
91             {
92 2454           OP* ret = probe_nextstate_orig(aTHX);
93              
94             do {
95 2454           const char* file = 0;
96 2454           int line = 0;
97              
98 2454 100         if (!probe_is_enabled()) {
99 2393           break;
100             }
101              
102 61 50         file = CopFILE(PL_curcop);
103 61           line = CopLINE(PL_curcop);
104             // it isn't always obvious what file path is being used (e.g., what you should put in the cfg file)
105             TRACE(("PROBE check [%s] [%d]\n", file, line));
106 61 100         if (!probe_lookup(file, line, 0)) {
107 59           break;
108             }
109              
110             INFO(("PROBE triggered [%s] [%d]\n", file, line));
111 2 50         if (!probe_trigger_cb) {
112 0           break;
113             }
114              
115 2           probe_invoke_callback(file, line, probe_trigger_cb);
116             } while (0);
117              
118 2454           return ret;
119             }
120              
121 1           static void probe_dump(void)
122             {
123 1           hv_iterinit(probe_hash);
124             while (1) {
125 2           SV* key = 0;
126 2           SV* value = 0;
127 2           char* kstr = 0;
128 2           STRLEN klen = 0;
129 2           HV* lines = 0;
130 2           HE* entry = hv_iternext(probe_hash);
131 2 100         if (!entry) {
132 1           break; /* no more hash keys */
133             }
134 1           key = hv_iterkeysv(entry);
135 1 50         if (!key) {
136 0           continue; /* invalid key */
137             }
138 1 50         kstr = SvPV(key, klen);
139 1 50         if (!kstr) {
140 0           continue; /* invalid key */
141             }
142 1           fprintf(stderr, "PROBE dump file [%s]\n", kstr);
143              
144 1           value = hv_iterval(probe_hash, entry);
145 1 50         if (!value) {
146 0           continue; /* invalid value */
147             }
148 1           lines = (HV*) SvRV(value);
149 1           hv_iterinit(lines);
150             while (1) {
151 3           SV* key = 0;
152 3           SV* value = 0;
153 3           char* kstr = 0;
154 3           STRLEN klen = 0;
155 3           HE* entry = hv_iternext(lines);
156 3 100         if (!entry) {
157 1           break; /* no more hash keys */
158             }
159 2           key = hv_iterkeysv(entry);
160 2 50         if (!key) {
161 0           continue; /* invalid key */
162             }
163 2 50         kstr = SvPV(key, klen);
164 2 50         if (!kstr) {
165 0           continue; /* invalid key */
166             }
167 2           value = hv_iterval(lines, entry);
168 2 50         if (!value || !SvTRUE(value)) {
    50          
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
169 0           continue;
170             }
171 2           fprintf(stderr, "PROBE dump line [%s]\n", kstr);
172 2           }
173 1           }
174 1           }
175              
176 2468           static int probe_is_enabled(void)
177             {
178 2468           return probe_enabled;
179             }
180              
181 3           static void probe_enable(void)
182             {
183 3 100         if (probe_is_enabled()) {
184 1           return;
185             }
186             INFO(("PROBE enabling\n"));
187 2           probe_enabled = 1;
188             }
189              
190 12           static void probe_reset(int installed)
191             {
192 12           probe_installed = installed;
193 12           probe_enabled = 0;
194 12           probe_hash = 0;
195 12           probe_trigger_cb = 0;
196 12           }
197              
198 11           static void probe_clear(void)
199             {
200 11           probe_hash = newHV();
201             INFO(("PROBE cleared\n"));
202 11           }
203              
204 6           static void probe_disable(void)
205             {
206 6 50         if (!probe_is_enabled()) {
207 6           return;
208             }
209 0           probe_enabled = 0;
210             INFO(("PROBE disabled\n"));
211             }
212              
213 33           static int probe_is_installed(void)
214             {
215 33           return probe_installed;
216             }
217              
218 15           static void probe_install(void)
219             {
220 15 100         if (probe_is_installed()) {
221 5           return;
222             }
223              
224             INFO(("PROBE installed, [%p] => [%p]\n", PL_ppaddr[OP_NEXTSTATE], probe_nextstate));
225              
226 10 100         if (!probe_nextstate_orig) {
227 8           probe_nextstate_orig = PL_ppaddr[OP_NEXTSTATE];
228             }
229 10           PL_ppaddr[OP_NEXTSTATE] = probe_nextstate;
230 10           probe_reset(1);
231 10           probe_clear();
232             }
233              
234 4           static void probe_remove(void)
235             {
236 4 100         if (!probe_is_installed()) {
237 2           return;
238             }
239             INFO(("PROBE removed, [%p] => [%p]\n", PL_ppaddr[OP_NEXTSTATE], probe_nextstate_orig));
240 2 50         if (probe_nextstate_orig) {
241 2           PL_ppaddr[OP_NEXTSTATE] = probe_nextstate_orig;
242             }
243 2           probe_reset(0);
244             }
245              
246             MODULE = Devel::Probe PACKAGE = Devel::Probe
247             PROTOTYPES: DISABLE
248              
249             #################################################################
250              
251             void
252             install()
253             CODE:
254 15           probe_install();
255              
256             void
257             remove()
258             CODE:
259 4           probe_remove();
260              
261             int
262             is_installed()
263             CODE:
264 14           RETVAL = probe_is_installed();
265             OUTPUT: RETVAL
266              
267             void
268             enable()
269             CODE:
270 3           probe_enable();
271              
272             void
273             disable()
274             CODE:
275 6           probe_disable();
276              
277             int
278             is_enabled()
279             CODE:
280 5           RETVAL = probe_is_enabled();
281             OUTPUT: RETVAL
282              
283             void
284             clear()
285             CODE:
286 1           probe_clear();
287              
288             void
289             dump()
290             CODE:
291 1           probe_dump();
292              
293             void
294             add_probe(const char* file, int line)
295             CODE:
296 2           probe_lookup(file, line, 1);
297              
298             void
299             trigger(SV* callback)
300             CODE:
301 1 50         if (probe_trigger_cb == (SV*)NULL) {
302 1           probe_trigger_cb = newSVsv(callback);
303             } else {
304 0 0         SvSetSV(probe_trigger_cb, callback);
305             }