File Coverage

blib/lib/Mutex/Channel.pm
Criterion Covered Total %
statement 38 77 49.3
branch 7 58 12.0
condition 0 6 0.0
subroutine 11 19 57.8
pod 6 6 100.0
total 62 166 37.3


line stmt bran cond sub pod time code
1             ###############################################################################
2             ## ----------------------------------------------------------------------------
3             ## Mutex::Channel - Mutex locking via a pipe or socket.
4             ##
5             ###############################################################################
6              
7             package Mutex::Channel;
8              
9 2     2   1011 use strict;
  2         4  
  2         61  
10 2     2   10 use warnings;
  2         4  
  2         57  
11              
12 2     2   10 no warnings qw( threads recursion uninitialized once );
  2         4  
  2         122  
13              
14             our $VERSION = '1.011';
15              
16 2     2   1307 use if $^O eq 'MSWin32', 'threads';
  2         28  
  2         44  
17 2     2   102 use if $^O eq 'MSWin32', 'threads::shared';
  2         4  
  2         11  
18              
19 2     2   61 use base 'Mutex';
  2         5  
  2         184  
20 2     2   441 use Mutex::Util;
  2         5  
  2         52  
21 2     2   12 use Scalar::Util 'looks_like_number';
  2         4  
  2         99  
22 2     2   547 use Time::HiRes 'alarm';
  2         1370  
  2         12  
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 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 2 50   2   1393 my ($pid, $obj) = ($tid ? $$ .'.'. $tid : $$, @_);
41 2 50       8 CORE::syswrite($obj->{_w_sock}, '0'), $obj->{ $pid } = 0 if $obj->{ $pid };
42              
43 2 50       7 if ( $obj->{_init_pid} eq $pid ) {
44 2 50       9 $use_pipe
45             ? Mutex::Util::destroy_pipes($obj, qw(_w_sock _r_sock))
46             : Mutex::Util::destroy_socks($obj, qw(_w_sock _r_sock));
47             }
48              
49 2         8 return;
50             }
51              
52             ###############################################################################
53             ## ----------------------------------------------------------------------------
54             ## Public methods.
55             ##
56             ###############################################################################
57              
58             sub new {
59 2     2 1 8 my ($class, %obj) = (@_, impl => 'Channel');
60 2 50       8 $obj{_init_pid} = $tid ? $$ .'.'. $tid : $$;
61 2 50       7 $obj{_t_lock} = threads::shared::share( my $t_lock ) if $is_MSWin32;
62              
63 2 50       9 $use_pipe
64             ? Mutex::Util::pipe_pair(\%obj, qw(_r_sock _w_sock))
65             : Mutex::Util::sock_pair(\%obj, qw(_r_sock _w_sock));
66              
67 2         25 CORE::syswrite($obj{_w_sock}, '0');
68              
69 2         18 return bless(\%obj, $class);
70             }
71              
72             sub lock {
73 0 0   0 1   my ($pid, $obj) = ($tid ? $$ .'.'. $tid : $$, shift);
74              
75 0 0         unless ($obj->{ $pid }) {
76             CORE::lock($obj->{_t_lock}), Mutex::Util::_sock_ready($obj->{_r_sock})
77 0 0         if $is_MSWin32;
78 0           Mutex::Util::_sysread($obj->{_r_sock}, my($b), 1), $obj->{ $pid } = 1;
79             }
80              
81 0           return;
82             }
83              
84             sub guard_lock {
85 0     0 1   &lock(@_);
86 0 0         bless([ $tid ? $$ .'.'. $tid : $$, $_[0] ], Mutex::Channel::_guard::);
87             }
88              
89             *lock_exclusive = \&lock;
90             *lock_shared = \&lock;
91              
92             sub unlock {
93 0 0   0 1   my ($pid, $obj) = ($tid ? $$ .'.'. $tid : $$, shift);
94              
95             CORE::syswrite($obj->{_w_sock}, '0'), $obj->{ $pid } = 0
96 0 0         if $obj->{ $pid };
97              
98 0           return;
99             }
100              
101             sub synchronize {
102 0 0   0 1   my ($pid, $obj, $code) = ($tid ? $$ .'.'. $tid : $$, shift, shift);
103 0           my (@ret, $b);
104              
105 0 0         return unless ref($code) eq 'CODE';
106              
107             # lock, run, unlock - inlined for performance
108 0           my $guard = bless([ $pid, $obj ], Mutex::Channel::_guard::);
109 0 0         unless ($obj->{ $pid }) {
110             CORE::lock($obj->{_t_lock}), Mutex::Util::_sock_ready($obj->{_r_sock})
111 0 0         if $is_MSWin32;
112 0           Mutex::Util::_sysread($obj->{_r_sock}, $b, 1), $obj->{ $pid } = 1;
113             }
114             (defined wantarray)
115 0 0         ? @ret = wantarray ? $code->(@_) : scalar $code->(@_)
    0          
116             : $code->(@_);
117              
118 0 0         return wantarray ? @ret : $ret[-1];
119             }
120              
121             *enter = \&synchronize;
122              
123             sub timedwait {
124 0     0 1   my ($obj, $timeout) = @_;
125              
126 0 0         $timeout = 1 unless defined $timeout;
127 0 0 0       Carp::croak('Mutex::Channel: timedwait (timeout) is not valid')
128             if (!looks_like_number($timeout) || $timeout < 0);
129              
130 0 0         $timeout = 0.0003 if $timeout < 0.0003;
131 0           local $@; my $ret = '';
  0            
132              
133 0           eval {
134 0     0     local $SIG{ALRM} = sub { alarm 0; die "alarm clock restart\n" };
  0            
  0            
135 0 0         alarm $timeout unless $is_MSWin32;
136              
137             die "alarm clock restart\n"
138 0 0 0       if $is_MSWin32 && Mutex::Util::_sock_ready($obj->{_r_sock}, $timeout);
139              
140 0 0         (!$is_MSWin32)
141             ? ($obj->lock_exclusive, $ret = 1, alarm(0))
142             : ($obj->lock_exclusive, $ret = 1);
143             };
144              
145 0 0         alarm 0 unless $is_MSWin32;
146              
147 0           $ret;
148             }
149              
150             1;
151              
152             __END__