File Coverage

blib/lib/IPC/Shareable/SharedMem.pm
Criterion Covered Total %
statement 135 141 95.7
branch 50 60 83.3
condition 17 24 70.8
subroutine 24 24 100.0
pod 15 15 100.0
total 241 264 91.2


line stmt bran cond sub pod time code
1             package IPC::Shareable::SharedMem;
2              
3 79     79   546 use warnings;
  79         139  
  79         5871  
4 79     79   479 use strict;
  79         136  
  79         2471  
5              
6 79     79   372 use Carp qw(carp croak confess);
  79         135  
  79         5194  
7 79     79   431 use Config;
  79         2142  
  79         4782  
8 79     79   399 use Data::Dumper;
  79         2336  
  79         4604  
9 79     79   2761 use Errno qw(EEXIST EPERM);
  79         180  
  79         4420  
10 79     79   680 use IPC::SysV qw(IPC_RMID IPC_STAT);
  79         248  
  79         5882  
11              
12             our $VERSION = '1.14_10';
13              
14             use constant {
15 79         9502 DEFAULT_SEG_SIZE => 1024,
16             DEFAULT_SEG_FLAGS => 0000,
17             DEFAULT_SEG_MODE => 0666,
18 79     79   465 };
  79         161  
19              
20             {
21             package IPC::Shareable::SharedMem::stat;
22              
23 79     79   463 use Class::Struct qw(struct);
  79         126  
  79         591  
24              
25             struct 'IPC::Shareable::SharedMem::stat' => [
26             uid => '$',
27             gid => '$',
28             cuid => '$',
29             cgid => '$',
30             mode => '$',
31             segsz => '$',
32             lpid => '$',
33             cpid => '$',
34             nattch => '$',
35             atime => '$',
36             dtime => '$',
37             ctime => '$',
38             ];
39             }
40              
41             sub new {
42 609     609 1 25882 my ($class, %params) = @_;
43              
44 609         2731 my $self = bless {}, $class;
45              
46 609 100 100     5195 if (defined $params{key} && $params{key} =~ /^0x[0-9a-fA-F]+$/i) {
47 1         8 $params{key} = hex($params{key});
48             }
49              
50 609 100 100     6634 if (! defined $params{key} || $params{key} !~ /^\d+$/) {
51 2         602 croak "new() requires a 'key' parameter with an integer value";
52             }
53              
54 607         3144 $self->key($params{key});
55 607         1503 $self->key_hex($self->key);
56              
57 607   100     3437 $self->size($params{size} || DEFAULT_SEG_SIZE);
58              
59 606   100     3002 $self->mode($params{mode} || DEFAULT_SEG_MODE);
60 606   100     2488 $self->flags(($params{flags} || DEFAULT_SEG_FLAGS) | $self->mode);
61              
62 606         2433 $self->type($params{type});
63              
64 606         1591 my $id = shmget($self->key, $self->size, $self->flags);
65              
66 606 100       2836 defined $id or do {
67 10         36 my $key = $self->key_hex;
68              
69 10 50       206 if ($!) {
70 10 100 66     314 if ($!{EEXIST} || $!{EPERM}) {
71 6         2105 croak "\nERROR: IPC::Shareable::SharedMem: shmget $key: $!\n\n" .
72             "Are you using exclusive, but trying to create multiple " .
73             "instances?\n\n";
74             }
75              
76 4         294 return undef;
77             }
78             };
79              
80 596         1844 $self->id($id);
81              
82 596         3057 return $self;
83             }
84             sub id {
85 10294     10294 1 46972 my ($self, $id) = @_;
86              
87 10294 100       19717 if (defined $id) {
88 597 100       1590 if ($self->{id}) {
89 1         15 warn "Can't set id() after object already instantiated";
90 1         8 return $self->{id};
91             }
92 596         2473 $self->{id} = $id;
93             }
94 10293         35216 return $self->{id};
95             }
96             sub key {
97 1855     1855 1 9796 my ($self, $key) = @_;
98              
99 1855 100       4113 if (defined $key) {
100 608 100       1749 if ($self->id) {
101 1         221 croak "Can't set the 'key' attribute after object is already established";
102             }
103              
104 607         2229 $self->{key} = $key;
105             }
106              
107 1854         5544 return $self->{key};
108             }
109             sub key_hex {
110 1104     1104 1 2640 my ($self, $key_int) = @_;
111              
112 1104 100       3017 if (defined $key_int) {
113 607         3496 $self->{key_hex} = sprintf "0x%08x", $key_int;
114             }
115              
116 1104         13798 return $self->{key_hex};
117             }
118             sub flags {
119 2077     2077 1 12121 my ($self, $flags) = @_;
120              
121 2077 100       4370 if (defined $flags) {
122 607 100       1314 if ($self->id) {
123 1         18 warn "Can't set flags() after object already instantiated";
124 1         18 return $self->{flags};
125             }
126              
127 606         1294 $self->{flags} = $flags;
128             }
129 2076         28866 return $self->{flags};
130             }
131             sub mode {
132 1216     1216 1 3951 my ($self, $mode) = @_;
133              
134 1216 100       2489 if (defined $mode) {
135 607 100       1321 if ($self->id) {
136 1         20 warn "Can't set mode() after object already instantiated";
137 1         10 return $self->{mode};
138             }
139              
140 606         1645 $self->{mode} = $mode;
141             }
142              
143 1215         3467 return $self->{mode};
144             }
145             sub size {
146 6148     6148 1 12889 my ($self, $size) = @_;
147              
148 6148 100       12569 if (defined $size) {
149 608 100       1523 if ($self->id) {
150 1         35 warn "Can't set size() after object already instantiated";
151 1         14 return $self->{size};
152             }
153 607 100       3720 if ($size !~ /^\d+$/) {
154 1         222 croak "size() requires an integer as parameter";
155             }
156              
157 606         2025 $self->{size} = $size;
158             }
159 6146         743352 return $self->{size};
160             }
161             sub type {
162 609     609 1 2465 my ($self, $type) = @_;
163              
164 609 100       3627 if (defined $type) {
165 501 100       1128 if ($self->id) {
166 1         17 warn "Can't set type() after object already instantiated";
167 1         9 return $self->{type};
168             }
169              
170 500         1586 $self->{type} = $type;
171             }
172              
173 608         1215 return $self->{type};
174             }
175             sub data {
176 1478     1478 1 2804 my ($self) = @_;
177              
178 1478         4151 my $data = $self->shmread;
179              
180 1478 100       3898 return if ! defined $data;
181              
182 1472         3122 my $pos = index($data, "\x00");
183 1472 50       4448 $data = $pos >= 0 ? substr($data, 0, $pos) : $data;
184              
185 1472         5252 return $data;
186             }
187             sub stat {
188 19     19 1 25898 my ($self) = @_;
189 19         46 my $data = '';
190 19 100       78 shmctl($self->id, IPC_STAT, $data) or return undef;
191              
192 18         237 my %values;
193              
194 18 50 0     83 if ($^O eq 'linux') {
    0          
    0          
195 18 50       414 if ($Config{longsize} == 8) {
196             # 64-bit Linux: ipc64_perm is 48 bytes.
197             # ipc64_perm: key(4) uid(4) gid(4) cuid(4) cgid(4) mode(4)
198             # seq(2) pad2(2) [4-byte align-pad] unused1(8) unused2(8)
199             # shmid_ds: segsz(8) atime(8) dtime(8) ctime(8) cpid(4) lpid(4) nattch(8)
200              
201 18         220 @values{qw(uid gid cuid cgid mode segsz atime dtime ctime cpid lpid nattch)}
202             = unpack('x[4] L L L L L x[24] Q q q q l l Q', $data);
203             }
204             else {
205             # 32-bit Linux: ipc64_perm is 36 bytes (unsigned long = 4 bytes).
206             # ipc64_perm: key(4) uid(4) gid(4) cuid(4) cgid(4) mode(4)
207             # seq(2) pad2(2) unused1(4) unused2(4)
208             # shmid_ds: segsz(4) atime(4) atime_nsec(4) dtime(4) dtime_nsec(4)
209             # ctime(4) ctime_nsec(4) cpid(4) lpid(4) nattch(4)
210              
211 0         0 @values{qw(uid gid cuid cgid mode segsz atime dtime ctime cpid lpid nattch)}
212             = unpack('x[4] L L L L L x[12] L L x[4] L x[4] L x[4] l l L', $data);
213             }
214             }
215             elsif ($^O eq 'freebsd' && $Config{longsize} == 8) {
216             # 64-bit FreeBSD: ipc_perm is 32 bytes.
217             # ipc_perm: cuid(4) cgid(4) uid(4) gid(4) mode(2) _seq(2) pad(4) _key(8)
218             # shmid_ds: segsz(8) lpid(4) cpid(4) nattch(8) atime(8) dtime(8) ctime(8)
219             # (key_t = long = 8 bytes on FreeBSD 64-bit, with 4 bytes of alignment padding)
220              
221 0         0 @values{qw(cuid cgid uid gid mode segsz lpid cpid nattch atime dtime ctime)}
222             = unpack('L L L L S x[14] Q l l Q q q q', $data);
223             }
224             elsif ($^O eq 'solaris') {
225 0 0       0 if ($Config{longsize} == 8) {
226             # 64-bit Solaris/illumos _LP64 shmid_ds (136 bytes on OmniOS r151058):
227             # ipc_perm (28 bytes): uid(4) gid(4) cuid(4) cgid(4) mode(4) seq(4) key(4)
228             # [pad 4] segsz(8) [gap 8] lkcnt(2) [pad 2] lpid(4) cpid(4)
229             # [pad 4] nattch(8) cnattch(8) atime(8) dtime(8) ctime(8)
230             # shmatt_t = 8 bytes mode_t = uint_t = 4 bytes
231             # Offsets verified on OmniOS r151058 via offsetof().
232              
233 0         0 @values{qw(uid gid cuid cgid mode segsz lpid cpid nattch atime dtime ctime)}
234             = unpack('L L L L L x[12] Q x[12] l l x[4] Q x[8] q q q', $data);
235             }
236             else {
237             # 32-bit Solaris/illumos shmid_ds (108 bytes):
238             # ipc_perm (44 bytes): uid(4) gid(4) cuid(4) cgid(4) mode(4) seq(4) key(4) pad[4](16)
239             # segsz(4) lpid(4) cpid(4) lkcnt(2) [pad 2] nattch(4) cnattch(4)
240             # atime(4) pad1(4) dtime(4) pad2(4) ctime(4) pad3(4) pad4[4](16)
241             # mode_t = uint_t = 4 bytes
242              
243 0         0 @values{qw(uid gid cuid cgid mode segsz lpid cpid nattch atime dtime ctime)}
244             = unpack('L4 L x[24] L l l x[4] L x[4] l x[4] l x[4] l x[20]', $data);
245             }
246             }
247             else {
248             # macOS/BSD shmid_ds / ipc_perm layout:
249             #
250             # ipc_perm (24 bytes): uid(4) gid(4) cuid(4) cgid(4) mode(2/ushort) seq(2) key(4)
251             # shmid_ds: segsz(8) lpid(4) cpid(4) nattch(2/ushort) [pad 2] atime(8) dtime(8) ctime(8)
252             #
253             # Fields happen to match stat_list() order, so a linear unpack works.
254              
255 0         0 @values{stat_list()} = unpack('L L L L S x[6] Q l l S x[2] q q q', $data);
256             }
257              
258 18         60 my @struct_initializers;
259 18         43 for (stat_list()) {
260 216         364 my $value = $values{$_};
261 216 100       429 if ($_ eq 'mode') {
262 18         45 $value = $value & 0777;
263 18         85 push @struct_initializers, $_ => sprintf("%#o", $value);
264             }
265             else {
266 198         404 push @struct_initializers, $_ => $value;
267             }
268             }
269              
270 18         780 return IPC::Shareable::SharedMem::stat->new(@struct_initializers);
271             }
272             sub stats {
273 1     1 1 8 my ($self) = @_;
274 1         23 my @stat_list = stat_list();
275              
276 1         6 my $stat = $self->stat;
277              
278 1         210 my %stats;
279              
280 1         4 for (@stat_list) {
281 12         307 $stats{$_} = $stat->$_;
282             }
283              
284 1         37 return \%stats;
285             }
286             sub stat_list {
287 20     20 1 116 return qw(
288             uid
289             gid
290             cuid
291             cgid
292             mode
293             segsz
294             lpid
295             cpid
296             nattch
297             atime
298             dtime
299             ctime
300             );
301             }
302              
303             sub shmread {
304 3087     3087 1 5426 my ($self) = @_;
305              
306 3087         5761 my $data = '';
307 3087 100       8174 shmread($self->id, $data, 0, $self->size) or return;
308 3074         26250 return $data;
309             }
310             sub shmwrite {
311 922     922 1 2065 my($self, $data) = @_;
312 922         2334 return shmwrite($self->id, $data, 0, $self->size);
313             }
314             sub remove {
315 441     441 1 993 my ($self) = @_;
316 441         1120 my $os_return_value = shmctl($self->id, IPC_RMID, 0);
317              
318 441 100 33     28282 if (defined $os_return_value && ($os_return_value eq '0 but true' || $os_return_value == 1)) {
      66        
319 440         2711 return 1;
320             }
321             else {
322 1         5 return 0;
323             }
324             }
325              
326             1;
327              
328             =head1 NAME
329              
330             IPC::Shareable::SharedMem - Allows access to a shared memory segment via an
331             object oriented interface.
332              
333             =head1 DESCRIPTION
334              
335             This module provides object oriented access to a shared memory segment. Although
336             it can be used standalone, it was designed for use specifically within the
337             L<< IPC::Shareable >> library.
338              
339             =for html
340            
341             Coverage Status
342              
343             =head1 SYNOPSIS
344              
345             =head1 METHODS
346              
347             =head2 new(%params)
348              
349             Instantiates and returns an object that represents a shared memory segment.
350              
351             If for any reason we can't create the shared memory segment, we'll return
352             C.
353              
354             Parameters (must be in key => value pairs):
355              
356             =head3 key
357              
358             I<< Mandatory, Integer >>: An integer that references the shared memory segment.
359              
360             =head3 size
361              
362             I: An integer representing the size in bytes of the
363             shared memory segment. The maximum is Operating System independent.
364              
365             I: 1024
366              
367             =head3 flags
368              
369             I: A bitwise mask of options logically OR'd together
370             with any or all of C (create segment if it doesn't exist),
371             C (exclusive access; if the segment already exists,
372             we'll C) and C (create a read only segment).
373              
374             See L for further details.
375              
376             I: C<0> (ie. no flags).
377              
378             =head3 mode
379              
380             I: An octal number representing the access permissions
381             for the shared memory segment. Exactly the same as a Unix file system
382             permissions.
383              
384             I: 0666 (User RW, Group RW, World RW).
385              
386             =head3 type
387              
388             I: The type of data that will be stored in the shared memory
389             segment. L uses C, C or C.
390              
391             =head2 id
392              
393             Sets/gets the identification number that references the shared memory segment.
394              
395             A warning will be thrown if you try to set the ID after the object is already
396             instantiated, and no change will occur.
397              
398             =head2 key
399              
400             Sets/gets the key used to identify the shared memory segment.
401              
402             Setting this attribute should only be done internally. If it is sent in after
403             the object is already associated with a shared memory segment, we will C.
404              
405             See L for further details.
406              
407             =head2 key_hex($key)
408              
409             Returns the hex formatted key which appears in C calls.
410              
411             Parameters:
412              
413             =head3 $key
414              
415             I<< Optional, String >>: This is always sent in during initialization.
416              
417             =head2 size
418              
419             Sets/gets the size of the shared memory segment in bytes. See L for
420             further details.
421              
422             A warning will be thrown if you try to set the size after the object is already
423             instantiated, and no change will occur.
424              
425             =head2 flags
426              
427             Sets/gets the flags that the segment will be created with. See L for
428             details.
429              
430             A warning will be thrown if you try to set the flags after the object is already
431             instantiated, and no change will occur.
432              
433             =head2 mode
434              
435             Sets/gets the access permissions. See L for further details.
436              
437             A warning will be thrown if you try to set the mode after the object is already
438             instantiated, and no change will occur.
439              
440             =head2 type
441              
442             Sets/gets the type of data that will be contained in the shared memory segment.
443             See L for details.
444              
445             A warning will be thrown if you try to set the type after the object is already
446             instantiated, and no change will occur.
447              
448             =head2 data
449              
450             Returns the data in the shared memory segment, with all NULL pad bytes removed.
451              
452             Use this method for text data. For binary data where you need all blocks within
453             the segment, use the L method.
454              
455             =head2 stat
456              
457             This method has sub methods that display various system-level information about
458             the memory segment. These sub methods are:
459              
460             uid
461             gid
462             cuid
463             cgid
464             mode
465             segsz
466             lpid
467             cpid
468             nattch
469             atime
470             dtime
471             ctime
472              
473             Example call:
474              
475             my $ctime = $seg->stat->ctime;
476              
477             =head2 stats
478              
479             Returns an href of the various system-level stat information:
480              
481             {
482             uid => 501,
483             gid => 20,
484             cuid => 501,
485             cgid => 20,
486             mode => 0666,
487             segsz => 65536,
488             lpid => 61270,
489             cpid => 61270,
490             nattch => 0,
491             atime => 1778791348,
492             dtime => 1778791348,
493             ctime => 1778791348,
494             }
495              
496             =head2 stat_list
497              
498             Returns an array of all the segment's system stat entries. These are what make
499             up the method names of the C<< $seg->stat >> object.
500              
501             =head2 shmread
502              
503             Returns the data (and NULL pad bytes) stored in the shared memory segment.
504              
505             By default, when data is retrieved from the shared memory segment, the data
506             is padded to the right by NULL bytes to fill up the entire size of the segment.
507             This can cause issues when using the space for non serialized data (ie. if you
508             stored "hello" in a 1024 byte segment, the ASCII text wouldn't match).
509              
510             Typically this method is used when you want all blocks of the segment, such as
511             if you've stored binary data.
512              
513             For text/ASCII data, use the L method.
514              
515             Send in a true value as this parameter and we'll clean the NULLs for you.
516              
517             I: The data if any is stored, empty string if no data has been stored
518             yet, and C if a failure to read occurs.
519              
520             =head2 shmwrite($data)
521              
522             Stores the serialized data to the shared memory segment.
523              
524             Parameters:
525              
526             $data
527              
528             I: Typically, the a serialized data structure.
529              
530             I: True on success, false on failure.
531              
532             =head2 remove
533              
534             Removes the shared memory segment and returns the resources to the system.
535              
536             I: True (C<1>) on success, false (C<0>) on failure.
537              
538             =head1 AUTHOR
539              
540             Ben Sugars (bsugars@canoe.ca)
541              
542             =head1 MAINTAINED BY
543              
544             Steve Bertrand
545              
546             =head1 SEE ALSO
547              
548             L, L L