File Coverage

blib/lib/IO/Lambda/Inotify.pm
Criterion Covered Total %
statement 91 107 85.0
branch 27 50 54.0
condition 11 18 61.1
subroutine 19 22 86.3
pod 2 6 33.3
total 150 203 73.8


line stmt bran cond sub pod time code
1             package IO::Lambda::Inotify;
2              
3 4     4   123801 use strict;
  4         8  
  4         147  
4 4     4   20 use warnings;
  4         9  
  4         143  
5 4     4   4702 use IO::Handle;
  4         60013  
  4         279  
6 4     4   1792 use IO::Lambda qw(:all :dev);
  4         22027  
  4         1915  
7 4     4   11061 use Linux::Inotify2;
  4         3869  
  4         687  
8 4     4   30 use base qw(Exporter);
  4         8  
  4         9729  
9             our $VERSION = '1.01';
10             our @EXPORT_OK = qw(
11             inotify
12             inotify_server
13             inotify_auto
14             inotify_timeout
15             inotify_plain
16             );
17             our %EXPORT_TAGS = ( all => [ qw(inotify) ] );
18             our $INOTIFY;
19              
20             our $DEBUG = $IO::Lambda::DEBUG{inotify} || 0;
21              
22             sub inotify_one_server
23             {
24 4     4 0 9 my ($inotify, $fh) = @_;
25              
26 4 50       16 unless ($fh) {
27 4 50       99 open $fh, "<&", $inotify-> fileno or die "can't dup inotify handle:$!";
28             }
29              
30 4         122 $inotify-> blocking(0);
31              
32             lambda {
33 4     4   174 context $fh;
34             readable {
35 6         25034 $inotify-> poll;
36 6 100       496 if ($inotify-> {io_lambda_condvar}) {
37 5         29 $inotify-> {io_lambda_condvar}-> terminate;
38 5         396 delete $inotify-> {io_lambda_condvar};
39             }
40 6         25 again;
41             }
42 4         43 }
43 4         64 }
44              
45             sub inotify_server
46             {
47 1     1 1 76 my @k = @_;
48             lambda {
49 1     1   3406 context map { inotify_one_server $_ } @k;
  1         5  
50 1         33 &tails();
51 1         10 };
52             }
53              
54             sub inotify
55             {
56 8 100 66 8 1 15508 return inotify_auto(@_) unless $_[0] and ref($_[0]) and $_[0]->isa('Linux::Inotify2');
      66        
57 6 100 66     54 return inotify_timeout(@_) if 4 == @_ and defined $_[3];
58 1         6 return inotify_plain(@_);
59             }
60              
61             sub inotify_plain
62             {
63 6     6 0 16 my ( $inotify, $path, $flags ) = @_;
64              
65 6         10 my @queue;
66             my $watch = $inotify-> watch( $path, $flags, sub {
67 5     5   657 my $event = shift;
68 5   33     52 push @queue, $event || $!;
69 5 50       36 if ( $DEBUG ) {
70 0 0       0 if ( $event ) {
71 0 0       0 warn "event $inotify.". $event-> w . " $event\n" if $DEBUG;
72             } else {
73 0 0       0 warn "event on $inotify failed :$!\n" if $DEBUG;
74             }
75             }
76 6         65 } );
77              
78 6 50       291 unless ( $watch ) {
79 0         0 my $error = $!;
80 0 0       0 warn "$inotify.watch($path,$flags) = $error\n" if $DEBUG;
81 0     0   0 return lambda { (undef, $error) };
  0         0  
82             }
83              
84 6 50       23 warn "new $watch\n" if $DEBUG;
85              
86 6 100       28 unless ( $inotify-> {io_lambda_server} ) {
87 3         7 my $fh;
88 3 50       11 warn "auto-start $inotify\n" if $DEBUG;
89 3 50       26 unless ( open $fh, , "<&", $inotify-> fileno) {
90 0         0 my $error = $!;
91 0         0 $watch-> cancel;
92 0     0   0 return lambda{ (undef, "can't dup inotify handle:$error") };
  0         0  
93             }
94 3         97 $inotify-> {io_lambda_server} = inotify_one_server($inotify);
95 3         90 $inotify-> {io_lambda_server}-> start;
96             }
97 6         231 $inotify-> {io_lambda_refcnt}++;
98            
99             my $scope_exit = bless sub {
100 5 50   5   28 warn "auto-cancel $watch\n" if $DEBUG;
101              
102 5 100       32 unless (--$inotify-> {io_lambda_refcnt}) {
103 2 50       8 warn "auto-stop $inotify\n" if $DEBUG;
104 2         14 $inotify-> {io_lambda_server}-> terminate;
105 2         193 undef $inotify-> {io_lambda_server};
106             }
107 5         29 $watch-> cancel;
108 6         47 }, __PACKAGE__;
109            
110              
111             # this lambda will be called on again and again
112             return lambda {
113 8 100   8   1858 unless ( $watch-> {inotify} ) {
114 1 50       4 warn "$watch was cancelled\n" if $DEBUG;
115 1         4 return undef, 'watcher is expired';
116             }
117              
118 7         16 my $scope_keeper = $scope_exit;
119              
120 7   66     83 my $listener = $inotify-> {io_lambda_condvar} //= lambda {};
  0         0  
121 7         160 $listener-> bind;
122 7         81 context $listener;
123             tail {
124 5 100       697 unless (@queue) {
125 1         3 this-> start;
126 1         147 return; # not our watcher
127             }
128              
129 4         9 my $event = shift @queue;
130 4 50       15 warn "[$event]\n" if $DEBUG;
131 4 50       38 return ref($event) ? ($event) : (undef, $event);
132             }
133 7         74 }
134 6         54 }
135              
136             sub inotify_auto
137             {
138 2     2 0 9 my @stuff = @_;
139              
140 2   66     24 $INOTIFY ||= Linux::Inotify2-> new;
141 2 50       34 unless ( $INOTIFY ) {
142 0         0 my $error = $!;
143 0 0       0 warn "Linux::Inotify2-> new(): $error\n" if $DEBUG;
144 0     0   0 return lambda { (undef, $error) };
  0         0  
145             }
146              
147 2         11 return inotify( $INOTIFY, @stuff );
148             }
149              
150             sub inotify_timeout
151             {
152 5     5 0 18 my ( $inotify, $path, $flags, $timeout ) = @_;
153              
154 5         19 my $watch = inotify_plain($inotify, $path, $flags);
155              
156             return lambda {
157 6     6   1588 context $watch;
158 6         222 tail { this-> terminate; return @_ };
  4         290  
  4         734  
159              
160 6         421 context $timeout;
161 6         85 timeout { this-> terminate; return undef, 'timeout' };
  2         108  
  2         202  
162             }
163 5         118 }
164              
165 5     5   220843 sub DESTROY { shift-> () }
166              
167             1;
168              
169             __DATA__