File Coverage

blib/lib/Sys/Mmap.pm
Criterion Covered Total %
statement 45 55 81.8
branch 15 24 62.5
condition n/a
subroutine 9 9 100.0
pod 1 1 100.0
total 70 89 78.6


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. (Note:
76             the tied interface does not support C, so this always maps the full
77             file.) If
78             C is larger then the file, and C is provided, the
79             file is grown to that length before being mapped. This is the preferred
80             interface, as it requires much less caution in handling the variable.
81             C will be tied into the "Sys::Mmap" package, and C will be
82             called for you.
83              
84             Assigning to C will overwrite the beginning of the file for a length
85             of the value being assigned in. The rest of the file or memory region after
86             that point will be left intact. You may use C to assign at a given
87             position:
88              
89             substr(VARIABLE, POSITION, LENGTH) = NEWVALUE
90              
91             =item mmap(VARIABLE, LENGTH, PROTECTION, FLAGS, FILEHANDLE, OFFSET)
92              
93             Maps C bytes of (the underlying contents of) C into your
94             address space, starting at offset C and makes C refer to that
95             memory. The C argument can be omitted in which case it defaults to
96             zero. The C argument can be zero in which case a stat is done on
97             C and the file size is used to infer the mapping length. If
98             C is also specified, the inferred length is C
99             (i.e. the remainder of the file from C onward). An exception is
100             thrown if C is at or beyond the end of the file.
101              
102             B: the underlying C system call requires the offset to be a
103             multiple of the system page size (typically 4096 bytes). Sys::Mmap handles
104             non-page-aligned offsets internally by adjusting the mapping, but very large
105             non-aligned offsets may map slightly more memory than the requested region.
106              
107             The C argument should be some ORed combination of the constants
108             C, C and C, or else C. The
109             constants C and C are unlikely to be useful here but are
110             included for completeness.
111              
112             The C argument must include either C or C (the
113             latter is unlikely to be useful here). If your platform supports it, you may
114             also use C or C. If your platform supplies
115             C as a non-zero constant (necessarily non-POSIX) then you should also
116             include that in C. POSIX.1b does not specify C as a C
117             argument and most if not all versions of Unix have C as zero.
118              
119             mmap returns C on failure, and the address in memory where the variable
120             was mapped to on success.
121              
122             =item munmap(VARIABLE)
123              
124             Unmaps the part of your address space which was previously mapped in with a
125             call to C and makes VARIABLE become undefined.
126              
127             munmap returns 1 on success and undef on failure.
128              
129             =item hardwire(VARIABLE, ADDRESS, LENGTH)
130              
131             Specifies the address in memory of a variable, possibly within a region you've
132             Ced another variable to. You must use the same precautions to keep the
133             variable from being reallocated, and use C with an exact length. If
134             you C a region that a Ced variable lives in, the
135             Ced variable will not automatically be Ced. You must do this
136             manually.
137              
138             =item Constants
139              
140             The Sys::Mmap module exports the following constants into your namespace:
141              
142             MAP_SHARED MAP_PRIVATE MAP_ANON MAP_ANONYMOUS MAP_FILE
143             MAP_NORESERVE MAP_POPULATE
144             MAP_HUGETLB MAP_HUGE_2MB MAP_HUGE_1GB
145             PROT_EXEC PROT_NONE PROT_READ PROT_WRITE
146              
147             Of the constants beginning with C, only C and C
148             are defined in POSIX.1b and only C is likely to be useful.
149              
150             =back
151              
152             =head1 BUGS
153              
154             Scott Walters doesn't know XS, and is just winging it. There must be a better
155             way to tell Perl not to reallocate a variable in memory...
156              
157             The C interface makes writing to a substring of the variable much less
158             efficient. One user cited his application running 10-20 times slower when C<<
159             Sys::Mmap->new() >> is used than when C is called directly.
160              
161             Malcolm Beattie has not reviewed Scott's work and is not responsible for any
162             bugs, errors, omissions, stylistic failings, importabilities, or design flaws
163             in this version of the code.
164              
165             There should be a tied interface to C as well.
166              
167             Scott Walter's spelling is awful.
168              
169             C will segfault Perl if the C area it was referring to is
170             C'd out from under it.
171              
172             C will segfault Perl if the variable was not successfully C'd
173             previously, or if it has since been reallocated by Perl.
174              
175             =head1 AUTHOR
176              
177             CowboyTim added support for MAP_NORESERVE, MAP_HUGETLB, MAP_HUGE_2MB, and MAP_HUGE_1GB.
178             Thanks CowboyTim!
179              
180             Todd Rinaldo cleaned up code, modernized again, and merged in many fixes,
181             2010-2011.
182              
183             Scott Walters updated for Perl 5.6.x, additions, 2002.
184              
185             Malcolm Beattie, 21 June 1996.
186              
187             =cut
188              
189 4     4   522615 use strict;
  4         10  
  4         169  
190 4     4   37 use warnings;
  4         27  
  4         3078  
191              
192             our $VERSION = '0.21';
193              
194             our $AUTOLOAD; # For sub AUTOLOAD
195              
196             require Exporter;
197             our @ISA = qw(Exporter);
198              
199             our @EXPORT = qw(mmap munmap
200             MAP_ANON MAP_ANONYMOUS MAP_FILE MAP_LOCKED MAP_PRIVATE MAP_SHARED MAP_NORESERVE
201             MAP_POPULATE
202             MAP_HUGETLB
203             MAP_HUGE_2MB
204             MAP_HUGE_1GB
205             PROT_EXEC PROT_NONE PROT_READ PROT_WRITE);
206              
207              
208             sub new {
209              
210 3 50   3 1 229615 if(scalar @_ < 3) {
211 0         0 warn 'Usage: Sys::Mmap->new( $var, $desiredSize, $optFile );';
212 0         0 return undef;
213             }
214              
215 3         9 my $type = $_[0];
216 3         7 my $leng = $_[2];
217              
218 3         22 tie $_[1], $_[0], @_[2 .. scalar(@_)-1 ];
219             # tie $_[1], $type, $leng;
220              
221             }
222              
223             sub TIESCALAR {
224              
225 3 50   3   12 if(scalar @_ < 2) {
226             # print "debug: got args: ", join ', ', @_, "\n";
227 0         0 warn 'Usage: tie $var, "Sys::Mmap", $desiredSize, $optionalFile;';
228 0         0 return undef;
229             }
230              
231 3         8 my $me;
232             my $fh;
233              
234 3         6 my $type = shift;
235 3         11 my $leng = shift;
236 3         6 my $file = shift;
237              
238 3         25 my $flags = constant('MAP_INHERIT',0)|
239             constant('MAP_SHARED',0);
240              
241 3 100       12 if($file) {
242 2 50       103 open $fh, '+>>', $file or do {
243 0         0 warn "mmap: could not open file '$file' for append r/w";
244 0         0 return undef;
245             };
246             # if we dont pad the file out to the specified length, we coredump
247 2         17 my $fhsize = -s $fh;
248 2 100       8 if($leng > $fhsize) {
249 1         3 $fhsize = $leng - $fhsize;
250 1 50       55 print $fh ("\000" x $fhsize) or die $!;
251             # print $fh pack("a$fhsize", '') or die $!;
252             # while($fhsize) { print $fh "\000"; $fhsize--; }
253             }
254 2         12 $flags |= constant('MAP_FILE',0);
255             } else {
256 1         5 $flags |= constant('MAP_ANON',0);
257             }
258              
259 3 100       287 my $addr = mmap(
    50          
260             $me,
261             $leng,
262             constant('PROT_READ',0)|constant('PROT_WRITE',0),
263             $flags,
264             $file ? $fh : *main::STDOUT
265             ) or die $!;
266              
267 3         99 bless \$me, $type;
268              
269             # XXX return $addr somehow...
270             }
271              
272             sub STORE {
273 2     2   6 my $me = shift;
274 2         4 my $newval = shift;
275 2         67 substr($$me, 0, length($newval), $newval);
276 2         26 $$me;
277             }
278              
279             sub FETCH {
280 7     7   3465 my $me = shift;
281 7         122 $$me;
282             }
283              
284             sub AUTOLOAD {
285             # This AUTOLOAD is used to 'autoload' constants from the constant()
286             # XS function. If a constant is not found then control is passed
287             # to the AUTOLOAD in AutoLoader.
288              
289 10 50   10   450473 if ($AUTOLOAD =~ /::(_?[a-z])/) {
290 0         0 $AutoLoader::AUTOLOAD = $AUTOLOAD;
291 0         0 goto &AutoLoader::AUTOLOAD;
292             }
293              
294 10         58 local $! = 0;
295 10         22 my $constname = $AUTOLOAD;
296 10         49 $constname =~ s/.*:://;
297 10 50       32 return if $constname eq 'DESTROY';
298 10 50       52 my $val = constant($constname, @_ ? $_[0] : 0);
299 10 50       33 if ($! == 0) {
300 4     4   32 no strict 'refs';
  4         6  
  4         801  
301 10     39   70 *$AUTOLOAD = sub { $val };
  39         9450  
302             }
303             else {
304 0         0 require Carp;
305 0         0 Carp::croak("Your vendor has not defined Sys::Mmap macro $constname");
306             }
307              
308 10         50 goto &$AUTOLOAD;
309             }
310              
311             eval {
312             require XSLoader;
313             XSLoader::load( 'Sys::Mmap', $VERSION );
314             } or do {
315             require DynaLoader;
316             push @ISA, 'DynaLoader';
317             bootstrap Sys::Mmap $VERSION;
318             };
319              
320             1;
321              
322             __END__