… | |
… | |
33 | use AnyEvent::Socket (); |
33 | use AnyEvent::Socket (); |
34 | |
34 | |
35 | =item $shell = AnyEvent;::Debug::shell $host, $service |
35 | =item $shell = AnyEvent;::Debug::shell $host, $service |
36 | |
36 | |
37 | This function binds on the given host and service port and returns a |
37 | This function binds on the given host and service port and returns a |
38 | shell object, whcih determines the lifetime of the shell. Any number |
38 | shell object, which determines the lifetime of the shell. Any number |
39 | of conenctions are accepted on the port, and they will give you a very |
39 | of conenctions are accepted on the port, and they will give you a very |
40 | primitive shell that simply executes every line you enter. |
40 | primitive shell that simply executes every line you enter. |
41 | |
41 | |
42 | All commands will be executed "blockingly" with the socket C<select>ed for |
42 | All commands will be executed "blockingly" with the socket C<select>ed for |
43 | output. For a less "blocking" interface see L<Coro::Debug>. |
43 | output. For a less "blocking" interface see L<Coro::Debug>. |
… | |
… | |
51 | internal variables inside C<my> variables, so users couldn't accidentally |
51 | internal variables inside C<my> variables, so users couldn't accidentally |
52 | access them. Having interactive access to your programs changed that: |
52 | access them. Having interactive access to your programs changed that: |
53 | having internal variables still in the global scope means you can debug |
53 | having internal variables still in the global scope means you can debug |
54 | them easier. |
54 | them easier. |
55 | |
55 | |
56 | As no authenticsation is done, in most cases it is best not to use a TCP |
56 | As no authentication is done, in most cases it is best not to use a TCP |
57 | port, but a unix domain socket, whcih cna be put wherever youc an access |
57 | port, but a unix domain socket, whcih can be put wherever you can access |
58 | it, but not others: |
58 | it, but not others: |
59 | |
59 | |
60 | our $SHELL = AnyEvent::Debug::shell "unix/", "/home/schmorp/shell"; |
60 | our $SHELL = AnyEvent::Debug::shell "unix/", "/home/schmorp/shell"; |
61 | |
61 | |
62 | Then you can use a tool to connect to the shell, such as the ever |
62 | Then you can use a tool to connect to the shell, such as the ever |
… | |
… | |
127 | } |
127 | } |
128 | }; |
128 | }; |
129 | } |
129 | } |
130 | } |
130 | } |
131 | |
131 | |
|
|
132 | =item AnyEvent::Debug::wrap [$level] |
|
|
133 | |
|
|
134 | Sets the instrumenting/wrapping level of all watchers that are being |
|
|
135 | created after this call. If no C<$level> has been specified, then it |
|
|
136 | toggles between C<0> and C<1>. |
|
|
137 | |
|
|
138 | A level of C<0> disables wrapping, i.e. AnyEvent works normally, and in |
|
|
139 | its most efficient mode. |
|
|
140 | |
|
|
141 | A level of C<1> enables wrapping, which replaces all watchers by |
|
|
142 | AnyEvent::Debug::Wrapped objects, stores the location where a watcher was |
|
|
143 | created and wraps the callback so invocations of it can be traced. |
|
|
144 | |
|
|
145 | A level of C<2> does everything that level C<1> does, but also stores a |
|
|
146 | full backtrace of the location the watcher was created. |
|
|
147 | |
|
|
148 | Instrumenting can increase the size of each watcher multiple times, and, |
|
|
149 | especially when backtraces are involved, also slows down watcher creation |
|
|
150 | a lot. |
|
|
151 | |
|
|
152 | Also, enabling and disabling instrumentation will not recover the full |
|
|
153 | performance that you had before wrapping (the AE::xxx functions will stay |
|
|
154 | slower, for example). |
|
|
155 | |
|
|
156 | Currently, enabling wrapping will also load AnyEvent::Strict, but this is |
|
|
157 | not be relied upon. |
|
|
158 | |
|
|
159 | =cut |
|
|
160 | |
|
|
161 | our $WRAP_LEVEL; |
|
|
162 | our $TRACE_LEVEL = 2; |
|
|
163 | our $TRACE_NEST = 0; |
|
|
164 | our $TRACE_CUR; |
|
|
165 | our $POST_DETECT; |
|
|
166 | |
|
|
167 | sub wrap(;$) { |
|
|
168 | my $PREV_LEVEL = $WRAP_LEVEL; |
|
|
169 | $WRAP_LEVEL = @_ ? 0+shift : $WRAP_LEVEL ? 0 : 1; |
|
|
170 | |
|
|
171 | if (defined $AnyEvent::MODEL) { |
|
|
172 | unless (defined $PREV_LEVEL) { |
|
|
173 | AnyEvent::Debug::Wrapped::_init (); |
|
|
174 | } |
|
|
175 | |
|
|
176 | if ($WRAP_LEVEL && !$PREV_LEVEL) { |
|
|
177 | require AnyEvent::Strict; |
|
|
178 | @AnyEvent::Debug::Wrap::ISA = @AnyEvent::ISA; |
|
|
179 | @AnyEvent::ISA = "AnyEvent::Debug::Wrap"; |
|
|
180 | AE::_reset; |
|
|
181 | AnyEvent::Debug::Wrap::_reset (); |
|
|
182 | } elsif (!$WRAP_LEVEL && $PREV_LEVEL) { |
|
|
183 | @AnyEvent::ISA = @AnyEvent::Debug::Wrap::ISA; |
|
|
184 | } |
|
|
185 | } else { |
|
|
186 | $POST_DETECT ||= AnyEvent::post_detect { |
|
|
187 | undef $POST_DETECT; |
|
|
188 | return unless $WRAP_LEVEL; |
|
|
189 | |
|
|
190 | (my $level, $WRAP_LEVEL) = ($WRAP_LEVEL, undef); |
|
|
191 | |
|
|
192 | require AnyEvent::Strict; |
|
|
193 | |
|
|
194 | AnyEvent::post_detect { # make sure we run after AnyEvent::Strict |
|
|
195 | wrap ($level); |
|
|
196 | }; |
|
|
197 | }; |
|
|
198 | } |
|
|
199 | } |
|
|
200 | |
|
|
201 | =item AnyEvent::Debug::path2mod $path |
|
|
202 | |
|
|
203 | Tries to replace a path (e.g. the file name returned by caller) |
|
|
204 | by a module name. Returns the path unchanged if it fails. |
|
|
205 | |
|
|
206 | Example: |
|
|
207 | |
|
|
208 | print AnyEvent::Debug::path2mod "/usr/lib/perl5/AnyEvent/Debug.pm"; |
|
|
209 | # might print "AnyEvent::Debug" |
|
|
210 | |
|
|
211 | =cut |
|
|
212 | |
|
|
213 | sub path2mod($) { |
|
|
214 | keys %INC; # reset iterator |
|
|
215 | |
|
|
216 | while (my ($k, $v) = each %INC) { |
|
|
217 | if ($_[0] eq $v) { |
|
|
218 | $k =~ s%/%::%g if $k =~ s/\.pm$//; |
|
|
219 | return $k; |
|
|
220 | } |
|
|
221 | } |
|
|
222 | |
|
|
223 | my $path = shift; |
|
|
224 | |
|
|
225 | $path =~ s%^\./%%; |
|
|
226 | |
|
|
227 | $path |
|
|
228 | } |
|
|
229 | |
|
|
230 | =item AnyEvent::Debug::cb2str $cb |
|
|
231 | |
|
|
232 | Using various gambits, tries to convert a callback (e.g. a code reference) |
|
|
233 | into a more useful string. |
|
|
234 | |
|
|
235 | Very useful if you debug a program and have some callback, but you want to |
|
|
236 | know where in the program the callbakc is actually defined. |
|
|
237 | |
|
|
238 | =cut |
|
|
239 | |
|
|
240 | sub cb2str($) { |
|
|
241 | my $cb = shift; |
|
|
242 | |
|
|
243 | require B; |
|
|
244 | |
|
|
245 | "CODE" eq ref $cb |
|
|
246 | or return "$cb"; |
|
|
247 | |
|
|
248 | my $cv = B::svref_2object ($cb); |
|
|
249 | |
|
|
250 | my $gv = $cv->GV |
|
|
251 | or return "$cb"; |
|
|
252 | |
|
|
253 | return (AnyEvent::Debug::path2mod $gv->FILE) . ":" . $gv->LINE |
|
|
254 | if $gv->NAME eq "__ANON__"; |
|
|
255 | |
|
|
256 | return $gv->STASH->NAME . "::" . $gv->NAME; |
|
|
257 | } |
|
|
258 | |
|
|
259 | package AnyEvent::Debug::Wrap; |
|
|
260 | |
|
|
261 | use AnyEvent (); BEGIN { AnyEvent::common_sense } |
|
|
262 | use Scalar::Util (); |
|
|
263 | use Carp (); |
|
|
264 | |
|
|
265 | sub _reset { |
|
|
266 | for my $name (qw(io timer signal child idle)) { |
|
|
267 | my $super = "SUPER::$name"; |
|
|
268 | |
|
|
269 | *$name = sub { |
|
|
270 | my ($self, %arg) = @_; |
|
|
271 | |
|
|
272 | my $w; |
|
|
273 | |
|
|
274 | my ($pkg, $file, $line, $sub); |
|
|
275 | |
|
|
276 | $w = 0; |
|
|
277 | do { |
|
|
278 | ($pkg, $file, $line) = caller $w++; |
|
|
279 | } while $pkg =~ /^(?:AE|AnyEvent::Socket|AnyEvent::Util|AnyEvent::Debug|AnyEvent::Strict)$/; |
|
|
280 | |
|
|
281 | $sub = (caller $w++)[3]; |
|
|
282 | |
|
|
283 | my $cb = $arg{cb}; |
|
|
284 | $arg{cb} = sub { |
|
|
285 | return &$cb |
|
|
286 | unless $TRACE_LEVEL; |
|
|
287 | |
|
|
288 | local $TRACE_NEST = $TRACE_NEST + 1; |
|
|
289 | local $TRACE_CUR = "$w"; |
|
|
290 | print "$TRACE_NEST enter $TRACE_CUR\n" if $TRACE_LEVEL; |
|
|
291 | eval { |
|
|
292 | local $SIG{__DIE__}; |
|
|
293 | &$cb; |
|
|
294 | }; |
|
|
295 | if ($@) { |
|
|
296 | print "$TRACE_NEST ERROR $TRACE_CUR $@"; |
|
|
297 | } |
|
|
298 | print "$TRACE_NEST leave $TRACE_CUR\n" if $TRACE_LEVEL; |
|
|
299 | }; |
|
|
300 | |
|
|
301 | $self = bless { |
|
|
302 | type => $name, |
|
|
303 | w => $self->$super (%arg), |
|
|
304 | file => $file, |
|
|
305 | line => $line, |
|
|
306 | sub => $sub, |
|
|
307 | cur => $TRACE_CUR, |
|
|
308 | cb => $cb, |
|
|
309 | }, "AnyEvent::Debug::Wrapped"; |
|
|
310 | |
|
|
311 | $w->{bt} = Carp::longmess "" |
|
|
312 | if $WRAP_LEVEL >= 2; |
|
|
313 | |
|
|
314 | Scalar::Util::weaken ($w = $self); |
|
|
315 | Scalar::Util::weaken ($AnyEvent::Debug::Wrapped{Scalar::Util::refaddr $self} = $self); |
|
|
316 | |
|
|
317 | print "$TRACE_NEST creat $w\n" if $TRACE_LEVEL; |
|
|
318 | |
|
|
319 | $self |
|
|
320 | }; |
|
|
321 | } |
|
|
322 | } |
|
|
323 | |
|
|
324 | package AnyEvent::Debug::Wrapped; |
|
|
325 | |
|
|
326 | use AnyEvent (); BEGIN { AnyEvent::common_sense } |
|
|
327 | |
|
|
328 | sub _init { |
|
|
329 | require overload; |
|
|
330 | import overload |
|
|
331 | '""' => sub { |
|
|
332 | $_[0]{str} ||= do { |
|
|
333 | my ($pkg, $line) = @{ $_[0]{caller} }; |
|
|
334 | |
|
|
335 | ($_[0]{cur} ? "$_[0]{cur}/" : "") |
|
|
336 | . (AnyEvent::Debug::path2mod $_[0]{file}) |
|
|
337 | .":" |
|
|
338 | . $_[0]{line} |
|
|
339 | . ($_[0]{sub} =~ /^[^(]/ ? "($_[0]{sub})" : "") |
|
|
340 | . ">" |
|
|
341 | . $_[0]{type} |
|
|
342 | . ">" |
|
|
343 | . (AnyEvent::Debug::cb2str $_[0]{cb}) |
|
|
344 | }; |
|
|
345 | }, |
|
|
346 | fallback => 1; |
|
|
347 | } |
|
|
348 | |
|
|
349 | sub DESTROY { |
|
|
350 | print "$TRACE_NEST dstry $_[0]\n" if $TRACE_LEVEL; |
|
|
351 | |
|
|
352 | delete $AnyEvent::Debug::Wrapped{Scalar::Util::refaddr $_[0]}; |
|
|
353 | } |
|
|
354 | |
132 | 1; |
355 | 1; |
133 | |
356 | |
134 | =back |
357 | =back |
135 | |
358 | |
136 | =head1 AUTHOR |
359 | =head1 AUTHOR |