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 83     83   573 use warnings;
  83         141  
  83         4187  
4 83     83   338 use strict;
  83         122  
  83         1812  
5              
6 83     83   279 use Carp qw(carp croak confess);
  83         127  
  83         4225  
7 83     83   333 use Config;
  83         106  
  83         2860  
8 83     83   318 use Errno qw(EEXIST EPERM);
  83         104  
  83         5005  
9 83     83   362 use IPC::SysV qw(IPC_RMID IPC_STAT);
  83         168  
  83         5663  
10              
11             our $VERSION = '1.16';
12              
13             use constant {
14 83         10096 DEFAULT_SEG_SIZE => 1024,
15             DEFAULT_SEG_FLAGS => 0000,
16             DEFAULT_SEG_MODE => 0666,
17 83     83   392 };
  83         154  
18              
19             {
20             package IPC::Shareable::SharedMem::stat;
21              
22 83     83   544 use Class::Struct qw(struct);
  83         248  
  83         442  
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 665     665 1 17396 my ($class, %params) = @_;
42              
43 665         2084 my $self = bless {}, $class;
44              
45 665 100 100     4427 if (defined $params{key} && $params{key} =~ /^0x[0-9a-fA-F]+$/i) {
46 1         4 $params{key} = hex($params{key});
47             }
48              
49 665 100 100     5149 if (! defined $params{key} || $params{key} !~ /^\d+$/) {
50 2         388 croak "new() requires a 'key' parameter with an integer value";
51             }
52              
53 663         3094 $self->key($params{key});
54 663         1063 $self->key_hex($self->key);
55              
56 663   100     2985 $self->size($params{size} || DEFAULT_SEG_SIZE);
57              
58 662   100     2607 $self->mode($params{mode} || DEFAULT_SEG_MODE);
59 662   100     2055 $self->flags(($params{flags} || DEFAULT_SEG_FLAGS) | $self->mode);
60              
61 662         1848 $self->type($params{type});
62              
63 662         1259 my $id = shmget($self->key, $self->size, $self->flags);
64              
65 662 100       2022 defined $id or do {
66 10         42 my $key = $self->key_hex;
67              
68 10 50       143 if ($!) {
69 10 100 66     195 if ($!{EEXIST} || $!{EPERM}) {
70 6         1473 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         212 return undef;
76             }
77             };
78              
79 652         1450 $self->id($id);
80              
81 652         2487 return $self;
82             }
83             sub id {
84 11763     11763 1 27674 my ($self, $id) = @_;
85              
86 11763 100       17198 if (defined $id) {
87 653 100       1355 if ($self->{id}) {
88 1         11 warn "Can't set id() after object already instantiated";
89 1         11 return $self->{id};
90             }
91 652         1743 $self->{id} = $id;
92             }
93 11762         35175 return $self->{id};
94             }
95             sub key {
96 2023     2023 1 5447 my ($self, $key) = @_;
97              
98 2023 100       3041 if (defined $key) {
99 664 100       1656 if ($self->id) {
100 1         144 croak "Can't set the 'key' attribute after object is already established";
101             }
102              
103 663         1749 $self->{key} = $key;
104             }
105              
106 2022         4271 return $self->{key};
107             }
108             sub key_hex {
109 1196     1196 1 2147 my ($self, $key_int) = @_;
110              
111 1196 100       2191 if (defined $key_int) {
112 663         2844 $self->{key_hex} = sprintf "0x%08x", $key_int;
113             }
114              
115 1196         9573 return $self->{key_hex};
116             }
117             sub flags {
118 2253     2253 1 8508 my ($self, $flags) = @_;
119              
120 2253 100       3398 if (defined $flags) {
121 663 100       1072 if ($self->id) {
122 1         11 warn "Can't set flags() after object already instantiated";
123 1         6 return $self->{flags};
124             }
125              
126 662         1063 $self->{flags} = $flags;
127             }
128 2252         19227 return $self->{flags};
129             }
130             sub mode {
131 1328     1328 1 2387 my ($self, $mode) = @_;
132              
133 1328 100       1978 if (defined $mode) {
134 663 100       1207 if ($self->id) {
135 1         11 warn "Can't set mode() after object already instantiated";
136 1         6 return $self->{mode};
137             }
138              
139 662         1268 $self->{mode} = $mode;
140             }
141              
142 1327         2822 return $self->{mode};
143             }
144             sub size {
145 6319     6319 1 9846 my ($self, $size) = @_;
146              
147 6319 100       10898 if (defined $size) {
148 664 100       1464 if ($self->id) {
149 1         21 warn "Can't set size() after object already instantiated";
150 1         8 return $self->{size};
151             }
152 663 100       3059 if ($size !~ /^\d+$/) {
153 1         117 croak "size() requires an integer as parameter";
154             }
155              
156 662         1402 $self->{size} = $size;
157             }
158 6317         545829 return $self->{size};
159             }
160             sub type {
161 665     665 1 2104 my ($self, $type) = @_;
162              
163 665 100       1178 if (defined $type) {
164 537 100       876 if ($self->id) {
165 1         11 warn "Can't set type() after object already instantiated";
166 1         6 return $self->{type};
167             }
168              
169 536         1129 $self->{type} = $type;
170             }
171              
172 664         878 return $self->{type};
173             }
174             sub data {
175 1639     1639 1 2338 my ($self) = @_;
176              
177 1639         3758 my $data = $self->shmread;
178              
179 1639 100       3346 return if ! defined $data;
180              
181 1633         3221 my $pos = index($data, "\x00");
182 1633 50       4016 $data = $pos >= 0 ? substr($data, 0, $pos) : $data;
183              
184 1633         4620 return $data;
185             }
186             sub stat {
187 19     19 1 18039 my ($self) = @_;
188 19         42 my $data = '';
189 19 100       39 shmctl($self->id, IPC_STAT, $data) or return undef;
190              
191 18         188 my %values;
192              
193 18 50 0     64 if ($^O eq 'linux') {
    0 0        
    0 0        
    0          
    0          
194 18 50       281 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 18         153 @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 18         49 my @struct_initializers;
292 18         31 for (stat_list()) {
293 216         263 my $value = $values{$_};
294 216 100       292 if ($_ eq 'mode') {
295 18         28 $value = $value & 0777;
296 18         60 push @struct_initializers, $_ => sprintf("%#o", $value);
297             }
298             else {
299 198         294 push @struct_initializers, $_ => $value;
300             }
301             }
302              
303 18         580 return IPC::Shareable::SharedMem::stat->new(@struct_initializers);
304             }
305             sub stats {
306 1     1 1 11 my ($self) = @_;
307 1         13 my @stat_list = stat_list();
308              
309 1         5 my $stat = $self->stat;
310              
311 1         120 my %stats;
312              
313 1         3 for (@stat_list) {
314 12         223 $stats{$_} = $stat->$_;
315             }
316              
317 1         26 return \%stats;
318             }
319             sub stat_list {
320 20     20 1 109 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 3126     3126 1 4348 my ($self) = @_;
338              
339 3126         4258 my $data = '';
340 3126 100       6400 shmread($self->id, $data, 0, $self->size) or return;
341 3113         18280 return $data;
342             }
343             sub shmwrite {
344 932     932 1 1597 my($self, $data) = @_;
345 932         1529 return shmwrite($self->id, $data, 0, $self->size);
346             }
347             sub remove {
348 477     477 1 880 my ($self) = @_;
349 477         777 my $os_return_value = shmctl($self->id, IPC_RMID, 0);
350              
351 477 100 33     19773 if (defined $os_return_value && ($os_return_value eq '0 but true' || $os_return_value == 1)) {
      66        
352 476         2030 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