File Coverage

blib/lib/AnyEvent/ITM.pm
Criterion Covered Total %
statement 27 85 31.7
branch 0 18 0.0
condition n/a
subroutine 9 23 39.1
pod 0 1 0.0
total 36 127 28.3


line stmt bran cond sub pod time code
1             package AnyEvent::ITM;
2             our $AUTHORITY = 'cpan:GETTY';
3             # ABSTRACT: Debug ITM/SWD stream deserializer for AnyEvent
4             $AnyEvent::ITM::VERSION = '0.100';
5 2     2   509940 use strict;
  2         4  
  2         69  
6 2     2   14 use warnings;
  2         3  
  2         126  
7 2     2   453 use bytes;
  2         383  
  2         13  
8              
9 2     2   1138 use AnyEvent;
  2         5012  
  2         52  
10 2     2   1718 use AnyEvent::Handle;
  2         36376  
  2         89  
11 2     2   20 use Carp qw( croak );
  2         3  
  2         172  
12 2     2   1476 use ITM;
  2         108041  
  2         207  
13 2     2   26 use Fcntl qw(O_RDONLY O_RDWR O_NONBLOCK O_NOCTTY);
  2         4  
  2         126  
14 2     2   9 use AnyEvent::Util qw(run_cmd portable_pipe);
  2         3  
  2         2116  
15              
16             AnyEvent::Handle::register_read_type(itm => sub {
17             my ( $self, $cb ) = @_;
18             sub {
19             if (defined $_[0]{rbuf}) {
20             my $first = substr($_[0]{rbuf},0,1);
21             my $len = length($_[0]{rbuf});
22             my $f = ord($first);
23             my $header = itm_header($first);
24             if ($header) {
25             my $size = $header->{size} ? $header->{size} : 0;
26             my $payload = substr($_[0]{rbuf},1,$size);
27             if (defined $payload && length($payload) == $size) {
28             my $itm = itm_parse($header,$size ? ($payload) : ());
29             $_[0]{rbuf} = substr($_[0]{rbuf},$size + 1);
30             $cb->( $_[0], $itm );
31             return 1;
32             }
33             return 0;
34             } else {
35             croak sprintf("unknown packet type");
36             }
37             }
38             return 0;
39             };
40             });
41              
42             sub _ts {
43 0     0     my @t = localtime;
44 0           return sprintf "%04d-%02d-%02d %02d:%02d:%02d",
45             $t[5]+1900, $t[4]+1, $t[3], $t[2], $t[1], $t[0];
46             }
47              
48             sub _print_ts {
49 0     0     my ( $label, $line ) = @_;
50 0           chomp $line;
51 0 0         if ($label eq '2>') {
52 0           print STDERR _ts()." $label $line\n";
53             } else {
54 0           print STDOUT _ts()." $label $line\n";
55             }
56             };
57              
58             sub handle {
59 0     0 0   my ( $class, $file, $payload_sub, $cv ) = @_;
60              
61 0 0         my $has_cv = defined $cv ? 1 : 0;
62              
63 0 0         $cv = AE::cv unless $has_cv;
64              
65             # Choose flags so open won't block
66 0           my $flags;
67 0 0         if (-p $file) {
68 0           $flags = O_RDWR | O_NONBLOCK;
69             } else {
70 0           $flags = O_RDONLY | O_NONBLOCK;
71 0 0         $flags |= O_NOCTTY if -c $file;
72             }
73              
74 0 0         sysopen(my $fh, $file, $flags) or die "sysopen $file: $!";
75 0           binmode($fh, ':raw');
76              
77             my $handle = AnyEvent::Handle->new(
78             fh => $fh,
79             on_error => sub {
80 0     0     my ( $handle, $fatal, $message ) = @_;
81 0           $handle->destroy;
82 0           $cv->send("$fatal: $message");
83             },
84             on_eof => sub {
85 0     0     my ( $handle ) = @_;
86 0           $handle->destroy;
87 0           $cv->send("EOF");
88             },
89             on_read => sub {
90 0     0     my $handle = shift;
91 0           $handle->push_read( itm => $payload_sub );
92             },
93 0           );
94              
95 0 0         $cv->recv unless $has_cv;
96              
97 0           return $handle;
98             }
99              
100             sub _run_cmd {
101 0     0     my ($class, @cmd) = @_;
102 0 0         die "run_cmd: no command" unless @cmd;
103              
104 0           my ($out_r, $out_w) = portable_pipe;
105 0           my ($err_r, $err_w) = portable_pipe;
106              
107 0           my $proc = run_cmd \@cmd, '>' => $out_w, '2>' => $err_w, close_all => 1;
108              
109 0           close $out_w;
110 0           close $err_w;
111              
112 0           my %cmd = (
113             cv => AE::cv,
114             proc => $proc,
115             );
116              
117             $cmd{hout} = AnyEvent::Handle->new(
118             fh => $out_r,
119             on_read => sub {
120 0     0     my ($h) = @_;
121             $h->push_read(line => sub {
122 0           my ($h, $line) = @_;
123 0           _print_ts('>', $line);
124 0           });
125             },
126 0     0     on_eof => sub { shift->destroy },
127 0     0     on_error => sub { shift->destroy },
128 0           );
129              
130             $cmd{herr} = AnyEvent::Handle->new(
131             fh => $err_r,
132             on_read => sub {
133 0     0     my ($h) = @_;
134             $h->push_read(line => sub {
135 0           my ($h, $line) = @_;
136 0           _print_ts('2>', $line);
137 0           });
138             },
139 0     0     on_eof => sub { shift->destroy },
140 0     0     on_error => sub { shift->destroy },
141 0           );
142              
143             $proc->cb(sub {
144 0     0     my $raw = shift->recv; # like $?
145 0           my $code = ($raw >> 8) & 0xff;
146 0           my $sig = $raw & 0x7f;
147 0           $cmd{exit_code} = $code;
148 0 0         $cmd{signal} = $sig if $sig;
149 0           $cmd{cv}->send($code);
150 0           });
151              
152 0           return \%cmd; # keep this in scope; wait via $obj->{cv}->recv
153             }
154              
155             1;
156              
157             __END__