File Coverage

lib/IOMux.pm
Criterion Covered Total %
statement 65 83 78.3
branch 12 38 31.5
condition 3 15 20.0
subroutine 16 20 80.0
pod 10 11 90.9
total 106 167 63.4


line stmt bran cond sub pod time code
1             # Copyrights 2011 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 1.07.
5 8     8   1307 use warnings;
  8         14  
  8         219  
6 8     8   40 use strict;
  8         10  
  8         378  
7              
8             package IOMux;
9 8     8   37 use vars '$VERSION';
  8         13  
  8         394  
10             $VERSION = '0.12';
11              
12 8     8   6172 use Log::Report 'iomux';
  8         806408  
  8         55  
13              
14 8     8   2430 use List::Util 'min';
  8         20  
  8         2711  
15 8     8   55 use POSIX 'errno_h';
  8         16  
  8         71  
16              
17             $SIG{PIPE} = 'IGNORE'; # pipes are handled in mux
18              
19             use constant
20 8         9852 { LONG_TIMEOUT => 60 # no-one has set a timeout
21 8     8   4877 };
  8         16  
22              
23              
24 7     7 1 2728 sub new(@) {my $class = shift; (bless {}, $class)->init( {@_} ) }
  7         38  
25             sub init($)
26 7     7 0 14 { my ($self, $args) = @_;
27 7         49 $self->{IM_handlers} = {};
28 7         17 $self->{IM_timeouts} = {};
29 7         19 $self;
30             }
31              
32             #-------------
33              
34             #-------------
35              
36             # add() is the main user interface to mux, because from then the
37             # user works with connection objects. Therefore, offer some extra
38             # features here.
39              
40             sub add($)
41 12     12 1 9794 { my ($self, $handler) = @_;
42              
43 12 50 0     91 UNIVERSAL::isa($handler, 'IOMux::Handler')
44             or error __x"attempt to add non handler {pkg}"
45             , pkg => (ref $handler || $handler);
46              
47 12         413 $handler->mux_init($self);
48 12         267 $handler;
49             }
50              
51              
52             sub open(@)
53 4     4 1 3167 { my $self = shift;
54 4 50       38 IOMux::Open->can('new')
55             or error __x"IOMux::Open not loaded";
56 4         18 my $conn = IOMux::Open->new(@_);
57 4 50       27 $self->add($conn) if $conn;
58 4         11 $conn;
59             }
60              
61              
62             sub loop(;$)
63 4     4 1 158 { my($self, $heartbeat) = @_;
64 4         27 $self->{IM_endloop} = 0;
65              
66 7077         26123 LOOP:
67 4   66     57 while(!$self->{IM_endloop} && keys %{$self->{IM_handlers}})
68             {
69             # while(my($fileno, $conn) = each %{$self->{IM_handlers}})
70             # { $conn->read
71             # if $conn->usesSSL && $conn->pending;
72             # }
73              
74 7073         9795 my $timeout = $self->{IM_next_timeout};
75 7073 50       12051 my $wait = defined $timeout ? $timeout-time : LONG_TIMEOUT;
76              
77             # For negative values, still give select a chance, to avoid
78             # starvation when timeout handling starts consuming all
79             # processor time.
80 7073 50       13918 $wait = 0.001 if $wait < 0.001;
81              
82 7073 50       17243 $self->one_go($wait, $heartbeat)
83             or last LOOP;
84              
85 7073         21893 $self->_checkTimeouts($timeout);
86             }
87              
88             $_->close
89 4         12 for values %{$self->{IM_handlers}};
  4         24  
90             }
91              
92              
93 0     0 1 0 sub endLoop($) { $_[0]->{IM_endloop} = $_[1] }
94              
95             #-------------
96              
97 0     0 1 0 sub handlers() {values %{shift->{IM_handlers}}}
  0         0  
98 21219     21219   51130 sub _handlers() {shift->{IM_handlers}}
99              
100              
101             sub handler($;$)
102 45     45 1 117 { my $hs = shift->{IM_handlers};
103 45         70 my $fileno = shift;
104 45 100       294 @_ or return $hs->{$fileno};
105 13 50       118 (defined $_[0]) ? ($hs->{$fileno} = shift) : (delete $hs->{$fileno});
106             }
107              
108              
109             sub remove($)
110 13     13 1 29 { my ($self, $fileno) = @_;
111              
112 13 50       56 my $obj = delete $self->{IM_handlers}{$fileno}
113             or return $self;
114              
115 13         102 $self->fdset($fileno, 0, 1, 1, 1);
116 13         95 $obj->mux_remove;
117              
118 13 50       313 if(my $timeout = delete $self->{IM_timeouts}{$fileno})
119 0 0       0 { delete $self->{IM_next_timeout}
120             if $self->{IM_next_timeout}==$timeout;
121             }
122              
123 13         29 $self;
124             }
125              
126              
127 0     0 1 0 sub fdset($$$$$) {panic}
128              
129              
130             sub changeTimeout($$$)
131 0     0 1 0 { my ($self, $fileno, $old, $when) = @_;
132 0 0       0 return if $old==$when;
133              
134 0         0 my $next = $self->{IM_next_timeout};
135 0 0       0 if($old)
136             { # next timeout will be recalculated max once per loop
137 0         0 delete $self->{IM_timeouts}{$fileno};
138 0 0 0     0 $self->{IM_next_timeout} = $next = undef if $next && $next==$old;
139             }
140              
141 0 0       0 if($when)
142 0 0 0     0 { $self->{IM_next_timeout} = $when if !$next || $next > $when;
143 0         0 $self->{IM_timeouts}{$fileno} = $when;
144             }
145             }
146              
147             # handle all timeouts which have expired either during the select
148             # or during the processing of flags.
149             sub _checkTimeouts($)
150 7073     7073   9438 { my ($self, $next) = @_;
151              
152 7073         8360 my $now = time;
153 7073 50 33     16244 if($next && $now < $next)
154             { # Even when next is cancelled, none can have expired.
155             # However, a new timeout may have arrived which may expire immediately.
156 0 0       0 return $next if $self->{IM_next_timeout};
157             }
158              
159 7073         10004 my $timo = $self->{IM_timeouts};
160 7073         8829 my $hnd = $self->{IM_handlers};
161 7073         18565 while(my ($fileno, $when) = each %$timo)
162 0 0       0 { $when <= $now or next;
163 0         0 $hnd->{$fileno}->mux_timeout($self);
164 0         0 delete $timo->{$fileno};
165             }
166              
167 7073         31849 $self->{IM_next_timeout} = min values %$timo;
168             }
169              
170             1;
171              
172             __END__