File Coverage

blib/lib/IPC/Mmap/POSIX.pm
Criterion Covered Total %
statement 65 92 70.6
branch 19 56 33.9
condition 3 9 33.3
subroutine 16 18 88.8
pod 0 5 0.0
total 103 180 57.2


line stmt bran cond sub pod time code
1             #/**
2             # Concrete implementation of the IPC::Mmap class for OS's supporting
3             # a POSIX mmap().
4             #

5             # Permission is granted to use this software under the same terms as Perl itself.
6             # Refer to the Perl Artistic License
7             # for details.
8             #
9             # @author D. Arnold
10             # @since 2006-05-01
11             # @self $self
12             #
13             # maintenance and modifications - Athanasios Douitsis aduitsis@cpan.org
14             #*/
15             package IPC::Mmap::POSIX;
16             #
17             # just bootstrap in the XS code
18             #
19 4     4   15 use Carp;
  4         4  
  4         189  
20 4     4   12 use Fcntl qw(:flock :mode);
  4         7  
  4         744  
21 4     4   1454 use FileHandle;
  4         28709  
  4         19  
22 4     4   2759 use IPC::SysV qw(IPC_PRIVATE IPC_CREAT);
  4         3091  
  4         405  
23 4     4   1532 use IPC::Semaphore;
  4         12865  
  4         83  
24 4     4   23 use IPC::Mmap;
  4         6  
  4         291  
25 4     4   1501 use FindBin qw($Bin $Script);
  4         3019  
  4         353  
26 4         177 use IPC::Mmap qw(MAP_ANON MAP_ANONYMOUS MAP_FILE MAP_PRIVATE MAP_SHARED
27 4     4   16 PROT_READ PROT_WRITE);
  4         4  
28 4     4   15 use base qw(IPC::Mmap);
  4         4  
  4         329  
29              
30 4     4   15 use strict;
  4         4  
  4         75  
31 4     4   12 use warnings;
  4         4  
  4         102  
32 4     4   1958 use Data::Dumper;
  4         24888  
  4         2559  
33              
34             #use constant MAP_ANON => constant('MAP_ANON', 0);
35             #use constant MAP_ANONYMOUS => constant('MAP_ANONYMOUS', 0);
36             #use constant MAP_FILE => constant('MAP_FILE', 0);
37             #use constant MAP_PRIVATE => constant('MAP_PRIVATE', 0);
38             #use constant MAP_SHARED => constant('MAP_SHARED', 0);
39             #use constant PROT_READ => constant('PROT_READ', 0);
40             #use constant PROT_WRITE => constant('PROT_WRITE', 0);
41              
42             our $VERSION = '0.22_02';
43             #/**
44             # Constructor. mmap()'s using POSIX mmap().
45             #
46             # @param $filename
47             # @param $length optional
48             # @param $protflags optional
49             # @param $mmapflags optional
50             #
51             # @return the IPC::Mmap::POSIX object on success; undef on failure
52             #*/
53             sub new {
54 8     8 0 27 my ($class, $file, $length, $prot, $mmap) = @_;
55              
56 8         40 my $fh;
57              
58             #the MAN_ANON case will be handled independentlY
59 8 50       20 if($mmap & MAP_ANON) {
60             #make sure we weren't given something that is not a pathname
61 0 0       0 croak 'When using anonymous mmap, only a pathname is allowed as the first argument' unless (ref($file) eq '');
62              
63             #if the file doesn't exist, just touch it
64 0 0       0 if(! -e $file) {
65 0 0       0 open(my $fd,'>',$file) or croak $!;
66 0         0 close $fd;
67             }
68 0 0       0 if(! -r $file) {
69 0         0 croak "For anonymous mmap, you must provide an readable filename in order for the ftok(3) to return a valid unique id. Unfortunately $file doesn't seem to be readable. ";
70             }
71              
72 0         0 my $unique_id = IPC::SysV::ftok($file,1);
73            
74             #create a brand new semaphore
75 0 0       0 my $sem = new IPC::Semaphore($unique_id, 1, 0666|IPC_CREAT) or croak "Cannot create semaphore:$!";
76             ####print STDERR "semaphore is ".Dumper($sem)." \n";
77              
78             #make sure its released
79 0 0       0 $sem->op(0,1,0) or croak "Cannot op(0,1,0) on sem";
80             #@@#warn "semaphore value is ",$sem->getval(0),"\n";
81              
82 0         0 my ($mapaddr, $maxlen, $slop) = _mmap_anon($length, $prot, $mmap);
83 0 0       0 croak "mmap() failed" unless defined($mapaddr);
84 0         0 my $self = {
85             _fh => $fh,
86             _file => $file,
87             _mmap => $mmap,
88             _access => $prot,
89             _addr => $mapaddr,
90             _maxlen => $maxlen,
91             _slop => $slop,
92             semaphore => $sem,
93             };
94              
95 0         0 return bless $self, $class;
96             }
97              
98              
99 8 50 33     38 croak 'No filename or filehandle provided.'
100             unless defined($file) || ($mmap & MAP_ANON);
101              
102 8 50 33     79 croak 'No filename or filehandle provided.'
      33        
103             if defined($file) && (ref $file) && (ref $file ne 'GLOB');
104              
105 8 50       27 if (ref $file) {
    50          
106 0         0 $fh = $file;
107             }
108             elsif (! ($mmap & MAP_ANON)) {
109             #
110             # specified a filename, we need to open (and maybe create) it
111             # NOTE: POSIX doesn't seem to like mmap'ing write-only files,
112             # so we'll cheat
113             #
114 8 100       18 my $flags = ($prot == PROT_READ) ? O_RDONLY : O_RDWR;
115 8 100       145 $flags |= O_CREAT
116             unless -e $file;
117 8 50       537 croak "Can't open $file: $!"
118             unless sysopen($fh, $file, $flags);
119             }
120              
121 8         74 my @filestats = stat $fh;
122 8 100       22 if ($filestats[7] < $length) {
123             #
124             # if file not big enough, expand if its writable
125             # else throw error
126             #
127 2 50       5 croak "IPC::Mmap::new(): specified file too small"
128             unless ($prot & PROT_WRITE);
129             #
130             # seek to end, then write NULs
131             # NOTE: we need to chunk this out!!!
132             #
133 2         3 my $tlen = $length - $filestats[7];
134 2         5 seek($fh, 0, 2);
135 2         91 syswrite($fh, "\0" x $tlen);
136             }
137 8         308 my ($mapaddr, $maxlen, $slop) = _mmap($length, $prot, $mmap, $fh);
138 8 50       27 croak "mmap() failed"
139             unless defined($mapaddr);
140 8         106 my $self = {
141             _fh => $fh,
142             _file => $file,
143             _mmap => $mmap,
144             _access => $prot,
145             _addr => $mapaddr,
146             _maxlen => $maxlen,
147             _slop => $slop,
148             };
149              
150 8         50 return bless $self, $class;
151             }
152              
153             sub DESTROY {
154 8 50   8   10266605 if(defined($_[0]->{semaphore})) {
155 0         0 print STDERR "destroying semaphore ".Dumper($_[0]->{semaphore})."\n";
156 0         0 $_[0]->{semaphore}->remove;
157             }
158             }
159              
160             #/**
161             # Locks the mmap'ed region. Implemented using flock()
162             # on the mmap()'ed file.
163             #

164             # NOTE: This lock is not sufficient
165             # for multithreaded access control, but may be sufficient for
166             # multiprocess access control.
167             #

168             # Also note that, due to flock() restrictions on some
169             # platforms, the type of lock is determined by the protection flags
170             # with which the mmap'ed region was created: if only PROT_READ,
171             # then shared access is used; otherwise, an exclusive lock is used.
172             #*/
173             sub lock {
174 6     6 0 12000478 my ($self, $offset, $len) = @_;
175              
176 6 50       119 if(defined($self->{semaphore})) {
177             #acquire
178 0 0       0 $self->{semaphore}->op(0,-1,0) or croak("Cannot op(0,-1,0) on sem");
179             #@@#warn "semaphore acquired";
180 0         0 return 1;
181             }
182            
183 6         17 my $fh = $self->{_fh};
184 6 100       52 my $mmode = ($self->{_access} == PROT_READ) ? LOCK_SH : LOCK_EX;
185 6         89 return flock($fh, $mmode);
186             }
187              
188             #/**
189             # Unlocks the mmap'ed region. Implemented using flock()
190             # on the mmap()'ed file.
191             #*/
192             sub unlock {
193 5     5 0 209 my ($self, $offset, $len) = @_;
194              
195 5 50       30 if(defined($self->{semaphore})) {
196             #release
197 0 0       0 $self->{semaphore}->op(0,1,0) or croak("Cannot op(0,1,0) on sem");
198             #@@#warn "semaphore released";
199 0         0 return 1;
200             }
201              
202 5         21 my $fh = $self->{_fh};
203 5         32 return flock($fh, LOCK_UN);
204             }
205             #/**
206             # Unmap the mmap()ed region.
207             #

208             # CAUTION!!! Use of this method is discouraged and
209             # deprecated. Unmapping from the file in one thread
210             # can cause segmentation in faults in other threads,
211             # so best practice is to just leave the mmap() in place
212             # and let process rundown clean things up.
213             #
214             # @deprecated
215             #*/
216             sub close {
217 0     0 0   my $self = shift;
218 0 0         _munmap($self->{_addr}, $self->{_maxlen})
219             if $self->{_addr};
220 0 0         CORE::close $self->{_fh} if $self->{_fh};
221             }
222             #
223             # unmap and close the file
224             # NOTE: do we need a ref count for multithreaded environments ?
225             #
226             sub oldDESTROY {
227 0     0 0   my $self = shift;
228 0           print STDERR "IPC::Mmap::DESTROY: addr is $self->{_addr} len $self->{_maxlen}\n";
229 0 0         _munmap($self->{_addr}, $self->{_maxlen})
230             if $self->{_addr};
231 0 0         CORE::close $self->{_fh} if $self->{_fh};
232             }
233              
234             1;