File Coverage

blib/lib/IPC/Shm/Simple.pm
Criterion Covered Total %
statement 153 244 62.7
branch 48 102 47.0
condition 15 29 51.7
subroutine 29 41 70.7
pod 22 29 75.8
total 267 445 60.0


line stmt bran cond sub pod time code
1             package IPC::Shm::Simple;
2 4     4   85832 use warnings;
  4         9  
  4         113  
3 4     4   21 use strict;
  4         7  
  4         114  
4 4     4   21 use Carp;
  4         7  
  4         342  
5              
6             #
7             # Copyright (C) 2005,2014 by Kevin Cody-Little
8             #
9             # Although this package as a whole is derived from
10             # IPC::ShareLite, this particular file is a new work.
11             #
12             # This code may be modified or redistributed under the terms
13             # of either the Artistic or GNU General Public licenses, at
14             # the modifier or redistributor's discretion.
15             #
16              
17             =head1 NAME
18              
19             IPC::Shm::Simple - Simple data in SysV shared memory segments.
20              
21             =head1 SYNOPSIS
22              
23             Provides the ability to create a shared segment with or without first
24             knowing what ipckey it will use. Caches shared memory reads in process
25             memory, and defeatably verifies writes by reading the value back
26             and comparing it stringwise.
27              
28             Can only store string or numeric data.
29              
30             =head1 OBJECT CACHING
31              
32             This module caches the underlying C object, such that the process only
33             has one attachment to the shared segment. However, the Perl objects are
34             not cached, to facilitate timely destruction. There can be many distinct
35             blessed references to the same shared segment. This is made transparent
36             by storing all state information in package lexicals, not upon the object.
37              
38             =cut
39              
40              
41 4     4   18 use Fcntl qw( :flock );
  4         5  
  4         395  
42 4     4   4274 use IPC::SysV qw( IPC_PRIVATE );
  4         5435  
  4         568  
43              
44 4     4   3406 use Class::Attrib;
  4         36892  
  4         113  
45 4     4   60 use DynaLoader;
  4         7  
  4         95  
46 4     4   3730 use UNIVERSAL;
  4         50  
  4         24  
47              
48 4     4   112 use vars qw( $VERSION @ISA %Attrib );
  4         7  
  4         11496  
49              
50             $VERSION = '1.10';
51             @ISA = qw( Class::Attrib DynaLoader );
52             %Attrib = (
53             Mode => oct( 660 ),
54             Size => 4096,
55             dwell => 0,
56             verify => 1
57             );
58              
59              
60             ###
61             ### Constructors
62             ###
63              
64             =head1 CONSTRUCTORS
65              
66             =head2 $this->bind( ipckey, [size], [mode] );
67              
68             Attach to the shared memory segment identified by ipckey, whether it
69             exists already or not.
70              
71             If a segment must be created, size and permissions may be specified as
72             for the C<< $this->create() >> call. Otherwise, the class defaults will apply.
73              
74             Returns blessed reference on success, undef on failure.
75              
76             Throws an exception on invalid parameters.
77              
78             The segment will be unlocked even if it was just created.
79              
80             =cut
81              
82             sub bind {
83 2     2 1 35 my ( $this, $ipckey, $size, $mode ) = @_;
84 2         5 my ( $self );
85              
86 2 100       12 unless ( $self = $this->attach( $ipckey ) ) {
87              
88 1 50       8 $self = $this->create( $ipckey, $size, $mode )
89             or return;
90              
91 1         5 $self->unlock;
92              
93             }
94              
95 2         16 return $self;
96             }
97              
98             { # BEGIN lexical scope
99             my %ShmIndex = (); # cache key=ipckey value=shmid
100             my %ShmShare = (); # cache key=shmid value=sharelite
101             my %ShmCount = (); # cache key=shmid value=integer
102              
103             =head2 $this->attach( ipckey );
104              
105             Attach to the shared memory segment identified by ipckey if it exists.
106              
107             Returns blessed reference on success, undef on failure.
108              
109             Throws an exception on invalid parameters.
110              
111             =cut
112              
113             sub attach {
114 6     6 1 14 my ( $this, $ipckey ) = @_;
115              
116 6 50       23 confess( __PACKAGE__ . "->attach: Called without ipckey." )
117             unless defined $ipckey;
118              
119 6 50       18 confess( __PACKAGE__ . "->attach: Called with empty ipckey." )
120             unless $ipckey;
121              
122 6 50       22 confess( __PACKAGE__ . "->attach: Called with string ipckey." )
123             unless $ipckey > 0;
124              
125 6 50       35 confess( __PACKAGE__ . "->attach: Called with IPC_PRIVATE." )
126             if $ipckey == IPC_PRIVATE;
127              
128 6   33     158 my $class = ref( $this ) || $this;
129              
130 6 50       32 if ( my $shmid = $ShmIndex{$ipckey} ) {
131 0         0 my $share = $ShmShare{$shmid};
132 0 0       0 unless ( $share ) {
133 0         0 carp __PACKAGE__ . "->attach: dangling ShmIndex";
134 0         0 delete $ShmIndex{$ipckey};
135 0         0 return;
136             }
137              
138 0         0 bless my $self = {}, $class;
139 0         0 $self->{share} = $share;
140 0         0 $self->{shmid} = $shmid;
141              
142 0 0       0 if ( $self->is_valid ) {
143 0         0 $ShmCount{$shmid}++;
144 0         0 return $self;
145             }
146              
147 0         0 carp __PACKAGE__ . "->attach: got invalid cached object";
148              
149 0         0 delete $ShmCount{$shmid};
150 0         0 delete $ShmShare{$shmid};
151 0         0 delete $ShmIndex{$ipckey};
152              
153 0         0 return;
154             }
155              
156 6         126 my $share = sharelite_attach( $ipckey );
157              
158 6 100       28 return unless $share; # no carp, $! is set
159              
160 3         20 my $shmid = sharelite_shmid( $share );
161              
162 3 50       12 unless ( defined $shmid ) {
163 0         0 carp "sharelite_shmid returned undef";
164 0         0 sharelite_shmdt( $share );
165 0         0 return;
166             }
167              
168 3         14 bless my $self = {}, $class;
169 3         22 $self->{share} = $share;
170 3         7 $self->{shmid} = $shmid;
171              
172             # inform subclasses that an uncached attachment has occurred
173 3 50       13 $self->ATTACH()
174             or return;
175              
176             # save the attached object in the cache
177 3         35 $ShmIndex{$ipckey} = $shmid;
178 3         10 $ShmShare{$shmid} = $share;
179 3         7 $ShmCount{$shmid} = 1;
180              
181 3         11 return $self;
182             }
183              
184             =head2 $self->ATTACH();
185              
186             Called by C< $this->attach() > and C< $this->shmat() > when an uncached
187             attachment occurs.
188              
189             Must return true, otherwise the attachment is aborted.
190              
191             Does nothing on its own; this is meant for subclasses to override.
192              
193             =cut
194              
195             sub ATTACH {
196 3     3 1 7 my ( $self ) = @_;
197              
198 3         12 return 1;
199             }
200              
201             =head2 $this->create( [ipckey], [segsize], [permissions] )
202              
203             Create a new shared memory segment, with the given ipckey, unless it exists.
204             Can be given C as an ipckey to create an unkeyed segment, which
205             is assumed if no argument is provided.
206              
207             The optional parameters segsize and permissions default to C<< $this->Size() >>
208             and C<< $this->Mode() >>, respectively.
209              
210             Returns blessed reference on success, undef on failure.
211              
212             The segment will automatically have a writelock in effect.
213              
214             =cut
215              
216             sub create {
217 6     6 1 574 my ( $this, $ipckey, $size, $mode ) = @_;
218              
219 6   66     37 $ipckey ||= IPC_PRIVATE;
220 6   66     85 $size ||= $this->Size();
221 6   66     428 $mode ||= $this->Mode();
222              
223 6   33     308 my $class = ref( $this ) || $this;
224              
225 6         352 my $share = sharelite_create( $ipckey, $size, $mode );
226              
227 6 50       21 return unless $share; # no carp, $! is set
228              
229 6         50 my $shmid = sharelite_shmid( $share );
230              
231 6 50       23 unless ( defined $shmid ) {
232 0         0 carp "sharelite_shmid returned undef";
233 0         0 sharelite_remove( $share );
234 0         0 sharelite_shmdt( $share );
235 0         0 return;
236             }
237              
238 6         24 bless my $self = {}, $class;
239 6         54 $self->{share} = $share;
240 6         27 $self->{shmid} = $shmid;
241              
242 6 100       37 $ShmIndex{$ipckey} = $shmid unless $ipckey == IPC_PRIVATE;
243 6         111 $ShmShare{$shmid} = $share;
244 6         13 $ShmCount{$shmid} = 1;
245              
246 6         43 return $self;
247             }
248              
249             =head2 $this->shmat( shmid );
250              
251             Attach to an existing shared memory segment by its shmid.
252              
253             =cut
254              
255             sub shmat {
256 0     0 1 0 my ( $this, $shmid ) = @_;
257              
258 0 0       0 confess( __PACKAGE__ . "->shmat: Called without shmid." )
259             unless defined $shmid;
260              
261 0 0       0 confess( __PACKAGE__ . "->shmat: Called with invalid shmid." )
262             if $shmid == -1;
263              
264 0   0     0 my $class = ref( $this ) || $this;
265              
266 0 0       0 if ( my $share = $ShmShare{$shmid} ) {
267              
268 0         0 bless my $self = {}, $class;
269 0         0 $self->{share} = $share;
270 0         0 $self->{shmid} = $shmid;
271              
272 0 0       0 if ( $self->is_valid ) {
273 0         0 $ShmCount{$shmid}++;
274 0         0 return $self;
275             }
276              
277 0         0 carp __PACKAGE__ . "->shmat: got invalid cached object";
278              
279 0         0 delete $ShmCount{$shmid};
280 0         0 delete $ShmShare{$shmid};
281              
282 0         0 return;
283             }
284              
285 0         0 my $share = sharelite_shmat( $shmid );
286              
287 0 0       0 return unless $share; # no carp, $! is set
288              
289 0         0 bless my $self = {}, $class;
290 0         0 $self->{share} = $share;
291 0         0 $self->{shmid} = $shmid;
292              
293             # inform subclasses that an uncached attachment has occurred
294 0 0       0 $self->ATTACH()
295             or return;
296              
297             # save the attached object in the cache
298 0         0 $ShmShare{$shmid} = $share;
299 0         0 $ShmCount{$shmid} = 1;
300              
301 0         0 return $self;
302             }
303              
304             =head1 CLEANUP METHOD
305              
306             =head2 $self->remove();
307              
308             Uncaches the referenced instance, and causes the underlying shared
309             memory segments to be removed from the operating system when DESTROYed.
310              
311             Returns 1 on success, undef on failure.
312              
313             =cut
314              
315             sub remove {
316 5     5 1 697 my ( $self ) = @_;
317 5         9 my ( $share, $shmid, $ipckey );
318              
319 5         12 $share = $self->{share};
320              
321 5 50       22 unless ( $share ) {
322 0         0 carp "undefined share during remove";
323 0         0 return;
324             }
325              
326 5 50       56 return ( sharelite_remove( $share ) == -1 ) ? undef : 1;
327             }
328              
329             # when the object is destroyed, the sharelite object must be too
330             # otherwise segment removal (and even removal marking) would never occur
331             sub DESTROY {
332 9     9   451 my ( $self ) = @_;
333              
334 9         25 my $shmid = $self->{shmid};
335              
336 9 50       37 unless ( defined $shmid ) {
337 0         0 carp "undefined shmid during DESTROY";
338 0         0 return;
339             }
340              
341 9         21 $ShmCount{$shmid}--;
342              
343 9 50       35 return if $ShmCount{$shmid};
344              
345 9         35 $self->DETACH;
346              
347 9         381 return;
348             }
349              
350             =head1 DESTRUCTOR
351              
352             =head2 $self->DETACH();
353              
354             Called by C< $self->DESTROY() > on the last copy of the object.
355              
356             Uncaches the referenced instance, and causes the underlying shared
357             memory segments to be detached by the operating system.
358              
359             If subclasees override this, they must call C< $self->SUPER::DESTROY() >.
360              
361             =cut
362             sub DETACH {
363 9     9 1 16 my ( $self ) = @_;
364              
365 9         32 $self->scache_clean;
366              
367 9         19 my $shmid = $self->{shmid};
368              
369 9 50       43 unless ( defined $shmid ) {
370 0         0 carp "undefined shmid during DETACH";
371 0         0 return;
372             }
373              
374 9         18 my $share = $self->{share};
375              
376 9 50       28 unless ( $share ) {
377 0         0 carp "undefined share during DETACH";
378 0         0 return;
379             }
380              
381 9         28 my $ipckey = sharelite_key( $share );
382              
383 9         36 delete $ShmCount{$shmid};
384 9         32 delete $ShmShare{$shmid};
385 9 100       44 delete $ShmIndex{$ipckey} unless $ipckey == IPC_PRIVATE;
386              
387 9         406 sharelite_shmdt( $share );
388              
389 9         22 return;
390             }
391              
392             } # END lexical scope
393              
394              
395             =head1 ACCESSOR METHODS
396              
397             =head2 $self->key();
398              
399             Returns the ipckey assigned by the program at instantiation.
400              
401             =head2 $self->shmid();
402              
403             Returns the shmid assigned by the operating system at instantiation.
404              
405             =head2 $self->flags();
406              
407             Returns the permissions flags assigned at instantiation.
408              
409             =head2 $self->length();
410              
411             Returns the number of bytes currently stored in the share.
412              
413             =head2 $self->serial();
414              
415             Returns the serial number of the current shared memory value.
416              
417             =head2 $self->top_seg_size();
418              
419             Returns the total size of the top share segment, in bytes.
420              
421             =head2 $self->chunk_seg_size();
422              
423             Returns the size of data chunk segments, in bytes.
424              
425             =head2 $self->chunk_seg_size( chunk_segment_size );
426              
427             Changes the size of chunk data segments. The share must have only one
428             allocated segment (the top segment) for this call to succeed.
429              
430             =head2 $self->nconns();
431              
432             Reports the number of processes connected to the share.
433              
434             =head2 $self->nrefs();
435              
436             Returns the current shared reference count.
437              
438             =head2 $self->incref();
439              
440             Increments the shared reference counter.
441              
442             =head2 $self->decref();
443              
444             Decrements the shared reference counter.
445              
446             =cut
447              
448             sub key {
449 0     0 1 0 return sharelite_key( shift->{share} );
450             }
451              
452             sub shmid {
453 0     0 1 0 return sharelite_shmid( shift->{share} );
454             }
455              
456             sub flags {
457 2     2 1 60 return sharelite_flags( shift->{share} );
458             }
459              
460             sub length {
461 5     5 1 42 return sharelite_length( shift->{share} );
462             }
463              
464             sub serial {
465 5     5 1 38 return sharelite_serial( shift->{share} );
466             }
467              
468             sub is_valid {
469 0     0 0 0 return sharelite_is_valid( shift->{share} );
470             }
471              
472             sub nsegments {
473 4     4 0 26 return sharelite_nsegments( shift->{share} );
474             }
475              
476             sub top_seg_size {
477 2     2 1 26 return sharelite_top_seg_size( shift->{share} );
478             }
479              
480             sub chunk_seg_size {
481 0     0 1 0 return sharelite_chunk_seg_size( shift->{share}, @_ );
482             }
483              
484             sub nconns {
485 0     0 1 0 return sharelite_nconns( shift->{share} );
486             }
487              
488             sub nrefs {
489 0     0 1 0 return sharelite_nrefs( shift->{share} );
490             }
491              
492             sub incref {
493 0     0 1 0 return sharelite_incref( shift->{share}, @_ );
494             }
495              
496             sub decref {
497 0     0 1 0 return sharelite_decref( shift->{share}, @_ );
498             }
499              
500              
501             =head1 DATA METHODS
502              
503             =head2 $self->scache();
504              
505             Returns a scalar reference to the segment cache. Does not guarantee
506             freshness, and the reference can become invalid after the next I/O
507             operation.
508              
509             =head2 $self->scache_clean();
510              
511             Entirely removes the cache entry for the object.
512              
513             =head2 $self->fetch();
514              
515             Fetch a previously stored value.
516              
517             If nothing has been stored yet, C<''> (the empty string) is returned.
518              
519             =head2 $self->FRESH();
520              
521             Invoked by C< fetch() > when the data has been changed by another process.
522              
523             =cut
524              
525              
526             { # BEGIN private lexical scope
527             my %ShmCache = (); # cache key=shmid value={}
528             # scache = string
529             # serial = integer
530             # sstamp = timestamp
531              
532             sub scache {
533 0     0 1 0 my $self = shift;
534              
535 0         0 my $shmid = $self->{shmid};
536              
537 0 0       0 unless ( defined $shmid ) {
538 0         0 carp "undefined shmid during scache retrieval";
539 0         0 return;
540             }
541              
542 0   0     0 my $cache = $ShmCache{$shmid} ||= {};
543              
544 0   0     0 $cache->{scache} ||= '';
545              
546 0         0 return \($cache->{scache});
547             }
548              
549             sub scache_clean {
550 9     9 1 16 my $self = shift;
551              
552 9         76 delete $ShmCache{$self->{shmid}};
553              
554             }
555              
556             sub fetch {
557 2007     2007 1 2452 my $self = shift;
558              
559 2007 50       3641 carp( __PACKAGE__ . "->fetch: Called without at least shared lock!" )
560             if $self->_locked( LOCK_UN );
561              
562 2007         3497 my $share = $self->{share};
563              
564 2007 50       3816 unless ( $share ) {
565 0         0 carp "undefined share during fetch";
566 0         0 return;
567             }
568              
569 2007         2941 my $shmid = $self->{shmid};
570              
571 2007 50       4095 unless ( defined $shmid ) {
572 0         0 carp "undefined shmid during fetch";
573 0         0 return;
574             }
575              
576 2007   100     5237 my $cache = $ShmCache{$shmid} ||= {};
577              
578             # determine current shared memory value serial number
579 2007         4238 my $serial = sharelite_serial( $share );
580              
581             # short circuit remaining tests if cache is found invalid
582 2007         2096 my $dofetch = 0;
583              
584             # definitely fetch if we don't have a matching serial number
585 2007 100 100     16427 $dofetch = 1
586             unless $cache->{serial} && ( $cache->{serial} == $serial );
587              
588             # same serial; believe the cached value if it isn't too old
589             # a zero ttl means trust the cached value until the serial changes
590 2007 100       3403 unless ( $dofetch ) {
591 39 50       125 if ( my $ttl = $self->dwell() ) {
592 0 0       0 $dofetch = 1 if $cache->{sstamp} + $ttl < time();
593             }
594             }
595              
596 2007 100       6593 if ( $dofetch ) {
597              
598 1968         6558 $cache->{scache} = sharelite_fetch( $share );
599              
600 1968 50       4378 croak( __PACKAGE__ . "->fetch: failed: $!" )
601             unless defined $cache->{scache};
602              
603 1968         2739 $cache->{sstamp} = time();
604 1968         2216 $cache->{serial} = $serial;
605              
606 1968 50       6879 if ( my $cref = UNIVERSAL::can( $self, 'FRESH' ) ) {
607 0         0 &$cref( $self );
608             }
609              
610             }
611              
612 2007         8119 return $cache->{scache};
613             }
614              
615             =head2 $self->store( value );
616              
617             Stores a string or numeric value in the shared memory segment.
618              
619             =cut
620              
621             sub store {
622 2007     2007 1 7086 my $self = shift;
623              
624 2007 50       3877 carp( __PACKAGE__ . "->store: Called without exclusive lock!" )
625             unless $self->_locked( LOCK_EX );
626              
627 2007         3239 my $share = $self->{share};
628              
629 2007 50       3342 unless ( $share ) {
630 0         0 carp "undefined share during store";
631 0         0 return;
632             }
633              
634 2007         2713 my $shmid = $self->{shmid};
635              
636 2007 50       3331 unless ( $shmid ) {
637 0         0 carp "undefined shmid during store";
638 0         0 return;
639             }
640              
641 2007   100     5279 my $cache = $ShmCache{$shmid} ||= {};
642              
643 2007         5435 my $rc = sharelite_store( $share, $_[0], CORE::length( $_[0] ) );
644              
645 2007 50       4004 croak( __PACKAGE__ . "->store: failed: $!" )
646             if $rc == -1;
647              
648 2007 50       5427 if ( $self->verify() ) {
649 2007         129420 my $data = sharelite_fetch( $share );
650              
651 2007 50       5106 croak( __PACKAGE__ . "->store: fetch failed: $!" )
652             unless defined $data;
653              
654 2007 50       4336 croak( __PACKAGE__ . "->store: Write verify failed!" )
655             unless $_[0] eq $data;
656              
657             }
658              
659             # simulate a fetch because storing also serves to confirm the value
660 2007         3450 $cache->{scache} = $_[0];
661 2007         3884 $cache->{sstamp} = time();
662 2007         3869 $cache->{serial} = sharelite_serial( $share );
663              
664             # return true so test harnesses pass
665 2007         4511 return 1;
666             }
667              
668             } # END scope
669              
670              
671             ###
672             ### Object Lock Methods - Class::Lockable friendly
673             ###
674              
675             sub lock {
676 4004     4004 0 530808 return shift->_lock( @_ );
677             }
678              
679             sub _lock {
680 4006     4006   5547 my ( $self, $flag ) = @_;
681              
682 4006         5563 my $share = $self->{share};
683              
684 4006 50       7138 unless ( $share ) {
685 0         0 carp "undefined share during _lock";
686 0         0 return;
687             }
688              
689             # short circuit if already locked as requested
690 4006 50       12942 return 0 if sharelite_locked( $share, $flag );
691              
692 4006         570676 my $rc = sharelite_lock( $share, $flag );
693              
694 4006 50       8944 if ( $rc == -1 ) {
695 0         0 carp( __PACKAGE__ . "->_lock: $!" );
696 0         0 return;
697             }
698              
699 4006         12465 return $rc == 0;
700             }
701              
702             sub locked {
703 0     0 0 0 return shift->_locked( @_ );
704             }
705              
706             sub _locked {
707 4014     4014   4974 my ( $self, $flag ) = @_;
708              
709 4014         5084 my $share = $self->{share};
710              
711 4014 50       7465 unless ( $share ) {
712 0         0 carp "undefined share during _locked";
713 0         0 return;
714             }
715              
716 4014         7377 my $rc = sharelite_locked( $share, $flag );
717              
718 4014 50       7378 if ( $rc == -1 ) {
719 0         0 carp( __PACKAGE__ . "->_locked: $!" );
720 0         0 return;
721             }
722              
723 4014         11789 return $rc != 0;
724             }
725              
726              
727             ###
728             ### Higher Level Lock Methods
729             ###
730              
731             sub unlock {
732 1     1 0 8 return shift->_lock( LOCK_UN );
733             }
734              
735             sub readlock {
736 1     1 0 6 return shift->_lock( LOCK_SH );
737             }
738              
739             sub writelock {
740 0     0 0   return shift->_lock( LOCK_EX );
741             }
742              
743              
744             bootstrap IPC::Shm::Simple $VERSION;
745              
746             1;
747              
748              
749             =head1 INSTANCE ATTRIBUTES - I/O BEHAVIOR
750              
751             =head2 $this->dwell( [seconds] );
752              
753             Specifies the time-to-live of cached shared memory reads, in seconds.
754             This only affects the case where the serial number has -not- changed.
755              
756             Default: 0.
757              
758             =head2 $this->verify( [boolean] );
759              
760             Specifies whether to read-back and compare shared memory writes.
761              
762             Expensive.
763              
764             Default: 1.
765              
766             =head1 PACKAGE ATTRIBUTES - SEGMENT PARAMETERS
767              
768             These methods carry the default values used during instantiation.
769              
770             =head2 $this->Mode( [value] );
771              
772             Specifies or fetches the permissions for new segments. Default: 0660.
773              
774             =head2 $this->Size( [value] );
775              
776             Specifies or fetches the initial size of new shared memory segments.
777             Default: 4096
778              
779             =head1 CAVEATS
780              
781             To do.
782              
783             =cut
784