File Coverage

blib/lib/Mutex/Channel.pm
Criterion Covered Total %
statement 31 62 50.0
branch 6 52 11.5
condition 0 6 0.0
subroutine 9 15 60.0
pod 5 5 100.0
total 51 140 36.4


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   903 use strict;
  2         4  
  2         57  
10 2     2   8 use warnings;
  2         4  
  2         56  
11              
12 2     2   9 no warnings qw( threads recursion uninitialized once );
  2         3  
  2         109  
13              
14             our $VERSION = '1.008';
15              
16 2     2   10 use base 'Mutex';
  2         4  
  2         198  
17 2     2   445 use Mutex::Util;
  2         5  
  2         81  
18 2     2   11 use Scalar::Util 'looks_like_number';
  2         4  
  2         163  
19 2     2   566 use Time::HiRes 'alarm';
  2         1461  
  2         10  
20              
21             my $is_MSWin32 = ($^O eq 'MSWin32') ? 1 : 0;
22             my $use_pipe = ($^O !~ /mswin|mingw|msys|cygwin/i && $] gt '5.010000');
23             my $tid = $INC{'threads.pm'} ? threads->tid : 0;
24              
25             sub CLONE {
26 0 0   0   0 $tid = threads->tid if $INC{'threads.pm'};
27             }
28              
29             sub DESTROY {
30 2 50   2   1431 my ($pid, $obj) = ($tid ? $$ .'.'. $tid : $$, @_);
31              
32 2 50       7 CORE::syswrite($obj->{_w_sock}, '0'), $obj->{ $pid } = 0 if $obj->{ $pid };
33              
34 2 50       6 if ( $obj->{_init_pid} eq $pid ) {
35 2 50       8 $use_pipe
36             ? Mutex::Util::destroy_pipes($obj, qw(_w_sock _r_sock))
37             : Mutex::Util::destroy_socks($obj, qw(_w_sock _r_sock));
38             }
39              
40 2         9 return;
41             }
42              
43             ###############################################################################
44             ## ----------------------------------------------------------------------------
45             ## Public methods.
46             ##
47             ###############################################################################
48              
49             sub new {
50 2     2 1 8 my ($class, %obj) = (@_, impl => 'Channel');
51 2 50       17 $obj{_init_pid} = $tid ? $$ .'.'. $tid : $$;
52              
53 2 50       8 $use_pipe
54             ? Mutex::Util::pipe_pair(\%obj, qw(_r_sock _w_sock))
55             : Mutex::Util::sock_pair(\%obj, qw(_r_sock _w_sock));
56              
57 2         32 CORE::syswrite($obj{_w_sock}, '0');
58              
59 2         15 return bless(\%obj, $class);
60             }
61              
62             sub lock {
63 0 0   0 1   my ($pid, $obj) = ($tid ? $$ .'.'. $tid : $$, shift);
64              
65 0 0         Mutex::Util::_sock_ready($obj->{_r_sock}) if $is_MSWin32;
66             Mutex::Util::_sysread($obj->{_r_sock}, my($b), 1), $obj->{ $pid } = 1
67 0 0         unless $obj->{ $pid };
68              
69 0           return;
70             }
71              
72             *lock_exclusive = \&lock;
73             *lock_shared = \&lock;
74              
75             sub unlock {
76 0 0   0 1   my ($pid, $obj) = ($tid ? $$ .'.'. $tid : $$, shift);
77              
78             CORE::syswrite($obj->{_w_sock}, '0'), $obj->{ $pid } = 0
79 0 0         if $obj->{ $pid };
80              
81 0           return;
82             }
83              
84             sub synchronize {
85 0 0   0 1   my ($pid, $obj, $code) = ($tid ? $$ .'.'. $tid : $$, shift, shift);
86 0           my (@ret, $b);
87              
88 0 0         return unless ref($code) eq 'CODE';
89              
90             # lock, run, unlock - inlined for performance
91 0 0         Mutex::Util::_sock_ready($obj->{_r_sock}) if $is_MSWin32;
92             Mutex::Util::_sysread($obj->{_r_sock}, $b, 1), $obj->{ $pid } = 1
93 0 0         unless $obj->{ $pid };
94              
95             (defined wantarray)
96 0 0         ? @ret = wantarray ? $code->(@_) : scalar $code->(@_)
    0          
97             : $code->(@_);
98              
99 0           CORE::syswrite($obj->{_w_sock}, '0'), $obj->{ $pid } = 0;
100              
101 0 0         return wantarray ? @ret : $ret[-1];
102             }
103              
104             *enter = \&synchronize;
105              
106             sub timedwait {
107 0     0 1   my ($obj, $timeout) = @_;
108              
109 0 0         $timeout = 1 unless defined $timeout;
110 0 0 0       Carp::croak('Mutex::Channel: timedwait (timeout) is not valid')
111             if (!looks_like_number($timeout) || $timeout < 0);
112              
113 0 0         $timeout = 0.0003 if $timeout < 0.0003;
114 0           local $@; my $ret = '';
  0            
115              
116 0           eval {
117 0     0     local $SIG{ALRM} = sub { alarm 0; die "alarm clock restart\n" };
  0            
  0            
118 0 0         alarm $timeout unless $is_MSWin32;
119              
120             die "alarm clock restart\n"
121 0 0 0       if $is_MSWin32 && Mutex::Util::_sock_ready($obj->{_r_sock}, $timeout);
122              
123 0 0         (!$is_MSWin32)
124             ? ($obj->lock_exclusive, $ret = 1, alarm(0))
125             : ($obj->lock_exclusive, $ret = 1);
126             };
127              
128 0 0         alarm 0 unless $is_MSWin32;
129              
130 0           $ret;
131             }
132              
133             1;
134              
135             __END__