File Coverage

lib/IOMux/Handler/Write.pm
Criterion Covered Total %
statement 49 94 52.1
branch 8 42 19.0
condition 1 11 9.0
subroutine 15 22 68.1
pod 10 11 90.9
total 83 180 46.1


line stmt bran cond sub pod time code
1             # Copyrights 2011-2020 by [Mark Overmeer ].
2             # For other contributors see ChangeLog.
3             # See the manual pages for details on the licensing terms.
4             # Pod stripped from pm file by OODoc 2.02.
5             # This code is part of distribution IOMux. Meta-POD processed with OODoc
6             # into POD and HTML manual-pages. See README.md
7             # Copyright Mark Overmeer. Licensed under the same terms as Perl itself.
8              
9             package IOMux::Handler::Write;
10 8     8   712 use vars '$VERSION';
  8         14  
  8         388  
11             $VERSION = '1.01';
12              
13 8     8   42 use base 'IOMux::Handler';
  8         12  
  8         2244  
14              
15 8     8   59 use warnings;
  8         14  
  8         275  
16 8     8   35 use strict;
  8         16  
  8         183  
17              
18 8     8   38 use Log::Report 'iomux';
  8         13  
  8         44  
19 8     8   1859 use Fcntl;
  8         16  
  8         1786  
20 8     8   53 use POSIX 'errno_h';
  8         9  
  8         50  
21 8     8   2587 use File::Spec ();
  8         13  
  8         177  
22 8     8   38 use File::Basename 'basename';
  8         10  
  8         487  
23              
24 8     8   71 use constant PIPE_BUF_SIZE => 4096;
  8         12  
  8         7257  
25              
26              
27             sub init($)
28 8     8 0 28 { my ($self, $args) = @_;
29 8         121 $self->SUPER::init($args);
30 8   50     83 $self->{IMHW_write_size} = $args->{write_size} || 4096;
31 8         17 $self;
32             }
33              
34             #-------------------
35              
36             sub writeSize(;$)
37 0     0 1 0 { my $self = shift;
38 0 0       0 @_ ? $self->{IMHW_write_size} = shift : $self->{IMHW_write_size};
39             }
40              
41             #-----------------------
42              
43             sub print(@)
44 6     6 1 1308 { my $self = shift;
45             $self->write( !ref $_[0] ? (@_>1 ? \join('',@_) : \shift)
46 6 50       29 : ref $_[0] eq 'ARRAY' ? \join('',@{$_[0]}) : $_[0] );
  0 0       0  
    50          
47             }
48              
49              
50             sub say(@)
51 0     0 1 0 { my $self = shift;
52             $self->write
53             ( !ref $_[0] ? \join('',@_, "\n")
54 0 0       0 : ref $_[0] eq 'ARRAY' ? \join('',@{$_[0]}, "\n")
  0 0       0  
55             : $_[0]."\n"
56             );
57             }
58              
59              
60             sub printf($@)
61 0     0 1 0 { my $self = shift;
62 0         0 $self->write(\sprintf(@_));
63             }
64              
65              
66             sub write($;$)
67 12     12 1 1988 { my ($self, $blob, $more) = @_;
68              
69 12 50       32 if(exists $self->{IMHW_outbuf})
70             { # There is already output waiting, glue this
71 0         0 ${$self->{IMHW_outbuf}} .= $$blob;
  0         0  
72 0         0 $self->{IMHW_more} = $more;
73 0         0 return;
74             }
75              
76              
77 12         31 my $bytes_written = syswrite $self->fh, $$blob, $self->{IMHW_write_size};
78 12 50       77 if(!defined $bytes_written)
    50          
79 0 0 0     0 { unless($!==EWOULDBLOCK || $!==EINTR)
80 0         0 { $self->close;
81 0         0 fault __x"write to {name} failed", name => $self->name;
82             }
83             # we cannot send the bytes yet
84             }
85             elsif($bytes_written==length $$blob)
86             { # we got rit of all at once. Cheap! No need to wait in mux
87 12 50       32 $more->($self) if $more;
88             $self->{IMHW_is_closing}->($self)
89 12 50       30 if $self->{IMHW_is_closing};
90 12         33 return;
91             }
92             else
93             { # some bytes sent
94 0         0 substr($$blob, 0, $bytes_written) = '';
95             }
96              
97             # start waiting for write-ready flag, to send more
98 0         0 $self->{IMHW_outbuf} = $blob;
99 0         0 $self->{IMHW_more} = $more;
100 0         0 $self->fdset(1, 0, 1, 0);
101             }
102              
103              
104             #-------------------------
105              
106             sub muxInit($)
107 7     7 1 14 { my ($self, $mux) = @_;
108 7         76 $self->SUPER::muxInit($mux);
109             # $self->fdset(1, 0, 1, 0);
110 7         406 $self->fdset(0, 0, 1, 0);
111             }
112              
113             sub muxWriteFlagged()
114 0     0 1 0 { my $self = shift;
115 0         0 my $outbuf = $self->{IMHW_outbuf};
116 0 0       0 unless($outbuf)
117             { # trigger follow-up event, which may produce more data to be sent
118 0         0 $self->muxOutbufferEmpty;
119 0         0 $outbuf = $self->{IMHW_outbuf};
120 0 0       0 unless(defined $outbuf)
121             { # nothing can be produced on call, so we don't need the
122             # empty-write signals on the moment (enabled at next write)
123 0         0 return;
124             }
125 0 0       0 unless(length $$outbuf)
126             { # retry callback at next interval
127 0         0 delete $self->{IMHW_outbuf};
128 0         0 return;
129             }
130             }
131              
132 0         0 my $bytes_written = syswrite $self->fh, $$outbuf, $self->{IMHW_write_size};
133 0 0       0 if(!defined $bytes_written)
    0          
134             { # should happen, but we're kind
135 0 0 0     0 return if $! == EWOULDBLOCK || $! == EINTR || $! == EAGAIN;
      0        
136 0         0 warning __x"write to {name} failed: {err}"
137             , name => $self->name, err => $!;
138 0         0 $self->close;
139             }
140             elsif($bytes_written==length $$outbuf)
141 0         0 { delete $self->{IMHW_outbuf};
142 0         0 $self->muxOutbufferEmpty;
143             }
144             else
145 0         0 { substr($$outbuf, 0, $bytes_written) = '';
146             }
147             }
148              
149              
150             sub muxOutbufferEmpty()
151 0     0 1 0 { my $self = shift;
152 0         0 my $more = delete $self->{IMHW_more};
153 0 0       0 return $more->() if defined $more;
154              
155 0         0 $self->fdset(0, 0, 1, 0);
156             $self->{IMHW_is_closing}->($self)
157 0 0       0 if $self->{IMHW_is_closing};
158             }
159              
160              
161 0     0 1 0 sub muxOutputWaiting() { exists shift->{IMHW_outbuf} }
162              
163             # Closing write handlers is a little complex: it should be delayed
164             # until the write buffer is empty.
165              
166             sub close(;$)
167 10     10 1 755 { my ($self, $cb) = @_;
168 10 50       26 if($self->{IMHW_outbuf})
169             { # delay closing until write buffer is empty
170 0     0   0 $self->{IMHW_is_closing} = sub { $self->SUPER::close($cb)};
  0         0  
171             }
172             else
173             { # can close immediately
174 10         64 $self->SUPER::close($cb);
175             }
176             }
177              
178             1;