File Coverage

blib/lib/IPC/Shareable/SharedMem.pm
Criterion Covered Total %
statement 132 142 92.9
branch 50 66 75.7
condition 17 30 56.6
subroutine 23 23 100.0
pod 15 15 100.0
total 237 276 85.8


line stmt bran cond sub pod time code
1             package IPC::Shareable::SharedMem;
2              
3 88     88   557 use warnings;
  88         153  
  88         4171  
4 88     88   329 use strict;
  88         139  
  88         2063  
5              
6 88     88   301 use Carp qw(carp croak confess);
  88         118  
  88         4145  
7 88     88   317 use Config;
  88         99  
  88         2937  
8 88     88   387 use Errno qw(EEXIST EPERM);
  88         156  
  88         3608  
9 88     88   380 use IPC::SysV qw(IPC_RMID IPC_STAT);
  88         314  
  88         6973  
10              
11             our $VERSION = '1.18';
12              
13             use constant {
14 88         12137 DEFAULT_SEG_SIZE => 1024,
15             DEFAULT_SEG_FLAGS => 0000,
16             DEFAULT_SEG_MODE => 0666,
17 88     88   370 };
  88         131  
18              
19             {
20             package IPC::Shareable::SharedMem::stat;
21              
22 88     88   565 use Class::Struct qw(struct);
  88         1686  
  88         381  
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 735     735 1 12637 my ($class, %params) = @_;
42              
43 735         1811 my $self = bless {}, $class;
44              
45 735 100 100     3962 if (defined $params{key} && $params{key} =~ /^0x[0-9a-fA-F]+$/i) {
46 1         3 $params{key} = hex($params{key});
47             }
48              
49 735 100 100     4813 if (! defined $params{key} || $params{key} !~ /^\d+$/) {
50 2         210 croak "new() requires a 'key' parameter with an integer value";
51             }
52              
53 733         2305 $self->key($params{key});
54 733         1241 $self->key_hex($self->key);
55              
56 733   100     2530 $self->size($params{size} || DEFAULT_SEG_SIZE);
57              
58 732   100     2623 $self->mode($params{mode} || DEFAULT_SEG_MODE);
59 732   100     2060 $self->flags(($params{flags} || DEFAULT_SEG_FLAGS) | $self->mode);
60              
61 732         1884 $self->type($params{type});
62              
63 732         1156 my $id = shmget($self->key, $self->size, $self->flags);
64              
65 732 100       2087 defined $id or do {
66 10         22 my $key = $self->key_hex;
67              
68 10 50       95 if ($!) {
69 10 100 66     76 if ($!{EEXIST} || $!{EPERM}) {
70 6         1113 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         142 return undef;
76             }
77             };
78              
79 722         1639 $self->id($id);
80              
81 722         2339 return $self;
82             }
83             sub id {
84 13129     13129 1 26660 my ($self, $id) = @_;
85              
86 13129 100       17803 if (defined $id) {
87 728 100       1202 if ($self->{id}) {
88 1         10 warn "Can't set id() after object already instantiated";
89 1         6 return $self->{id};
90             }
91 727         1523 $self->{id} = $id;
92             }
93 13128         28272 return $self->{id};
94             }
95             sub key {
96 2233     2233 1 5428 my ($self, $key) = @_;
97              
98 2233 100       3219 if (defined $key) {
99 734 100       1441 if ($self->id) {
100 1         105 croak "Can't set the 'key' attribute after object is already established";
101             }
102              
103 733         1680 $self->{key} = $key;
104             }
105              
106 2232         4351 return $self->{key};
107             }
108             sub key_hex {
109 1307     1307 1 2117 my ($self, $key_int) = @_;
110              
111 1307 100       1976 if (defined $key_int) {
112 733         2766 $self->{key_hex} = sprintf "0x%08x", $key_int;
113             }
114              
115 1307         8204 return $self->{key_hex};
116             }
117             sub flags {
118 2478     2478 1 9430 my ($self, $flags) = @_;
119              
120 2478 100       3411 if (defined $flags) {
121 733 100       1127 if ($self->id) {
122 1         11 warn "Can't set flags() after object already instantiated";
123 1         5 return $self->{flags};
124             }
125              
126 732         981 $self->{flags} = $flags;
127             }
128 2477         28412 return $self->{flags};
129             }
130             sub mode {
131 1468     1468 1 2353 my ($self, $mode) = @_;
132              
133 1468 100       2020 if (defined $mode) {
134 733 100       1035 if ($self->id) {
135 1         11 warn "Can't set mode() after object already instantiated";
136 1         5 return $self->{mode};
137             }
138              
139 732         1206 $self->{mode} = $mode;
140             }
141              
142 1467         2866 return $self->{mode};
143             }
144             sub size {
145 7202     7202 1 9920 my ($self, $size) = @_;
146              
147 7202 100       10841 if (defined $size) {
148 734 100       1105 if ($self->id) {
149 1         14 warn "Can't set size() after object already instantiated";
150 1         6 return $self->{size};
151             }
152 733 100       2680 if ($size !~ /^\d+$/) {
153 1         100 croak "size() requires an integer as parameter";
154             }
155              
156 732         1397 $self->{size} = $size;
157             }
158 7200         560056 return $self->{size};
159             }
160             sub type {
161 735     735 1 1682 my ($self, $type) = @_;
162              
163 735 100       1250 if (defined $type) {
164 582 100       835 if ($self->id) {
165 1         11 warn "Can't set type() after object already instantiated";
166 1         6 return $self->{type};
167             }
168              
169 581         1167 $self->{type} = $type;
170             }
171              
172 734         968 return $self->{type};
173             }
174             sub data {
175 1722     1722 1 2277 my ($self) = @_;
176              
177 1722         3546 my $data = $self->shmread;
178              
179 1722 100       3114 return if ! defined $data;
180              
181 1716         3079 my $pos = index($data, "\x00");
182 1716 50       4106 $data = $pos >= 0 ? substr($data, 0, $pos) : $data;
183              
184 1716         5436 return $data;
185             }
186             sub stat {
187 24     24 1 14181 my ($self) = @_;
188 24         55 my $data = '';
189 24 100       40 shmctl($self->id, IPC_STAT, $data) or return undef;
190              
191 23         198 my %values;
192              
193 23 50 0     79 if ($^O eq 'linux') {
    0 0        
    0 0        
    0          
    0          
194 23 50       422 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 23         276 @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             elsif ($^O eq 'solaris') {
224 0 0       0 if ($Config{longsize} == 8) {
225             # 64-bit Solaris/illumos _LP64 shmid_ds (136 bytes on OmniOS r151058):
226             # ipc_perm (28 bytes): uid(4) gid(4) cuid(4) cgid(4) mode(4) seq(4) key(4)
227             # [pad 4] segsz(8) [gap 8] lkcnt(2) [pad 2] lpid(4) cpid(4)
228             # [pad 4] nattch(8) cnattch(8) atime(8) dtime(8) ctime(8)
229             # shmatt_t = 8 bytes mode_t = uint_t = 4 bytes
230             # Offsets verified on OmniOS r151058 via offsetof().
231              
232 0         0 @values{qw(uid gid cuid cgid mode segsz lpid cpid nattch atime dtime ctime)}
233             = unpack('L L L L L x[12] Q x[12] l l x[4] Q x[8] q q q', $data);
234             }
235             else {
236             # 32-bit Solaris/illumos shmid_ds (108 bytes):
237             # ipc_perm (44 bytes): uid(4) gid(4) cuid(4) cgid(4) mode(4) seq(4) key(4) pad[4](16)
238             # segsz(4) lpid(4) cpid(4) lkcnt(2) [pad 2] nattch(4) cnattch(4)
239             # atime(4) pad1(4) dtime(4) pad2(4) ctime(4) pad3(4) pad4[4](16)
240             # mode_t = uint_t = 4 bytes
241              
242 0         0 @values{qw(uid gid cuid cgid mode segsz lpid cpid nattch atime dtime ctime)}
243             = unpack('L4 L x[24] L l l x[4] L x[4] l x[4] l x[4] l x[20]', $data);
244             }
245             }
246             elsif ($^O eq 'openbsd' && $Config{longsize} == 8) {
247             # 64-bit OpenBSD shmid_ds (104 bytes), struct layout from sys/shm.h:
248             # ipc_perm (32 bytes): uid(4) gid(4) cuid(4) cgid(4) mode(4/int)
249             # +12 bytes (key/seq/pad)
250             # segsz(4/int) lpid(4/pid_t) cpid(4/pid_t) nattch(2/shmatt_t) [pad 2]
251             # atime(8/time_t) __shm_atimensec(8/long)
252             # dtime(8/time_t) __shm_dtimensec(8/long)
253             # ctime(8/time_t) __shm_ctimensec(8/long)
254             # shm_internal(8/ptr)
255              
256 0         0 @values{qw(uid gid cuid cgid mode segsz lpid cpid nattch atime dtime ctime)}
257             = unpack('L L L L L x[12] L l l S x[2] q x[8] q x[8] q', $data);
258             }
259             elsif ($^O eq 'dragonfly' && $Config{longsize} == 8) {
260             # 64-bit DragonFly BSD shmid_ds (sys/sys/shm.h, sys/sys/ipc.h).
261             # ipc_perm (28 bytes):
262             # uid(4) gid(4) cuid(4) cgid(4) mode(4) _seq(2) [2 pad] _key(4)
263             # [4 pad to align segsz]
264             # shmid_ds:
265             # segsz(8) lpid(4) cpid(4) nattch(8)
266             # atime(8) [atimensec(8)?] dtime(8) [dtimensec(8)?] ctime(8)
267             #
268             # Some DragonFly versions include __shm_*timensec fields (108 bytes
269             # total), others omit them (88 bytes). Detect via data length.
270              
271 0 0       0 if (length($data) > 96) {
272 0         0 @values{qw(uid gid cuid cgid mode segsz lpid cpid nattch atime dtime ctime)}
273             = unpack('L L L L L x[12] Q l l Q q x[8] q x[8] q', $data);
274             }
275             else {
276 0         0 @values{qw(uid gid cuid cgid mode segsz lpid cpid nattch atime dtime ctime)}
277             = unpack('L L L L L x[12] Q l l Q q q q', $data);
278             }
279             }
280             else {
281             # macOS shmid_ds / ipc_perm layout (XNU kernel):
282             #
283             # ipc_perm (24 bytes): uid(4) gid(4) cuid(4) cgid(4) mode(2/ushort) seq(2) key(4)
284             # shmid_ds: segsz(8) lpid(4) cpid(4) nattch(2/ushort) [pad 2] atime(8) dtime(8) ctime(8)
285             #
286             # Fields happen to match stat_list() order, so a linear unpack works.
287              
288 0         0 @values{stat_list()} = unpack('L L L L S x[6] Q l l S x[2] q q q', $data);
289             }
290              
291 23         46 my @struct_initializers;
292 23         51 for (stat_list()) {
293 276         297 my $value = $values{$_};
294 276 100       290 if ($_ eq 'mode') {
295 23         71 $value = $value & 0777;
296 23         78 push @struct_initializers, $_ => sprintf("%#o", $value);
297             }
298             else {
299 253         316 push @struct_initializers, $_ => $value;
300             }
301             }
302              
303 23         552 return IPC::Shareable::SharedMem::stat->new(@struct_initializers);
304             }
305             sub stats {
306 1     1 1 10 my ($self) = @_;
307 1         3 my @stat_list = stat_list();
308              
309 1         2 my $stat = $self->stat;
310              
311 1         89 my %stats;
312              
313 1         2 for (@stat_list) {
314 12         139 $stats{$_} = $stat->$_;
315             }
316              
317 1         11 return \%stats;
318             }
319             sub stat_list {
320 25     25 1 125 return qw(
321             uid
322             gid
323             cuid
324             cgid
325             mode
326             segsz
327             lpid
328             cpid
329             nattch
330             atime
331             dtime
332             ctime
333             );
334             }
335              
336             sub shmread {
337 3748     3748 1 5092 my ($self) = @_;
338              
339 3748         4572 my $data = '';
340 3748 100       6984 shmread($self->id, $data, 0, $self->size) or return;
341 3728         26230 return $data;
342             }
343             sub shmwrite {
344 993     993 1 1775 my($self, $data) = @_;
345 993         1575 return shmwrite($self->id, $data, 0, $self->size);
346             }
347             sub remove {
348 543     543 1 831 my ($self) = @_;
349 543         823 my $os_return_value = shmctl($self->id, IPC_RMID, 0);
350              
351 543 100 33     19361 if (defined $os_return_value && ($os_return_value eq '0 but true' || $os_return_value == 1)) {
      66        
352 542         2047 return 1;
353             }
354             else {
355 1         4 return 0;
356             }
357             }
358              
359             1;
360              
361             =head1 NAME
362              
363             IPC::Shareable::SharedMem - Allows access to a shared memory segment via an
364             object oriented interface.
365              
366             =head1 DESCRIPTION
367              
368             This module provides object oriented access to a shared memory segment. Although
369             it can be used standalone, it was designed for use specifically within the
370             L<< IPC::Shareable >> library.
371              
372             =for html
373            
374             Coverage Status
375              
376             =head1 SYNOPSIS
377              
378             use IPC::Shareable::SharedMem;
379              
380             my $seg = IPC::Shareable::SharedMem->new(
381             key => 1234,
382             size => 65536,
383             );
384              
385             $seg->shmwrite($data);
386              
387             my $data = $seg->data;
388              
389             =head1 METHODS
390              
391             =head2 new(%params)
392              
393             Instantiates and returns an object that represents a shared memory segment.
394              
395             If for any reason we can't create the shared memory segment, we'll return
396             C.
397              
398             Parameters (must be in key => value pairs):
399              
400             =head3 key
401              
402             I<< Mandatory, Integer >>: An integer that references the shared memory segment.
403              
404             =head3 size
405              
406             I: An integer representing the size in bytes of the
407             shared memory segment. The maximum is Operating System independent.
408              
409             I: 1024
410              
411             =head3 flags
412              
413             I: A bitwise mask of options logically OR'd together
414             with any or all of C (create segment if it doesn't exist),
415             C (exclusive access; if the segment already exists,
416             we'll C) and C (create a read only segment).
417              
418             See L for further details.
419              
420             I: C<0> (ie. no flags).
421              
422             =head3 mode
423              
424             I: An octal number representing the access permissions
425             for the shared memory segment. Exactly the same as a Unix file system
426             permissions.
427              
428             I: 0666 (User RW, Group RW, World RW).
429              
430             =head3 type
431              
432             I: The type of data that will be stored in the shared memory
433             segment. L uses C, C or C.
434              
435             =head2 id
436              
437             Sets/gets the identification number that references the shared memory segment.
438              
439             A warning will be thrown if you try to set the ID after the object is already
440             instantiated, and no change will occur.
441              
442             =head2 key
443              
444             Sets/gets the key used to identify the shared memory segment.
445              
446             Setting this attribute should only be done internally. If it is sent in after
447             the object is already associated with a shared memory segment, we will C.
448              
449             See L for further details.
450              
451             =head2 key_hex($key)
452              
453             Returns the hex formatted key which appears in C calls.
454              
455             Parameters:
456              
457             =head3 $key
458              
459             I<< Optional, String >>: This is always sent in during initialization.
460              
461             =head2 size
462              
463             Sets/gets the size of the shared memory segment in bytes. See L for
464             further details.
465              
466             A warning will be thrown if you try to set the size after the object is already
467             instantiated, and no change will occur.
468              
469             =head2 flags
470              
471             Sets/gets the flags that the segment will be created with. See L for
472             details.
473              
474             A warning will be thrown if you try to set the flags after the object is already
475             instantiated, and no change will occur.
476              
477             =head2 mode
478              
479             Sets/gets the access permissions. See L for further details.
480              
481             A warning will be thrown if you try to set the mode after the object is already
482             instantiated, and no change will occur.
483              
484             =head2 type
485              
486             Sets/gets the type of data that will be contained in the shared memory segment.
487             See L for details.
488              
489             A warning will be thrown if you try to set the type after the object is already
490             instantiated, and no change will occur.
491              
492             =head2 data
493              
494             Returns the data in the shared memory segment, with all NULL pad bytes removed.
495              
496             Use this method for text data. For binary data where you need all blocks within
497             the segment, use the L method.
498              
499             =head2 stat
500              
501             This method has sub methods that display various system-level information about
502             the memory segment. These sub methods are:
503              
504             uid
505             gid
506             cuid
507             cgid
508             mode
509             segsz
510             lpid
511             cpid
512             nattch
513             atime
514             dtime
515             ctime
516              
517             Example call:
518              
519             my $ctime = $seg->stat->ctime;
520              
521             =head2 stats
522              
523             Returns an href of the various system-level stat information:
524              
525             {
526             uid => 501,
527             gid => 20,
528             cuid => 501,
529             cgid => 20,
530             mode => 0666,
531             segsz => 65536,
532             lpid => 61270,
533             cpid => 61270,
534             nattch => 0,
535             atime => 1778791348,
536             dtime => 1778791348,
537             ctime => 1778791348,
538             }
539              
540             =head2 stat_list
541              
542             Returns an array of all the segment's system stat entries. These are what make
543             up the method names of the C<< $seg->stat >> object.
544              
545             =head2 shmread
546              
547             Returns the data (and NULL pad bytes) stored in the shared memory segment.
548              
549             By default, when data is retrieved from the shared memory segment, the data
550             is padded to the right by NULL bytes to fill up the entire size of the segment.
551             This can cause issues when using the space for non serialized data (ie. if you
552             stored "hello" in a 1024 byte segment, the ASCII text wouldn't match).
553              
554             Typically this method is used when you want all blocks of the segment, such as
555             if you've stored binary data.
556              
557             For text/ASCII data, use the L method which automatically strips NULL
558             pad bytes.
559              
560             I: The data if any is stored, empty string if no data has been stored
561             yet, and C if a failure to read occurs.
562              
563             =head2 shmwrite($data)
564              
565             Stores the serialized data to the shared memory segment.
566              
567             Parameters:
568              
569             $data
570              
571             I: Typically, the a serialized data structure.
572              
573             I: True on success, false on failure.
574              
575             =head2 remove
576              
577             Removes the shared memory segment and returns the resources to the system.
578              
579             I: True (C<1>) on success, false (C<0>) on failure.
580              
581             =head1 AUTHOR
582              
583             Ben Sugars (bsugars@canoe.ca)
584              
585             =head1 MAINTAINED BY
586              
587             Steve Bertrand
588              
589             =head1 SEE ALSO
590              
591             L, L, L
592              
593             =cut