blib/lib/IPC/Mmap.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 49 | 54 | 90.7 |
branch | 16 | 22 | 72.7 |
condition | 3 | 5 | 60.0 |
subroutine | 18 | 23 | 78.2 |
pod | 0 | 18 | 0.0 |
total | 86 | 122 | 70.4 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | #/** | ||||||
2 | # Provides a minimal interface to POSIX mmap(), and its | ||||||
3 | # Win32 equivalent. Abstract base class that is used by | ||||||
4 | # the IPC::Mmap::POSIX and IPC::Mmap::Win32 implementations. | ||||||
5 | #
|
||||||
6 | # Permission is granted to use this software under the same terms as Perl itself. | ||||||
7 | # Refer to the Perl Artistic License | ||||||
8 | # for details. | ||||||
9 | # | ||||||
10 | # @author D. Arnold | ||||||
11 | # @since 2006-05-01 | ||||||
12 | # @self $self | ||||||
13 | # @exports MAP_SHARED permit the mmap'd area to be shared with other processes | ||||||
14 | # @exports MAP_PRIVATE do not permit the mmap'ed area to be shared with other processes | ||||||
15 | # @exports MAP_ANON do not use a backing file | ||||||
16 | # @exports MAP_ANONYMOUS same as MAP_ANON | ||||||
17 | # @exports MAP_FILE use a backing file for the memory mapped area | ||||||
18 | # @exports PROT_READ permit read access to the mmap'ed area | ||||||
19 | # @exports PROT_WRITE permit write access to the mmap'ed area | ||||||
20 | #*/ | ||||||
21 | package IPC::Mmap; | ||||||
22 | |||||||
23 | 4 | 4 | 8419 | use Carp; | |||
4 | 5 | ||||||
4 | 211 | ||||||
24 | 4 | 4 | 13 | use DynaLoader; | |||
4 | 4 | ||||||
4 | 64 | ||||||
25 | 4 | 4 | 8 | use Exporter; | |||
4 | 6 | ||||||
4 | 222 | ||||||
26 | our @ISA = qw(Exporter DynaLoader); | ||||||
27 | our $VERSION = '0.22_01'; | ||||||
28 | |||||||
29 | bootstrap IPC::Mmap $VERSION; | ||||||
30 | |||||||
31 | 4 | 4 | 12 | use strict; | |||
4 | 4 | ||||||
4 | 173 | ||||||
32 | 4 | 4 | 15 | use warnings; | |||
4 | 16 | ||||||
4 | 2176 | ||||||
33 | |||||||
34 | our @EXPORT = qw(MAP_ANON MAP_ANONYMOUS MAP_FILE MAP_PRIVATE MAP_SHARED | ||||||
35 | PROT_READ PROT_WRITE); | ||||||
36 | |||||||
37 | if ($^O eq 'MSWin32') { | ||||||
38 | require IPC::Mmap::Win32; | ||||||
39 | } | ||||||
40 | else { | ||||||
41 | require IPC::Mmap::POSIX; | ||||||
42 | } | ||||||
43 | # | ||||||
44 | # these are generated within the appropriate XS code; | ||||||
45 | # gruesome, perhaps, but gets the job done | ||||||
46 | # | ||||||
47 | 16 | 16 | 0 | 57 | sub MAP_ANON { return constant('MAP_ANON', 0); } | ||
48 | 0 | 0 | 0 | 0 | sub MAP_ANONYMOUS { return constant('MAP_ANONYMOUS', 0); } | ||
49 | 7 | 7 | 0 | 132 | sub MAP_FILE { return constant('MAP_FILE', 0); } | ||
50 | 0 | 0 | 0 | 0 | sub MAP_PRIVATE { return constant('MAP_PRIVATE', 0); } | ||
51 | 7 | 7 | 0 | 101 | sub MAP_SHARED { return constant('MAP_SHARED', 0); } | ||
52 | 33 | 33 | 0 | 12654 | sub PROT_READ { return constant('PROT_READ', 0); } | ||
53 | 19 | 19 | 0 | 160 | sub PROT_WRITE { return constant('PROT_WRITE', 0); } | ||
54 | |||||||
55 | |||||||
56 | #/** | ||||||
57 | # Constructor. Maps the specified number of bytes of the specified file | ||||||
58 | # into the current process's address space. Read/write access protection | ||||||
59 | # (default is read-only), and mmap() control flags may be specified | ||||||
60 | # (default is MAP_SHARED). If no length is given, maps the file's current length. | ||||||
61 | #
|
||||||
62 | # The specified file will be created if needed, and openned in an | ||||||
63 | # access mode that is compatible with the specified access protection. | ||||||
64 | # If the size of the file is less than the specified length, and the access flags | ||||||
65 | # include write access, the file will be extended with NUL characters to the | ||||||
66 | # specified length. | ||||||
67 | #
|
||||||
68 | # Note that for Win32, the specified file is used as a "namespace", | ||||||
69 | # rather than physical file, if an "anonymous" mmap() is requested. | ||||||
70 | #
|
||||||
71 | # On POSIX platforms, an anonymous, private shared memory region | ||||||
72 | # can be created (to be inherited by any fork()'ed | ||||||
73 | # child processes) by using a zero-length filename, and | ||||||
74 | # "private" (MAP_PRIVATE) mmap() flags. | ||||||
75 | #
|
||||||
76 | # On Win32 platforms, the default behavior is to create a "namespace", and use the | ||||||
77 | # Windows swap file for the backing file. However, by including MAP_FILE in the | ||||||
78 | # mmap() flags parameter, the specified file will be opened and/or created, | ||||||
79 | # and used for the backing file, rather than the system swap file. | ||||||
80 | # | ||||||
81 | # @param $filename name of file (or namespace) to be mapped | ||||||
82 | # @param $length optional number of bytes to be mapped | ||||||
83 | # @param $protflags optional read/write access flags | ||||||
84 | # @param $mmapflags optional mmap() control flags | ||||||
85 | # | ||||||
86 | # @return the IPC::Mmap object on success; undef on failure | ||||||
87 | #*/ | ||||||
88 | sub new { | ||||||
89 | 8 | 8 | 0 | 52 | my ($class, $file, $length, $prot, $mmap) = @_; | ||
90 | |||||||
91 | 8 | 50 | 24 | $length = 0 unless defined($length); | |||
92 | 8 | 50 | 17 | $prot = PROT_READ unless defined($prot); | |||
93 | 8 | 50 | 17 | $mmap = MAP_SHARED unless defined($mmap); | |||
94 | # | ||||||
95 | # we're just a factory for the platform-specific objects | ||||||
96 | # | ||||||
97 | 8 | 50 | 118 | return ($^O eq 'MSWin32') ? | |||
98 | IPC::Mmap::Win32->new($file, $length, $prot, $mmap) : | ||||||
99 | IPC::Mmap::POSIX->new($file, $length, $prot, $mmap); | ||||||
100 | } | ||||||
101 | |||||||
102 | #/** | ||||||
103 | # Reads data from a specific area of the mmap()'ed file. | ||||||
104 | # | ||||||
105 | # @param $data scalar to receive the data | ||||||
106 | # @param $offset optional offset into mmap'ed area; default is zero | ||||||
107 | # @param $length optional length to read; default is from the offset to the end of the file | ||||||
108 | # | ||||||
109 | # @return the number of bytes actually read on success; undef on failure | ||||||
110 | #*/ | ||||||
111 | sub read { | ||||||
112 | 12 | 12 | 0 | 129 | my $self = shift; | ||
113 | |||||||
114 | 12 | 100 | 18 | croak "Invalid access on write-only region", | |||
115 | return undef | ||||||
116 | unless $self->{_access} & PROT_READ; | ||||||
117 | |||||||
118 | 11 | 50 | 27 | my $off = ($_[1] || 0) + $self->{_slop}; | |||
119 | 11 | 66 | 32 | my $len = $_[2] || $self->{_maxlen}; | |||
120 | |||||||
121 | 11 | 100 | 53 | croak "read failed: offset exceeds region length", | |||
122 | return undef | ||||||
123 | if ($off >= $self->{_maxlen}); | ||||||
124 | |||||||
125 | 9 | 64 | return mmap_read($self->{_addr}, $self->{_maxlen}, | ||||
126 | $off, $_[0], $len); | ||||||
127 | } | ||||||
128 | |||||||
129 | #/** | ||||||
130 | # Write data to the mmap()'ed region. | ||||||
131 | # Writes the specified number of bytes of the specified scalar variable | ||||||
132 | # to the mmap'ed region starting at the specified offset. If not specified, | ||||||
133 | # offset defaults to zero, and length> defaults to the length of the scalar. | ||||||
134 | # If the specified length exceeds the available length of the mmap'ed region | ||||||
135 | # starting from the offset, only the available region length will be written. | ||||||
136 | # | ||||||
137 | # @param $data the data to be written | ||||||
138 | # @param $offset optional offset where the data should be written; default is zero | ||||||
139 | # @param $length optional length of the data to write; default is the length of the data | ||||||
140 | # | ||||||
141 | # @return on success, returns the actual number of bytes written; returns undef | ||||||
142 | # if the offset exceeds the length of the region | ||||||
143 | #*/ | ||||||
144 | sub write { | ||||||
145 | 10 | 10 | 0 | 141 | my ($self, $var, $off, $len) = @_; | ||
146 | |||||||
147 | 10 | 100 | 22 | croak "Invalid access on read-only region", | |||
148 | return undef | ||||||
149 | unless $self->{_access} & PROT_WRITE; | ||||||
150 | |||||||
151 | 9 | 50 | 21 | $off = 0 unless defined($off); | |||
152 | 9 | 12 | $off += $self->{_slop}; | ||||
153 | 9 | 100 | 21 | $len = length($var) unless $len; | |||
154 | |||||||
155 | 9 | 100 | 47 | croak "write failed: offset exceeds region length", | |||
156 | return undef | ||||||
157 | if ($off >= $self->{_maxlen}); | ||||||
158 | |||||||
159 | 8 | 56 | return mmap_write($self->{_addr}, $self->{_maxlen}, | ||||
160 | $off, $var, $len); | ||||||
161 | } | ||||||
162 | #/** | ||||||
163 | # Packs a list of values according to the specified pack string, and writes | ||||||
164 | # the binary result to the mmap'ed region at specified offset. | ||||||
165 | # If the offset plus the packed data length extends beyond the end of the | ||||||
166 | # region, only the available number of bytes will be written. | ||||||
167 | # | ||||||
168 | # @param $offset offset to write the packed data | ||||||
169 | # @param $packstr pack string to be applied to the data | ||||||
170 | # @param @values list of values to pack and write | ||||||
171 | # | ||||||
172 | # @return undef if $offset is beyond the end of the mmap'ed region; otherwise, | ||||||
173 | # the total number of bytes written | ||||||
174 | #*/ | ||||||
175 | sub pack { | ||||||
176 | 2 | 2 | 0 | 53 | my $self = shift; | ||
177 | 2 | 3 | my $off = shift; | ||||
178 | 2 | 8 | my $packstr = shift; | ||||
179 | 2 | 29 | return $self->write(CORE::pack($packstr, @_), $off); | ||||
180 | } | ||||||
181 | #/** | ||||||
182 | # Read the specified number of bytes starting at the specified offset | ||||||
183 | # and unpack into Perl scalars using the specified pack() string. | ||||||
184 | # | ||||||
185 | # @param $offset offset to start reading from | ||||||
186 | # @param $length number of bytes to read | ||||||
187 | # @param $packstr pack string to apply to the read data | ||||||
188 | # | ||||||
189 | # @return on success, the list of unpacked values; undef on failure | ||||||
190 | #*/ | ||||||
191 | sub unpack { | ||||||
192 | 2 | 2 | 0 | 47 | my ($self, $off, $length, $packstr) = @_; | ||
193 | 2 | 5 | my $val; | ||||
194 | return undef | ||||||
195 | 2 | 50 | 6 | unless $self->read($val, $off, $length); | |||
196 | 2 | 29 | return CORE::unpack($packstr, $val); | ||||
197 | } | ||||||
198 | |||||||
199 | #/** | ||||||
200 | # Locks the mmap'ed region. Pure virtual function to be implemented | ||||||
201 | # in the OS-specific implementation subclass. | ||||||
202 | #*/ | ||||||
203 | 0 | 0 | 0 | 0 | sub lock { } | ||
204 | |||||||
205 | #/** | ||||||
206 | # Unlock the mmap'ed region. Pure virtual function | ||||||
207 | # to be implemented in the OS-specific implementation | ||||||
208 | # subclass. | ||||||
209 | # | ||||||
210 | #*/ | ||||||
211 | 0 | 0 | 0 | 0 | sub unlock { } | ||
212 | #/** | ||||||
213 | # Get the filename (or namespace on Win32) for the mmap'ed file. | ||||||
214 | # | ||||||
215 | # @return the mmap'ed filename. | ||||||
216 | #*/ | ||||||
217 | 1 | 1 | 0 | 11 | sub getFilename { return $_[0]->{_file}; } | ||
218 | |||||||
219 | #/** | ||||||
220 | # Get the filehandle for the mmap'ed file. If MAP_ANON | ||||||
221 | # was specified for POSIX platforms, or MAP_FILE was not specified | ||||||
222 | # on Win32 platforms, returns undef. | ||||||
223 | # | ||||||
224 | # @return the file handle used for the mmap'ed file. | ||||||
225 | #*/ | ||||||
226 | 0 | 0 | 0 | 0 | sub getFileHandle { return $_[0]->{_fh}; } | ||
227 | #/** | ||||||
228 | # Get the length of the mmap'ed region | ||||||
229 | # | ||||||
230 | # @return the length of the mmap()ed region. | ||||||
231 | #*/ | ||||||
232 | 2 | 2 | 0 | 29 | sub getLength { return $_[0]->{_maxlen}; } | ||
233 | #/** | ||||||
234 | # Get the base address to which the mmap'ed region was mapped. | ||||||
235 | # | ||||||
236 | # @return the address of the mmap()ed region. | ||||||
237 | #*/ | ||||||
238 | 1 | 1 | 0 | 34 | sub getAddress { return $_[0]->{_addr}; } | ||
239 | |||||||
240 | |||||||
241 | 1; |