File Coverage

blib/lib/Sys/Mmap.pm
Criterion Covered Total %
statement 16 52 30.7
branch 4 24 16.6
condition n/a
subroutine 4 8 50.0
pod 1 1 100.0
total 25 85 29.4


line stmt bran cond sub pod time code
1             package Sys::Mmap;
2              
3             =head1 NAME
4              
5             Sys::Mmap - uses mmap to map in a file as a Perl variable
6              
7             =head1 SYNOPSIS
8              
9             use Sys::Mmap;
10              
11             Sys::Mmap->new( my $str, 8192, 'structtest2.pl' ) or die $!;
12             Sys::Mmap->new( $var, 8192 ) or die $!;
13              
14             mmap( $foo, 0, PROT_READ, MAP_SHARED, FILEHANDLE ) or die "mmap: $!";
15             @tags = $foo =~ /<(.*?)>/g;
16             munmap($foo) or die "munmap: $!";
17              
18             mmap( $bar, 8192, PROT_READ | PROT_WRITE, MAP_SHARED, FILEHANDLE );
19             substr( $bar, 1024, 11 ) = "Hello world";
20              
21             mmap( $baz, 8192, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, STDOUT );
22              
23             $addr = mmap( $baz, 8192, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, STDOUT );
24             Sys::Mmap::hardwire( $qux, $addr, 8192 );
25              
26             =head1 DESCRIPTION
27              
28             The Sys::Mmap module uses the POSIX L call
29             to map in a file as a Perl variable. Memory access by mmap may be shared
30             between threads or forked processes, and may be a disc file that has been
31             mapped into memory. L depends on your operating system supporting
32             UNIX or POSIX.1b mmap, of course.
33              
34             B that L now defines a C<:mmap> tag and presents mmap'd files as
35             regular files, if that is your cup of joe.
36              
37             Several processes may share one copy of the file or string, saving memory, and
38             concurrently making changes to portions of the file or string. When not used
39             with a file, it is an alternative to SysV shared memory. Unlike SysV shared
40             memory, there are no arbitrary size limits on the shared memory area, and
41             sparse memory usage is handled optimally on most modern UNIX implementations.
42              
43             Using the C method provides a C'd interface to C that
44             allows you to use the variable as a normal variable. If a filename is provided,
45             the file is opened and mapped in. If the file is smaller than the length
46             provided, the file is grown to that length. If no filename is provided,
47             anonymous shared inheritable memory is used. Assigning to the variable will
48             replace a section in the file corresponding to the length of the variable,
49             leaving the remainder of the file intact and unmodified. Using C
50             allows you to access the file at an offset, and does not place any requirements
51             on the length argument to C or the length of the variable being
52             inserted, provided it does not exceed the length of the memory region. This
53             protects you from the pathological cases involved in using C directly,
54             documented below.
55              
56             When calling C or C directly, you need to be careful how
57             you use the variable. Some programming constructs may create copies of a string
58             which, while unimportant for smallish strings, are far less welcome if you're
59             mapping in a file which is a few gigabytes big. If you use C and
60             attempt to write to the file via the variable you need to be even more careful.
61             One of the few ways in which you can safely write to the string in-place is by
62             using C as an lvalue and ensuring that the part of the string that
63             you replace is exactly the same length. Other functions will allocate other
64             storage for the variable, and it will no longer overlay the mapped in file.
65              
66             =over 4
67              
68             =item Sys::Mmap->new( C, C, C )
69              
70             Maps C bytes of (the contents of) C if
71             C is provided, otherwise uses anonymous, shared inheritable
72             memory. This memory region is inherited by any Ced children.
73             C will now refer to the contents of that file. Any change to
74             C will make an identical change to the file. If C is zero
75             and a file is specified, the current length of the file will be used. If
76             C is larger then the file, and C is provided, the
77             file is grown to that length before being mapped. This is the preferred
78             interface, as it requires much less caution in handling the variable.
79             C will be tied into the "Sys::Mmap" package, and C will be
80             called for you.
81              
82             Assigning to C will overwrite the beginning of the file for a length
83             of the value being assigned in. The rest of the file or memory region after
84             that point will be left intact. You may use C to assign at a given
85             position:
86              
87             substr(VARIABLE, POSITION, LENGTH) = NEWVALUE
88              
89             =item mmap(VARIABLE, LENGTH, PROTECTION, FLAGS, FILEHANDLE, OFFSET)
90              
91             Maps C bytes of (the underlying contents of) C into your
92             address space, starting at offset C and makes C refer to that
93             memory. The C argument can be omitted in which case it defaults to
94             zero. The C argument can be zero in which case a stat is done on
95             C and the size of the underlying file is used instead.
96              
97             The C argument should be some ORed combination of the constants
98             C, C and C, or else C. The
99             constants C and C are unlikely to be useful here but are
100             included for completeness.
101              
102             The C argument must include either C or C (the
103             latter is unlikely to be useful here). If your platform supports it, you may
104             also use C or C. If your platform supplies
105             C as a non-zero constant (necessarily non-POSIX) then you should also
106             include that in C. POSIX.1b does not specify C as a C
107             argument and most if not all versions of Unix have C as zero.
108              
109             mmap returns C on failure, and the address in memory where the variable
110             was mapped to on success.
111              
112             =item munmap(VARIABLE)
113              
114             Unmaps the part of your address space which was previously mapped in with a
115             call to C and makes VARIABLE become undefined.
116              
117             munmap returns 1 on success and undef on failure.
118              
119             =item hardwire(VARIABLE, ADDRESS, LENGTH)
120              
121             Specifies the address in memory of a variable, possibly within a region you've
122             Ced another variable to. You must use the same precautions to keep the
123             variable from being reallocated, and use C with an exact length. If
124             you C a region that a Ced variable lives in, the
125             Ced variable will not automatically be Ced. You must do this
126             manually.
127              
128             =item Constants
129              
130             The Sys::Mmap module exports the following constants into your namespace:
131              
132             MAP_SHARED MAP_PRIVATE MAP_ANON MAP_ANONYMOUS MAP_FILE
133             MAP_NORESERVE
134             MAP_HUGETLB MAP_HUGE_2MB MAP_HUGE_1GB
135             PROT_EXEC PROT_NONE PROT_READ PROT_WRITE
136              
137             Of the constants beginning with C, only C and C
138             are defined in POSIX.1b and only C is likely to be useful.
139              
140             =back
141              
142             =head1 BUGS
143              
144             Scott Walters doesn't know XS, and is just winging it. There must be a better
145             way to tell Perl not to reallocate a variable in memory...
146              
147             The C interface makes writing to a substring of the variable much less
148             efficient. One user cited his application running 10-20 times slower when C<<
149             Sys::Mmap->new() >> is used than when C is called directly.
150              
151             Malcolm Beattie has not reviewed Scott's work and is not responsible for any
152             bugs, errors, omissions, stylistic failings, importabilities, or design flaws
153             in this version of the code.
154              
155             There should be a tied interface to C as well.
156              
157             Scott Walter's spelling is awful.
158              
159             C will segfault Perl if the C area it was refering to is
160             C'd out from under it.
161              
162             C will segfault Perl if the variable was not successfully C'd
163             previously, or if it has since been reallocated by Perl.
164              
165             =head1 AUTHOR
166              
167             CowboyTim added support for MAP_NORESERVE, MAP_HUGETLB, MAP_HUGE_2MB, and MAP_HUGE_1GB.
168             Thanks CowboyTim!
169              
170             Todd Rinaldo cleaned up code, modernized again, and merged in many fixes,
171             2010-2011.
172              
173             Scott Walters updated for Perl 5.6.x, additions, 2002.
174              
175             Malcolm Beattie, 21 June 1996.
176              
177             =cut
178              
179 2     2   26805 use strict;
  2         4  
  2         1221  
180             our ($VERSION, @ISA, @EXPORT, $AUTOLOAD);
181             require Exporter;
182             @ISA = qw(Exporter);
183              
184             @EXPORT = qw(mmap munmap
185             MAP_ANON MAP_ANONYMOUS MAP_FILE MAP_LOCKED MAP_PRIVATE MAP_SHARED MAP_NORESERVE
186             MAP_HUGETLB
187             MAP_HUGE_2MB
188             MAP_HUGE_1GB
189             PROT_EXEC PROT_NONE PROT_READ PROT_WRITE);
190              
191             $VERSION = '0.19';
192              
193             sub new {
194              
195 0 0   0 1 0 if(scalar @_ < 3) {
196 0         0 warn 'Usage: Sys::Mmap->new( $var, $desiredSize, $optFile );';
197 0         0 return undef;
198             }
199              
200 0         0 my $type = $_[0];
201 0         0 my $leng = $_[2];
202              
203 0         0 tie $_[1], $_[0], @_[2 .. scalar(@_)-1 ];
204             # tie $_[1], $type, $leng;
205              
206             }
207              
208             sub TIESCALAR {
209              
210 0 0   0   0 if(scalar @_ < 2) {
211             # print "debug: got args: ", join ', ', @_, "\n";
212 0         0 warn 'Usage: tie $var, "Sys::Mmap", $desiredSize, $optionalFile;';
213 0         0 return undef;
214             }
215              
216 0         0 my $me;
217             my $fh;
218              
219 0         0 my $type = shift;
220 0         0 my $leng = shift;
221 0         0 my $file = shift;
222              
223 0         0 my $flags = constant('MAP_INHERIT',0)|
224             constant('MAP_SHARED',0);
225              
226 0 0       0 if($file) {
227 0 0       0 open $fh, '+>>', $file or do {
228 0         0 warn "mmap: could not open file '$file' for append r/w";
229 0         0 return undef;
230             };
231             # if we dont pad the file out to the specified length, we coredump
232 0         0 my $fhsize = -s $fh;
233 0 0       0 if($leng > $fhsize) {
234 0         0 $fhsize = $leng - $fhsize;
235 0 0       0 print $fh ("\000" x $fhsize) or die $!;
236             # print $fh pack("a$fhsize", '') or die $!;
237             # while($fhsize) { print $fh "\000"; $fhsize--; }
238             }
239 0         0 $flags |= constant('MAP_FILE',0);
240             } else {
241 0         0 $flags |= constant('MAP_ANON',0);
242             }
243              
244 0 0       0 my $addr = mmap(
    0          
245             $me,
246             $leng,
247             constant('PROT_READ',0)|constant('PROT_WRITE',0),
248             $flags,
249             $file ? $fh : *main::STDOUT
250             ) or die $!;
251              
252 0         0 bless \$me, $type;
253              
254             # XXX return $addr somehow...
255             }
256              
257             sub STORE {
258 0     0   0 my $me = shift;
259 0         0 my $newval = shift;
260 0         0 substr($$me, 0, length($newval), $newval);
261 0         0 $$me;
262             }
263              
264             sub FETCH {
265 0     0   0 my $me = shift;
266 0         0 $$me;
267             }
268              
269             sub AUTOLOAD {
270             # This AUTOLOAD is used to 'autoload' constants from the constant()
271             # XS function. If a constant is not found then control is passed
272             # to the AUTOLOAD in AutoLoader.
273              
274 3 50   3   82850 if ($AUTOLOAD =~ /::(_?[a-z])/) {
275 0         0 $AutoLoader::AUTOLOAD = $AUTOLOAD;
276 0         0 goto &AutoLoader::AUTOLOAD;
277             }
278              
279 3         22 local $! = 0;
280 3         4 my $constname = $AUTOLOAD;
281 3         9 $constname =~ s/.*:://;
282 3 50       8 return if $constname eq 'DESTROY';
283 3 50       16 my $val = constant($constname, @_ ? $_[0] : 0);
284 3 50       7 if ($! == 0) {
285 2     2   9 no strict 'refs';
  2         2  
  2         257  
286 3     9   17 *$AUTOLOAD = sub { $val };
  9         118  
287             }
288             else {
289 0         0 require Carp;
290 0         0 Carp::croak("Your vendor has not defined Sys::Mmap macro $constname");
291             }
292              
293 3         9 goto &$AUTOLOAD;
294             }
295              
296             eval {
297             require XSLoader;
298             XSLoader::load( 'Sys::Mmap', $VERSION );
299             } or do {
300             require DynaLoader;
301             push @ISA, 'DynaLoader';
302             bootstrap Sys::Mmap $VERSION;
303             };
304              
305             1;
306              
307             __END__