File Coverage

blib/lib/IPC/Shareable/SharedMem.pm
Criterion Covered Total %
statement 130 133 97.7
branch 49 54 90.7
condition 17 24 70.8
subroutine 23 23 100.0
pod 15 15 100.0
total 234 249 93.9


line stmt bran cond sub pod time code
1             package IPC::Shareable::SharedMem;
2              
3 78     78   595 use warnings;
  78         150  
  78         5336  
4 78     78   391 use strict;
  78         118  
  78         2473  
5              
6 78     78   313 use Carp qw(carp croak confess);
  78         135  
  78         4206  
7 78     78   370 use Config;
  78         108  
  78         3755  
8 78     78   382 use Data::Dumper;
  78         131  
  78         4258  
9 78     78   339 use IPC::SysV qw(IPC_RMID IPC_STAT);
  78         149  
  78         5262  
10              
11             our $VERSION = '1.14_07';
12              
13             use constant {
14 78         9667 DEFAULT_SEG_SIZE => 1024,
15             DEFAULT_SEG_FLAGS => 0000,
16             DEFAULT_SEG_MODE => 0666,
17 78     78   363 };
  78         164  
18              
19             {
20             package IPC::Shareable::SharedMem::stat;
21              
22 78     78   718 use Class::Struct qw(struct);
  78         237  
  78         447  
23              
24             struct 'IPC::Shareable::SharedMem::stat' => [
25             uid => '$',
26             gid => '$',
27             cuid => '$',
28             cgid => '$',
29             mode => '$',
30             segsz => '$',
31             lpid => '$',
32             cpid => '$',
33             nattch => '$',
34             atime => '$',
35             dtime => '$',
36             ctime => '$',
37             ];
38             }
39              
40             sub new {
41 604     604 1 17774 my ($class, %params) = @_;
42              
43 604         2514 my $self = bless {}, $class;
44              
45 604 100 100     5188 if (defined $params{key} && $params{key} =~ /^0x[0-9a-fA-F]+$/i) {
46 1         5 $params{key} = hex($params{key});
47             }
48              
49 604 100 100     7093 if (! defined $params{key} || $params{key} !~ /^\d+$/) {
50 2         490 croak "new() requires a 'key' parameter with an integer value";
51             }
52              
53 602         3025 $self->key($params{key});
54 602         1286 $self->key_hex($self->key);
55              
56 602   100     3210 $self->size($params{size} || DEFAULT_SEG_SIZE);
57              
58 601   100     3152 $self->mode($params{mode} || DEFAULT_SEG_MODE);
59 601   100     2547 $self->flags(($params{flags} || DEFAULT_SEG_FLAGS) | $self->mode);
60              
61 601         2622 $self->type($params{type});
62              
63 601         1368 my $id = shmget($self->key, $self->size, $self->flags);
64              
65 601 100       2376 defined $id or do {
66 10         42 my $key = $self->key_hex;
67              
68 10 50       176 if ($!) {
69 10 100 66     159 if ($! =~ /File exists/ || $! =~ /Permission denied/) {
70 6         2187 croak "\nERROR: IPC::Shareable::SharedMem: shmget $key: $!\n\n" .
71             "Are you using exclusive, but trying to create multiple " .
72             "instances?\n\n";
73             }
74              
75 4         126 return undef;
76             }
77             };
78              
79 591         1731 $self->id($id);
80              
81 591         2853 return $self;
82             }
83             sub id {
84 10229     10229 1 52303 my ($self, $id) = @_;
85              
86 10229 100       19835 if (defined $id) {
87 592 100       1500 if ($self->{id}) {
88 1         18 warn "Can't set id() after object already instantiated";
89 1         10 return $self->{id};
90             }
91 591         2048 $self->{id} = $id;
92             }
93 10228         34222 return $self->{id};
94             }
95             sub key {
96 1840     1840 1 7055 my ($self, $key) = @_;
97              
98 1840 100       4024 if (defined $key) {
99 603 100       1770 if ($self->id) {
100 1         176 croak "Can't set the 'key' attribute after object is already established";
101             }
102              
103 602         2291 $self->{key} = $key;
104             }
105              
106 1839         5530 return $self->{key};
107             }
108             sub key_hex {
109 1094     1094 1 2596 my ($self, $key_int) = @_;
110              
111 1094 100       2682 if (defined $key_int) {
112 602         3364 $self->{key_hex} = sprintf "0x%08x", $key_int;
113             }
114              
115 1094         11612 return $self->{key_hex};
116             }
117             sub flags {
118 2057     2057 1 10686 my ($self, $flags) = @_;
119              
120 2057 100       4331 if (defined $flags) {
121 602 100       1590 if ($self->id) {
122 1         18 warn "Can't set flags() after object already instantiated";
123 1         20 return $self->{flags};
124             }
125              
126 601         1380 $self->{flags} = $flags;
127             }
128 2056         50319 return $self->{flags};
129             }
130             sub mode {
131 1206     1206 1 2873 my ($self, $mode) = @_;
132              
133 1206 100       2568 if (defined $mode) {
134 602 100       1304 if ($self->id) {
135 1         18 warn "Can't set mode() after object already instantiated";
136 1         10 return $self->{mode};
137             }
138              
139 601         1510 $self->{mode} = $mode;
140             }
141              
142 1205         3401 return $self->{mode};
143             }
144             sub size {
145 6116     6116 1 12121 my ($self, $size) = @_;
146              
147 6116 100       11971 if (defined $size) {
148 603 100       1459 if ($self->id) {
149 1         28 warn "Can't set size() after object already instantiated";
150 1         9 return $self->{size};
151             }
152 602 100       3835 if ($size !~ /^\d+$/) {
153 1         194 croak "size() requires an integer as parameter";
154             }
155              
156 601         1729 $self->{size} = $size;
157             }
158 6114         657599 return $self->{size};
159             }
160             sub type {
161 604     604 1 2215 my ($self, $type) = @_;
162              
163 604 100       1488 if (defined $type) {
164 496 100       1027 if ($self->id) {
165 1         15 warn "Can't set type() after object already instantiated";
166 1         7 return $self->{type};
167             }
168              
169 495         1327 $self->{type} = $type;
170             }
171              
172 603         1198 return $self->{type};
173             }
174             sub data {
175 1478     1478 1 3094 my ($self) = @_;
176              
177 1478         3761 my $data = $self->shmread;
178              
179 1478 100       4367 return if ! defined $data;
180              
181             # Remove \x{0} (NULL bytes) after end of string
182 1472         31582 $data =~ s/\x00+//;
183              
184 1472         6185 return $data;
185             }
186             sub stat {
187 29     29 1 15243 my ($self) = @_;
188 29         46 my $data = '';
189 29 100       54 shmctl($self->id, IPC_STAT, $data) or return undef;
190              
191 28         288 my %values;
192              
193 28 50 0     98 if ($^O eq 'linux') {
    0          
194 28 50       374 if ($Config{longsize} == 8) {
195             # 64-bit Linux: ipc64_perm is 48 bytes.
196             # ipc64_perm: key(4) uid(4) gid(4) cuid(4) cgid(4) mode(4)
197             # seq(2) pad2(2) [4-byte align-pad] unused1(8) unused2(8)
198             # shmid_ds: segsz(8) atime(8) dtime(8) ctime(8) cpid(4) lpid(4) nattch(8)
199              
200 28         220 @values{qw(uid gid cuid cgid mode segsz atime dtime ctime cpid lpid nattch)}
201             = unpack('x[4] L L L L L x[24] Q q q q l l Q', $data);
202             }
203             else {
204             # 32-bit Linux: ipc64_perm is 36 bytes (unsigned long = 4 bytes).
205             # ipc64_perm: key(4) uid(4) gid(4) cuid(4) cgid(4) mode(4)
206             # seq(2) pad2(2) unused1(4) unused2(4)
207             # shmid_ds: segsz(4) atime(4) atime_nsec(4) dtime(4) dtime_nsec(4)
208             # ctime(4) ctime_nsec(4) cpid(4) lpid(4) nattch(4)
209              
210 0         0 @values{qw(uid gid cuid cgid mode segsz atime dtime ctime cpid lpid nattch)}
211             = unpack('x[4] L L L L L x[12] L L x[4] L x[4] L x[4] l l L', $data);
212             }
213             }
214             elsif ($^O eq 'freebsd' && $Config{longsize} == 8) {
215             # 64-bit FreeBSD: ipc_perm is 32 bytes.
216             # ipc_perm: cuid(4) cgid(4) uid(4) gid(4) mode(2) _seq(2) pad(4) _key(8)
217             # shmid_ds: segsz(8) lpid(4) cpid(4) nattch(8) atime(8) dtime(8) ctime(8)
218             # (key_t = long = 8 bytes on FreeBSD 64-bit, with 4 bytes of alignment padding)
219              
220 0         0 @values{qw(cuid cgid uid gid mode segsz lpid cpid nattch atime dtime ctime)}
221             = unpack('L L L L S x[14] Q l l Q q q q', $data);
222             }
223             else {
224             # macOS/BSD shmid_ds / ipc_perm layout:
225             #
226             # ipc_perm (24 bytes): uid(4) gid(4) cuid(4) cgid(4) mode(2/ushort) seq(2) key(4)
227             # shmid_ds: segsz(8) lpid(4) cpid(4) nattch(2/ushort) [pad 2] atime(8) dtime(8) ctime(8)
228             #
229             # Fields happen to match stat_list() order, so a linear unpack works.
230              
231 0         0 @values{stat_list()} = unpack('L L L L S x[6] Q l l S x[2] q q q', $data);
232             }
233              
234 28         64 my @struct_initializers;
235 28         46 for (stat_list()) {
236 336         374 my $value = $values{$_};
237 336 100       462 if ($_ eq 'mode') {
238 28         40 $value = $value & 0777;
239 28         101 push @struct_initializers, $_ => sprintf("%#o", $value);
240             }
241             else {
242 308         469 push @struct_initializers, $_ => $value;
243             }
244             }
245              
246 28         869 return IPC::Shareable::SharedMem::stat->new(@struct_initializers);
247             }
248             sub stats {
249 1     1 1 6 my ($self) = @_;
250 1         2 my @stat_list = stat_list();
251              
252 1         4 my %stats;
253              
254 1         8 for (@stat_list) {
255 12         1229 $stats{$_} = $self->stat->$_;
256             }
257              
258 1         96 return \%stats;
259             }
260             sub stat_list {
261 30     30 1 122 return qw(
262             uid
263             gid
264             cuid
265             cgid
266             mode
267             segsz
268             lpid
269             cpid
270             nattch
271             atime
272             dtime
273             ctime
274             );
275             }
276              
277             sub shmread {
278 3073     3073 1 5500 my ($self) = @_;
279              
280 3073         5590 my $data = '';
281 3073 100       8804 shmread($self->id, $data, 0, $self->size) or return;
282 3060         21987 return $data;
283             }
284             sub shmwrite {
285 918     918 1 2008 my($self, $data) = @_;
286 918         2325 return shmwrite($self->id, $data, 0, $self->size);
287             }
288             sub remove {
289 436     436 1 859 my ($self) = @_;
290 436         944 my $os_return_value = shmctl($self->id, IPC_RMID, 0);
291              
292 436 100 33     25074 if (defined $os_return_value && ($os_return_value eq '0 but true' || $os_return_value == 1)) {
      66        
293 435         2551 return 1;
294             }
295             else {
296 1         6 return 0;
297             }
298             }
299              
300             1;
301              
302             =head1 NAME
303              
304             IPC::Shareable::SharedMem - Allows access to a shared memory segment via an
305             object oriented interface.
306              
307             =head1 DESCRIPTION
308              
309             This module provides object oriented access to a shared memory segment. Although
310             it can be used standalone, it was designed for use specifically within the
311             L<< IPC::Shareable >> library.
312              
313             =for html
314            
315             Coverage Status
316              
317             =head1 SYNOPSIS
318              
319             =head1 METHODS
320              
321             =head2 new(%params)
322              
323             Instantiates and returns an object that represents a shared memory segment.
324              
325             If for any reason we can't create the shared memory segment, we'll return
326             C.
327              
328             Parameters (must be in key => value pairs):
329              
330             =head3 key
331              
332             I<< Mandatory, Integer >>: An integer that references the shared memory segment.
333              
334             =head3 size
335              
336             I: An integer representing the size in bytes of the
337             shared memory segment. The maximum is Operating System independent.
338              
339             I: 1024
340              
341             =head3 flags
342              
343             I: A bitwise mask of options logically OR'd together
344             with any or all of C (create segment if it doesn't exist),
345             C (exclusive access; if the segment already exists,
346             we'll C) and C (create a read only segment).
347              
348             See L for further details.
349              
350             I: C<0> (ie. no flags).
351              
352             =head3 mode
353              
354             I: An octal number representing the access permissions
355             for the shared memory segment. Exactly the same as a Unix file system
356             permissions.
357              
358             I: 0666 (User RW, Group RW, World RW).
359              
360             =head3 type
361              
362             I: The type of data that will be stored in the shared memory
363             segment. L uses C, C or C.
364              
365             =head2 id
366              
367             Sets/gets the identification number that references the shared memory segment.
368              
369             A warning will be thrown if you try to set the ID after the object is already
370             instantiated, and no change will occur.
371              
372             =head2 key
373              
374             Sets/gets the key used to identify the shared memory segment.
375              
376             Setting this attribute should only be done internally. If it is sent in after
377             the object is already associated with a shared memory segment, we will C.
378              
379             See L for further details.
380              
381             =head2 key_hex($key)
382              
383             Returns the hex formatted key which appears in C calls.
384              
385             Parameters:
386              
387             =head3 $key
388              
389             I<< Optional, String >>: This is always sent in during initialization.
390              
391             =head2 size
392              
393             Sets/gets the size of the shared memory segment in bytes. See L for
394             further details.
395              
396             A warning will be thrown if you try to set the size after the object is already
397             instantiated, and no change will occur.
398              
399             =head2 flags
400              
401             Sets/gets the flags that the segment will be created with. See L for
402             details.
403              
404             A warning will be thrown if you try to set the flags after the object is already
405             instantiated, and no change will occur.
406              
407             =head2 mode
408              
409             Sets/gets the access permissions. See L for further details.
410              
411             A warning will be thrown if you try to set the mode after the object is already
412             instantiated, and no change will occur.
413              
414             =head2 type
415              
416             Sets/gets the type of data that will be contained in the shared memory segment.
417             See L for details.
418              
419             A warning will be thrown if you try to set the type after the object is already
420             instantiated, and no change will occur.
421              
422             =head2 data
423              
424             Returns the data in the shared memory segment, with all NULL pad bytes removed.
425              
426             Use this method for text data. For binary data where you need all blocks within
427             the segment, use the L method.
428              
429             =head2 stat
430              
431             This method has sub methods that display various system-level information about
432             the memory segment. These sub methods are:
433              
434             uid
435             gid
436             cuid
437             cgid
438             mode
439             segsz
440             lpid
441             cpid
442             nattch
443             atime
444             dtime
445             ctime
446              
447             Example call:
448              
449             my $ctime = $seg->stat->ctime;
450              
451             =head2 stats
452              
453             Returns an href of the various system-level stat information:
454              
455             {
456             uid => 501,
457             gid => 20,
458             cuid => 501,
459             cgid => 20,
460             mode => 0666,
461             segsz => 65536,
462             lpid => 61270,
463             cpid => 61270,
464             nattch => 0,
465             atime => 1778791348,
466             dtime => 1778791348,
467             ctime => 1778791348,
468             }
469              
470             =head2 stat_list
471              
472             Returns an array of all the segment's system stat entries. These are what make
473             up the method names of the C<< $seg->stat >> object.
474              
475             =head2 shmread
476              
477             Returns the data (and NULL pad bytes) stored in the shared memory segment.
478              
479             By default, when data is retrieved from the shared memory segment, the data
480             is padded to the right by NULL bytes to fill up the entire size of the segment.
481             This can cause issues when using the space for non serialized data (ie. if you
482             stored "hello" in a 1024 byte segment, the ASCII text wouldn't match).
483              
484             Typically this method is used when you want all blocks of the segment, such as
485             if you've stored binary data.
486              
487             For text/ASCII data, use the L method.
488              
489             Send in a true value as this parameter and we'll clean the NULLs for you.
490              
491             I: The data if any is stored, empty string if no data has been stored
492             yet, and C if a failure to read occurs.
493              
494             =head2 shmwrite($data)
495              
496             Stores the serialized data to the shared memory segment.
497              
498             Parameters:
499              
500             $data
501              
502             I: Typically, the a serialized data structure.
503              
504             I: True on success, false on failure.
505              
506             =head2 remove
507              
508             Removes the shared memory segment and returns the resources to the system.
509              
510             I: True (C<1>) on success, false (C<0>) on failure.
511              
512             =head1 AUTHOR
513              
514             Ben Sugars (bsugars@canoe.ca)
515              
516             =head1 MAINTAINED BY
517              
518             Steve Bertrand
519              
520             =head1 SEE ALSO
521              
522             L, L L