File Coverage

blib/lib/MCE/Mutex/Channel.pm
Criterion Covered Total %
statement 51 86 59.3
branch 17 68 25.0
condition 4 12 33.3
subroutine 14 21 66.6
pod 6 6 100.0
total 92 193 47.6


line stmt bran cond sub pod time code
1             ###############################################################################
2             ## ----------------------------------------------------------------------------
3             ## MCE::Mutex::Channel - Mutex locking via a pipe or socket.
4             ##
5             ###############################################################################
6              
7             package MCE::Mutex::Channel;
8              
9 108     108   5581 use strict;
  108         181  
  108         4581  
10 108     108   567 use warnings;
  108         210  
  108         8035  
11              
12 108     108   570 no warnings qw( threads recursion uninitialized once );
  108         250  
  108         9365  
13              
14             our $VERSION = '1.902';
15              
16 108     108   713 use if $^O eq 'MSWin32', 'threads';
  108         194  
  108         5507  
17 108     108   600 use if $^O eq 'MSWin32', 'threads::shared';
  108         193  
  108         3932  
18              
19 108     108   527 use base 'MCE::Mutex';
  108         321  
  108         16553  
20 108     108   1596 use MCE::Util ();
  108         156  
  108         3590  
21 108     108   929 use Scalar::Util qw(looks_like_number weaken);
  108         598  
  108         9770  
22 108     108   616 use Time::HiRes 'alarm';
  108         277  
  108         1088  
23              
24             my $is_MSWin32 = ($^O eq 'MSWin32') ? 1 : 0;
25             my $use_pipe = ($^O !~ /mswin|mingw|msys|cygwin/i && $] gt '5.010000');
26             my $tid = $INC{'threads.pm'} ? threads->tid : 0;
27              
28             sub CLONE {
29 0 0   0   0 $tid = threads->tid if $INC{'threads.pm'};
30             }
31              
32             sub MCE::Mutex::Channel::_guard::DESTROY {
33 0     0   0 my ($pid, $obj) = @{ $_[0] };
  0         0  
34 0 0       0 CORE::syswrite($obj->{_w_sock}, '0'), $obj->{ $pid } = 0 if $obj->{ $pid };
35              
36 0         0 return;
37             }
38              
39             sub DESTROY {
40 283 50   283   6118 my ($pid, $obj) = ($tid ? $$ .'.'. $tid : $$, @_);
41 283 50       2810 CORE::syswrite($obj->{_w_sock}, '0'), $obj->{$pid } = 0 if $obj->{$pid };
42 283 50       1222 CORE::syswrite($obj->{_r_sock}, '0'), $obj->{$pid.'b'} = 0 if $obj->{$pid.'b'};
43              
44 283 100       1183 if ( $obj->{_init_pid} eq $pid ) {
45 225 100 66     1997 (!$use_pipe || $obj->{impl} eq 'Channel2')
46             ? MCE::Util::_destroy_socks($obj, qw(_w_sock _r_sock))
47             : MCE::Util::_destroy_pipes($obj, qw(_w_sock _r_sock));
48             }
49              
50 283         18488 return;
51             }
52              
53             my @mutex;
54              
55             sub _destroy {
56 0 0   0   0 my $pid = $tid ? $$ .'.'. $tid : $$;
57              
58             # Called by { MCE, MCE::Child, and MCE::Hobo }::_exit
59 0         0 for my $i ( 0 .. @mutex - 1 ) {
60             CORE::syswrite($mutex[$i]->{_w_sock}, '0'), $mutex[$i]->{$pid} = 0
61 0 0       0 if ( $mutex[$i]->{$pid} );
62             CORE::syswrite($mutex[$i]->{_r_sock}, '0'), $mutex[$i]->{$pid.'b'} = 0
63 0 0       0 if ( $mutex[$i]->{$pid.'b'} );
64             }
65             }
66              
67             sub _save_for_global_cleanup {
68 26     26   93 push(@mutex, $_[0]), weaken($mutex[-1]);
69             }
70              
71             ###############################################################################
72             ## ----------------------------------------------------------------------------
73             ## Public methods.
74             ##
75             ###############################################################################
76              
77             sub new {
78 473     473 1 2056 my ($class, %obj) = (@_, impl => 'Channel');
79 473 50       3344 $obj{_init_pid} = $tid ? $$ .'.'. $tid : $$;
80 473 50       1331 $obj{_t_lock} = threads::shared::share( my $t_lock ) if $is_MSWin32;
81              
82 473 50       2523 $use_pipe
83             ? MCE::Util::_pipe_pair(\%obj, qw(_r_sock _w_sock))
84             : MCE::Util::_sock_pair(\%obj, qw(_r_sock _w_sock));
85              
86 473         5669 CORE::syswrite($obj{_w_sock}, '0');
87 473         2635 bless \%obj, $class;
88              
89 473 100 66     5156 if ( caller !~ /^MCE:?/ || caller(1) !~ /^MCE:?/ ) {
90 2         8 MCE::Mutex::Channel::_save_for_global_cleanup(\%obj);
91             }
92              
93 473         4202 return \%obj;
94             }
95              
96             sub lock {
97 371 50   371 1 3272 my ($pid, $obj) = ($tid ? $$ .'.'. $tid : $$, shift);
98              
99 371 50       6214 unless ($obj->{ $pid }) {
100             CORE::lock($obj->{_t_lock}), MCE::Util::_sock_ready($obj->{_r_sock})
101 371 50       1363 if $is_MSWin32;
102 371         5500 MCE::Util::_sysread($obj->{_r_sock}, my($b), 1), $obj->{ $pid } = 1;
103             }
104              
105 371         1806 return;
106             }
107              
108             sub guard_lock {
109 0     0 1 0 &lock(@_);
110 0 0       0 bless([ $tid ? $$ .'.'. $tid : $$, $_[0] ], MCE::Mutex::Channel::_guard::);
111             }
112              
113             *lock_exclusive = \&lock;
114             *lock_shared = \&lock;
115              
116             sub unlock {
117 371 50   371 1 3538 my ($pid, $obj) = ($tid ? $$ .'.'. $tid : $$, shift);
118              
119             CORE::syswrite($obj->{_w_sock}, '0'), $obj->{ $pid } = 0
120 371 50       14711 if $obj->{ $pid };
121              
122 371         2242 return;
123             }
124              
125             sub synchronize {
126 0 0   0 1   my ($pid, $obj, $code) = ($tid ? $$ .'.'. $tid : $$, shift, shift);
127 0           my (@ret, $b);
128              
129 0 0         return unless ref($code) eq 'CODE';
130              
131             # lock, run, unlock - inlined for performance
132 0           my $guard = bless([ $pid, $obj ], MCE::Mutex::Channel::_guard::);
133 0 0         unless ($obj->{ $pid }) {
134             CORE::lock($obj->{_t_lock}), MCE::Util::_sock_ready($obj->{_r_sock})
135 0 0         if $is_MSWin32;
136 0           MCE::Util::_sysread($obj->{_r_sock}, $b, 1), $obj->{ $pid } = 1;
137             }
138             (defined wantarray)
139 0 0         ? @ret = wantarray ? $code->(@_) : scalar $code->(@_)
    0          
140             : $code->(@_);
141              
142 0 0         return wantarray ? @ret : $ret[-1];
143             }
144              
145             *enter = \&synchronize;
146              
147             sub timedwait {
148 0     0 1   my ($obj, $timeout) = @_;
149              
150 0 0         $timeout = 1 unless defined $timeout;
151 0 0 0       Carp::croak('MCE::Mutex::Channel: timedwait (timeout) is not valid')
152             if (!looks_like_number($timeout) || $timeout < 0);
153              
154 0 0         $timeout = 0.0003 if $timeout < 0.0003;
155 0           local $@; my $ret = '';
  0            
156              
157 0           eval {
158 0     0     local $SIG{ALRM} = sub { alarm 0; die "alarm clock restart\n" };
  0            
  0            
159 0 0         alarm $timeout unless $is_MSWin32;
160              
161             die "alarm clock restart\n"
162 0 0 0       if $is_MSWin32 && MCE::Util::_sock_ready($obj->{_r_sock}, $timeout);
163              
164 0 0         (!$is_MSWin32)
165             ? ($obj->lock_exclusive, $ret = 1, alarm(0))
166             : ($obj->lock_exclusive, $ret = 1);
167             };
168              
169 0 0         alarm 0 unless $is_MSWin32;
170              
171 0           $ret;
172             }
173              
174             1;
175              
176             __END__
177              
178             ###############################################################################
179             ## ----------------------------------------------------------------------------
180             ## Module usage.
181             ##
182             ###############################################################################
183              
184             =head1 NAME
185              
186             MCE::Mutex::Channel - Mutex locking via a pipe or socket
187              
188             =head1 VERSION
189              
190             This document describes MCE::Mutex::Channel version 1.902
191              
192             =head1 DESCRIPTION
193              
194             A pipe-socket implementation for C<MCE::Mutex>.
195              
196             The API is described in L<MCE::Mutex>.
197              
198             =over 3
199              
200             =item new
201              
202             =item lock
203              
204             =item lock_exclusive
205              
206             =item lock_shared
207              
208             =item guard_lock
209              
210             =item unlock
211              
212             =item synchronize
213              
214             =item enter
215              
216             =item timedwait
217              
218             =back
219              
220             =head1 AUTHOR
221              
222             Mario E. Roy, S<E<lt>marioeroy AT gmail DOT comE<gt>>
223              
224             =cut
225