File Coverage

blib/lib/IPC/Shareable/SharedMem.pm
Criterion Covered Total %
statement 133 139 95.6
branch 49 58 84.4
condition 17 24 70.8
subroutine 24 24 100.0
pod 15 15 100.0
total 238 260 91.5


line stmt bran cond sub pod time code
1             package IPC::Shareable::SharedMem;
2              
3 78     78   472 use warnings;
  78         104  
  78         4016  
4 78     78   322 use strict;
  78         116  
  78         1728  
5              
6 78     78   262 use Carp qw(carp croak confess);
  78         106  
  78         3706  
7 78     78   323 use Config;
  78         108  
  78         2638  
8 78     78   1792 use Data::Dumper;
  78         1554  
  78         5009  
9 78     78   346 use Errno qw(EEXIST EPERM);
  78         137  
  78         3226  
10 78     78   607 use IPC::SysV qw(IPC_RMID IPC_STAT);
  78         249  
  78         4593  
11              
12             our $VERSION = '1.14_09';
13              
14             use constant {
15 78         7290 DEFAULT_SEG_SIZE => 1024,
16             DEFAULT_SEG_FLAGS => 0000,
17             DEFAULT_SEG_MODE => 0666,
18 78     78   380 };
  78         143  
19              
20             {
21             package IPC::Shareable::SharedMem::stat;
22              
23 78     78   528 use Class::Struct qw(struct);
  78         130  
  78         398  
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 604     604 1 13804 my ($class, %params) = @_;
43              
44 604         1834 my $self = bless {}, $class;
45              
46 604 100 100     3949 if (defined $params{key} && $params{key} =~ /^0x[0-9a-fA-F]+$/i) {
47 1         3 $params{key} = hex($params{key});
48             }
49              
50 604 100 100     5034 if (! defined $params{key} || $params{key} !~ /^\d+$/) {
51 2         454 croak "new() requires a 'key' parameter with an integer value";
52             }
53              
54 602         2165 $self->key($params{key});
55 602         1012 $self->key_hex($self->key);
56              
57 602   100     2470 $self->size($params{size} || DEFAULT_SEG_SIZE);
58              
59 601   100     2283 $self->mode($params{mode} || DEFAULT_SEG_MODE);
60 601   100     1846 $self->flags(($params{flags} || DEFAULT_SEG_FLAGS) | $self->mode);
61              
62 601         1661 $self->type($params{type});
63              
64 601         1057 my $id = shmget($self->key, $self->size, $self->flags);
65              
66 601 100       1787 defined $id or do {
67 10         27 my $key = $self->key_hex;
68              
69 10 50       127 if ($!) {
70 10 100 66     229 if ($!{EEXIST} || $!{EPERM}) {
71 6         1721 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         209 return undef;
77             }
78             };
79              
80 591         1292 $self->id($id);
81              
82 591         2085 return $self;
83             }
84             sub id {
85 10218     10218 1 28896 my ($self, $id) = @_;
86              
87 10218 100       15058 if (defined $id) {
88 592 100       1217 if ($self->{id}) {
89 1         11 warn "Can't set id() after object already instantiated";
90 1         5 return $self->{id};
91             }
92 591         1983 $self->{id} = $id;
93             }
94 10217         25765 return $self->{id};
95             }
96             sub key {
97 1840     1840 1 5753 my ($self, $key) = @_;
98              
99 1840 100       2957 if (defined $key) {
100 603 100       1455 if ($self->id) {
101 1         164 croak "Can't set the 'key' attribute after object is already established";
102             }
103              
104 602         1530 $self->{key} = $key;
105             }
106              
107 1839         3949 return $self->{key};
108             }
109             sub key_hex {
110 1094     1094 1 1861 my ($self, $key_int) = @_;
111              
112 1094 100       1839 if (defined $key_int) {
113 602         2393 $self->{key_hex} = sprintf "0x%08x", $key_int;
114             }
115              
116 1094         8646 return $self->{key_hex};
117             }
118             sub flags {
119 2057     2057 1 8052 my ($self, $flags) = @_;
120              
121 2057 100       3000 if (defined $flags) {
122 602 100       975 if ($self->id) {
123 1         11 warn "Can't set flags() after object already instantiated";
124 1         6 return $self->{flags};
125             }
126              
127 601         1096 $self->{flags} = $flags;
128             }
129 2056         17929 return $self->{flags};
130             }
131             sub mode {
132 1206     1206 1 2403 my ($self, $mode) = @_;
133              
134 1206 100       1889 if (defined $mode) {
135 602 100       1233 if ($self->id) {
136 1         11 warn "Can't set mode() after object already instantiated";
137 1         6 return $self->{mode};
138             }
139              
140 601         1278 $self->{mode} = $mode;
141             }
142              
143 1205         2473 return $self->{mode};
144             }
145             sub size {
146 6104     6104 1 10835 my ($self, $size) = @_;
147              
148 6104 100       9468 if (defined $size) {
149 603 100       1027 if ($self->id) {
150 1         22 warn "Can't set size() after object already instantiated";
151 1         9 return $self->{size};
152             }
153 602 100       2755 if ($size !~ /^\d+$/) {
154 1         113 croak "size() requires an integer as parameter";
155             }
156              
157 601         1788 $self->{size} = $size;
158             }
159 6102         520984 return $self->{size};
160             }
161             sub type {
162 604     604 1 1569 my ($self, $type) = @_;
163              
164 604 100       1155 if (defined $type) {
165 496 100       795 if ($self->id) {
166 1         27 warn "Can't set type() after object already instantiated";
167 1         7 return $self->{type};
168             }
169              
170 495         1082 $self->{type} = $type;
171             }
172              
173 603         866 return $self->{type};
174             }
175             sub data {
176 1478     1478 1 2226 my ($self) = @_;
177              
178 1478         2870 my $data = $self->shmread;
179              
180 1478 100       3136 return if ! defined $data;
181              
182             # Remove \x{0} (NULL bytes) after end of string
183 1472         24536 $data =~ s/\x00+//;
184              
185 1472         3982 return $data;
186             }
187             sub stat {
188 30     30 1 17259 my ($self) = @_;
189 30         41 my $data = '';
190 30 100       66 shmctl($self->id, IPC_STAT, $data) or return undef;
191              
192 29         206 my %values;
193              
194 29 50 0     69 if ($^O eq 'linux') {
    0          
    0          
195 29 50       312 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 29         237 @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 29         57 my @struct_initializers;
259 29         45 for (stat_list()) {
260 348         418 my $value = $values{$_};
261 348 100       417 if ($_ eq 'mode') {
262 29         38 $value = $value & 0777;
263 29         80 push @struct_initializers, $_ => sprintf("%#o", $value);
264             }
265             else {
266 319         383 push @struct_initializers, $_ => $value;
267             }
268             }
269              
270 29         662 return IPC::Shareable::SharedMem::stat->new(@struct_initializers);
271             }
272             sub stats {
273 1     1 1 5 my ($self) = @_;
274 1         2 my @stat_list = stat_list();
275              
276 1         2 my %stats;
277              
278 1         4 for (@stat_list) {
279 12         718 $stats{$_} = $self->stat->$_;
280             }
281              
282 1         59 return \%stats;
283             }
284             sub stat_list {
285 31     31 1 126 return qw(
286             uid
287             gid
288             cuid
289             cgid
290             mode
291             segsz
292             lpid
293             cpid
294             nattch
295             atime
296             dtime
297             ctime
298             );
299             }
300              
301             sub shmread {
302 3065     3065 1 4700 my ($self) = @_;
303              
304 3065         4828 my $data = '';
305 3065 100       6312 shmread($self->id, $data, 0, $self->size) or return;
306 3052         16104 return $data;
307             }
308             sub shmwrite {
309 916     916 1 1453 my($self, $data) = @_;
310 916         1644 return shmwrite($self->id, $data, 0, $self->size);
311             }
312             sub remove {
313 436     436 1 771 my ($self) = @_;
314 436         735 my $os_return_value = shmctl($self->id, IPC_RMID, 0);
315              
316 436 100 33     25759 if (defined $os_return_value && ($os_return_value eq '0 but true' || $os_return_value == 1)) {
      66        
317 435         1733 return 1;
318             }
319             else {
320 1         3 return 0;
321             }
322             }
323              
324             1;
325              
326             =head1 NAME
327              
328             IPC::Shareable::SharedMem - Allows access to a shared memory segment via an
329             object oriented interface.
330              
331             =head1 DESCRIPTION
332              
333             This module provides object oriented access to a shared memory segment. Although
334             it can be used standalone, it was designed for use specifically within the
335             L<< IPC::Shareable >> library.
336              
337             =for html
338            
339             Coverage Status
340              
341             =head1 SYNOPSIS
342              
343             =head1 METHODS
344              
345             =head2 new(%params)
346              
347             Instantiates and returns an object that represents a shared memory segment.
348              
349             If for any reason we can't create the shared memory segment, we'll return
350             C.
351              
352             Parameters (must be in key => value pairs):
353              
354             =head3 key
355              
356             I<< Mandatory, Integer >>: An integer that references the shared memory segment.
357              
358             =head3 size
359              
360             I: An integer representing the size in bytes of the
361             shared memory segment. The maximum is Operating System independent.
362              
363             I: 1024
364              
365             =head3 flags
366              
367             I: A bitwise mask of options logically OR'd together
368             with any or all of C (create segment if it doesn't exist),
369             C (exclusive access; if the segment already exists,
370             we'll C) and C (create a read only segment).
371              
372             See L for further details.
373              
374             I: C<0> (ie. no flags).
375              
376             =head3 mode
377              
378             I: An octal number representing the access permissions
379             for the shared memory segment. Exactly the same as a Unix file system
380             permissions.
381              
382             I: 0666 (User RW, Group RW, World RW).
383              
384             =head3 type
385              
386             I: The type of data that will be stored in the shared memory
387             segment. L uses C, C or C.
388              
389             =head2 id
390              
391             Sets/gets the identification number that references the shared memory segment.
392              
393             A warning will be thrown if you try to set the ID after the object is already
394             instantiated, and no change will occur.
395              
396             =head2 key
397              
398             Sets/gets the key used to identify the shared memory segment.
399              
400             Setting this attribute should only be done internally. If it is sent in after
401             the object is already associated with a shared memory segment, we will C.
402              
403             See L for further details.
404              
405             =head2 key_hex($key)
406              
407             Returns the hex formatted key which appears in C calls.
408              
409             Parameters:
410              
411             =head3 $key
412              
413             I<< Optional, String >>: This is always sent in during initialization.
414              
415             =head2 size
416              
417             Sets/gets the size of the shared memory segment in bytes. See L for
418             further details.
419              
420             A warning will be thrown if you try to set the size after the object is already
421             instantiated, and no change will occur.
422              
423             =head2 flags
424              
425             Sets/gets the flags that the segment will be created with. See L for
426             details.
427              
428             A warning will be thrown if you try to set the flags after the object is already
429             instantiated, and no change will occur.
430              
431             =head2 mode
432              
433             Sets/gets the access permissions. See L for further details.
434              
435             A warning will be thrown if you try to set the mode after the object is already
436             instantiated, and no change will occur.
437              
438             =head2 type
439              
440             Sets/gets the type of data that will be contained in the shared memory segment.
441             See L for details.
442              
443             A warning will be thrown if you try to set the type after the object is already
444             instantiated, and no change will occur.
445              
446             =head2 data
447              
448             Returns the data in the shared memory segment, with all NULL pad bytes removed.
449              
450             Use this method for text data. For binary data where you need all blocks within
451             the segment, use the L method.
452              
453             =head2 stat
454              
455             This method has sub methods that display various system-level information about
456             the memory segment. These sub methods are:
457              
458             uid
459             gid
460             cuid
461             cgid
462             mode
463             segsz
464             lpid
465             cpid
466             nattch
467             atime
468             dtime
469             ctime
470              
471             Example call:
472              
473             my $ctime = $seg->stat->ctime;
474              
475             =head2 stats
476              
477             Returns an href of the various system-level stat information:
478              
479             {
480             uid => 501,
481             gid => 20,
482             cuid => 501,
483             cgid => 20,
484             mode => 0666,
485             segsz => 65536,
486             lpid => 61270,
487             cpid => 61270,
488             nattch => 0,
489             atime => 1778791348,
490             dtime => 1778791348,
491             ctime => 1778791348,
492             }
493              
494             =head2 stat_list
495              
496             Returns an array of all the segment's system stat entries. These are what make
497             up the method names of the C<< $seg->stat >> object.
498              
499             =head2 shmread
500              
501             Returns the data (and NULL pad bytes) stored in the shared memory segment.
502              
503             By default, when data is retrieved from the shared memory segment, the data
504             is padded to the right by NULL bytes to fill up the entire size of the segment.
505             This can cause issues when using the space for non serialized data (ie. if you
506             stored "hello" in a 1024 byte segment, the ASCII text wouldn't match).
507              
508             Typically this method is used when you want all blocks of the segment, such as
509             if you've stored binary data.
510              
511             For text/ASCII data, use the L method.
512              
513             Send in a true value as this parameter and we'll clean the NULLs for you.
514              
515             I: The data if any is stored, empty string if no data has been stored
516             yet, and C if a failure to read occurs.
517              
518             =head2 shmwrite($data)
519              
520             Stores the serialized data to the shared memory segment.
521              
522             Parameters:
523              
524             $data
525              
526             I: Typically, the a serialized data structure.
527              
528             I: True on success, false on failure.
529              
530             =head2 remove
531              
532             Removes the shared memory segment and returns the resources to the system.
533              
534             I: True (C<1>) on success, false (C<0>) on failure.
535              
536             =head1 AUTHOR
537              
538             Ben Sugars (bsugars@canoe.ca)
539              
540             =head1 MAINTAINED BY
541              
542             Steve Bertrand
543              
544             =head1 SEE ALSO
545              
546             L, L L