Codebase list libipc-shareable-perl / 61eb0d0
Update upstream source from tag 'upstream/1.12' Update to upstream version '1.12' with Debian dir fa6505ecd8e2aaa51b8d8b59056baef432ee6a1b gregor herrmann 2 years ago
49 changed file(s) with 436 addition(s) and 431 deletion(s). Raw diff Collapse all Expand all
00 Revision history for Perl extension IPC::Shareable.
1
2 1.12 2022-03-13
3 - Add tests in t/07-new.t to test how using tied() against a dereferenced
4 variable returned from new() allows access to the underlying
5 IPC::Shareable object
6 - Reworked how spawn() and unspawn() manage things internally
7 - POD updates, fixes and clarifications
8 - Removed spawn() and unspawn(). There's really no need for these as one
9 can simply create but not destroy
10
11 1.11 2022-03-07
12 - Fix certain tests so they don't throw if we bail early
13
14 1.10 2022-03-07
15 - Fix issue where if segments were created underneath of a parent by an
16 external process other than the process that created the parent, the
17 global register wasn't being updated, therefore those segments weren't
18 being removed when calling clean_up_all()
19 - All test files now check number of segments before and after the entire
20 script has run, verifying that all segments were cleaned up ok
21 - The test suite itself in its entirety makes sure that all segments
22 created during the suite run are cleaned up properly
23 - Added CI_TESTING=1 to coverage CI tests
124
225 1.09 2022-03-06
326 - Made 81-fork_dup_rand_keys.t developer only (but still need to figure out
77 CREDITS
88 DISCLAIMER
99 'docs/Shared Memory Configuration.txt'
10 examples/new.pl
1011 lib/IPC/Shareable.pm
1112 lib/IPC/Shareable/SharedMem.pm
1213 Makefile.PL
4041 t/65-seg_size.t
4142 t/66-size_exceeded.t
4243 t/67-exhaust_shm_slots.t
43 t/71-unspawn.t
44 t/72-unspawn_destroy.t
4544 t/75-graceful.t
4645 t/76-singleton.t
4746 t/77-singleton_warn.t
4948 t/81-fork_dup_rand_keys.t
5049 t/82-sig_child_ignore.t
5150 t/83-clean_protected.t
52 t/85-spawn_object_contains_data.t
53 t/86-unspawn_object_contains_data.t
5451 t/90-pod_coverage.t
5552 t/91-pod_linkcheck.t
5653 t/92-pod.t
5754 t/93-manifest.t
58 t/_spawn
59 t/_spawn_class
60 t/SpawnTest.pm
55 t/99-end.t
6156 testing/new_one.pl
6257 testing/new_two.pl
6358 testing/one_deep_hash.pl
5353 "web" : "https://github.com/stevieb9/ipc-shareable"
5454 }
5555 },
56 "version" : "1.09",
56 "version" : "1.12",
5757 "x_serialization_backend" : "JSON::PP version 4.04"
5858 }
2828 resources:
2929 bugtracker: https://github.com/stevieb9/ipc-shareable/issues
3030 repository: https://github.com/stevieb9/ipc-shareable.git
31 version: '1.09'
31 version: '1.12'
3232 x_serialization_backend: 'CPAN::Meta::YAML version 0.018'
0 use warnings;
1 use strict;
2 use feature 'say';
3
4 use Data::Dumper;
5 use IPC::Shareable;
6
7 say "Before: " . IPC::Shareable::ipcs;
8
9 my $h = IPC::Shareable->new(
10 key => 'blah',
11 create => 1,
12 destroy => 1
13 );
14
15 $h->{one}{two} = 'hello, world!';
16 $h->{one}{three}{four} = 1;
17
18 print Dumper $h;
19
20 IPC::Shareable::_end;
21 say "After: " . IPC::Shareable::ipcs;
55 use Carp qw(carp croak confess);
66 use IPC::SysV qw(IPC_RMID);
77
8 our $VERSION = '1.09';
8 our $VERSION = '1.12';
99
1010 use constant DEBUGGING => ($ENV{SHM_DEBUG} or 0);
1111
2020 use String::CRC32;
2121 use Storable 0.6 qw(freeze thaw);
2222
23 our $VERSION = '1.09';
23 our $VERSION = '1.12';
2424
2525 use constant {
2626 LOCK_SH => 1,
125125 sub STORE {
126126 my $knot = shift;
127127
128 my $sid = $knot->seg->{_id};
129
130 $global_register{$sid} ||= $knot;
128 if (! exists $global_register{$knot->seg->id}) {
129 $global_register{$knot->seg->id} = $knot;
130 }
131131
132132 $knot->{_data} = $knot->_decode($knot->seg) unless ($knot->{_lock});
133133
163163 sub FETCH {
164164 my $knot = shift;
165165
166 my $sid = $knot->seg->{_id};
167
168 $global_register{$sid} ||= $knot;
166 if (! exists $global_register{$knot->seg->id}) {
167 $global_register{$knot->seg->id} = $knot;
168 }
169169
170170 my $data;
171171 if ($knot->{_lock} || $knot->{_iterating}) {
285285 sub PUSH {
286286 my $knot = shift;
287287
288 $global_register{$knot->seg->id} ||= $knot;
288 if (! exists $global_register{$knot->seg->id}) {
289 $global_register{$knot->seg->id} = $knot;
290 }
291
289292 $knot->{_data} = $knot->_decode($knot->seg, $knot->{_data}) unless $knot->{_lock};
290293
291294 push @{$knot->{_data}}, @_;
397400 }
398401 }
399402 sub global_register {
403 # This is a ridiculous way to do this, but if we don't call Dumper, hashes
404 # that are created in a separate process than the parent hash don't
405 # show up properly in the global register. t/81
406
407 local $SIG{__WARN__} = sub {
408 my ($warning) = @_;
409 if ($warning !~ /hash after insertion/) {
410 warn $warning;
411 }
412 };
413
414 Dumper \%global_register;
415
400416 return \%global_register;
401417 }
402418 sub process_register {
418434 sub ipcs {
419435 my $count = `ipcs -m | wc -l`;
420436 chomp $count;
421 return $count;
422 }
423 sub spawn {
424 my ($knot, %opts) = @_;
425
426 croak "spawn() requires a key/glue sent in..." if ! defined $opts{key};
427
428 $opts{mode} = 0666 if ! defined $opts{mode};
429
430 $SIG{CHLD} = 'IGNORE';
431
432 _spawn(
433 key => $opts{key},
434 mode => $opts{mode},
435 );
436 }
437 sub _spawn {
438 my (%opts) = @_;
439
440 my $pid = fork;
441 return if $pid;
442
443 if (! $pid) {
444 tie my %h, 'IPC::Shareable', {
445 key => $opts{key},
446 create => 1,
447 #exclusive => 1,
448 destroy => $opts{destroy},
449 mode => $opts{mode},
450 };
451
452 $h{__ipc}->{run} = 1;
453
454 while (1) {
455 local $SIG{__WARN__} = sub {};
456 last if ! defined $h{__ipc};
457 last if ! $h{__ipc}->{run};
458 }
459
460 IPC::Shareable->clean_up_all if $opts{destroy};
461 exit 0;
462 }
463 }
464 sub unspawn {
465 shift;
466 my ($key, $destroy) = @_;
467
468 $destroy ||= 0;
469
470 tie my %h, 'IPC::Shareable', {
471 key => $key,
472 destroy => $destroy,
473 mode => 0666,
474 };
475
476 $h{__ipc}->{run} = 0;
477
478 $SIG{CHLD} = undef;
479
480 sleep 1;
481
482 IPC::Shareable->clean_up_all if $destroy;
437 return int($count);
483438 }
484439 sub lock {
485440 my ($knot, $flags) = @_;
525480 sub clean_up {
526481 my $class = shift;
527482
528 for my $s (values %process_register) {
483 for my $id (keys %process_register) {
484 my $s = $process_register{$id};
529485 next unless $s->attributes('owner') == $$;
530486 next if $s->attributes('protected');
531487 remove($s);
533489 }
534490 sub clean_up_all {
535491 my $class = shift;
536 for my $s (values %process_register) {
537 next if $s->attributes('protected');
538 remove($s);
539 }
540
541 for my $s (values %global_register) {
492
493 my $global_register = __PACKAGE__->global_register;
494
495 for my $id (keys %$global_register) {
496 my $s = $global_register->{$id};
542497 next if $s->attributes('protected');
543498 remove($s);
544499 }
562517 "clean_up_protected() \$protect_key must be an integer. You sent $protect_key";
563518 }
564519
565 for my $s (values %global_register) {
520 my $global_register = __PACKAGE__->global_register;
521
522 for my $id (keys %$global_register) {
523 my $s = $global_register->{$id};
566524 my $stored_key = $s->attributes('protected');
567525
568526 if ($stored_key && $stored_key == $protect_key) {
615573 }
616574
617575 END {
576 _end();
577 }
578
579 # --- Private methods below
580
581 sub _encode {
582 my ($knot, $seg, $data) = @_;
583
584 my $serializer = $knot->attributes('serializer');
585
586 if ($serializer eq 'storable') {
587 return _freeze($seg, $data);
588 }
589 elsif ($serializer eq 'json'){
590 return _encode_json($seg, $data);
591 }
592
593 return undef;
594 }
595 sub _end {
618596 for my $s (values %process_register) {
619597 unlock($s);
620598 next if $s->attributes('protected');
622600 next if $s->attributes('owner') != $$;
623601 remove($s);
624602 }
625 }
626
627 # --- Private methods below
628
629 sub _encode {
630 my ($knot, $seg, $data) = @_;
631
632 my $serializer = $knot->attributes('serializer');
633
634 if ($serializer eq 'storable') {
635 return _freeze($seg, $data);
636 }
637 elsif ($serializer eq 'json'){
638 return _encode_json($seg, $data);
639 }
640
641 return undef;
642603 }
643604 sub _decode {
644605 my ($knot, $seg) = @_;
813774 $knot->{_data} = _thaw($seg);
814775
815776 if ($sem->getval(SEM_MARKER) != SHM_EXISTS) {
816 $global_register{$knot->seg->id} ||= $knot;
777
778 if (! exists $global_register{$knot->seg->id}) {
779 $global_register{$knot->seg->id} = $knot;
780 }
781
817782 $process_register{$knot->seg->id} ||= $knot;
818783 if (! $sem->setval(SEM_MARKER, SHM_EXISTS)){
819784 croak "Couldn't set semaphore during object creation: $!";
11191084 tie ARRAY, 'IPC::Shareable', OPTIONS;
11201085 tie HASH, 'IPC::Shareable', OPTIONS;
11211086
1122 (tied VARIABLE)->lock;
1123 (tied VARIABLE)->unlock;
1124
1125 (tied VARIABLE)->lock(LOCK_SH|LOCK_NB)
1087 tied(VARIABLE)->lock;
1088 tied(VARIABLE)->unlock;
1089
1090 tied(VARIABLE)->lock(LOCK_SH|LOCK_NB)
11261091 or print "Resource unavailable\n";
11271092
1128 my $segment = (tied VARIABLE)->seg;
1129 my $semaphore = (tied VARIABLE)->sem;
1130
1131 (tied VARIABLE)->remove;
1093 my $segment = tied(VARIABLE)->seg;
1094 my $semaphore = tied(VARIABLE)->sem;
1095
1096 tied(VARIABLE)->remove;
11321097
11331098 IPC::Shareable::clean_up;
11341099 IPC::Shareable::clean_up_all;
11401105
11411106 # Get the actual IPC::Shareable tied object
11421107
1143 my $knot = tied VARIABLE; # Dereference first if necessary
1108 my $knot = tied(VARIABLE); # Dereference first if using a tied reference
11441109
11451110 =head1 DESCRIPTION
11461111
12631228 Set this to a specific integer so we can pass the value to any child objects
12641229 created under the main one.
12651230
1266 To clean up protected objects, call C<< (tied %object)->clean_protected >>.
1231 To clean up protected objects, call
1232 C<< (tied %object)->clean_up_protected(integer) >>, where 'integer' is the
1233 value you set the C<protected> option to. You can call this cleanup routine in
1234 the script you created the segment, or anywhere else, at any time.
12671235
12681236 Default: B<0>
12691237
13211289 create => 0,
13221290 exclusive => 0,
13231291 mode => 0666,
1324 size => IPC::Shareable::SHM_BUFSIZ(),
1292 size => IPC::Shareable::SHM_BUFSIZ(), # 65536
13251293 protected => 0,
13261294 limit => 1,
13271295 destroy => 0,
13361304
13371305 Instantiates and returns a reference to a hash backed by shared memory.
13381306
1307 my $href = IPC::Shareable->new(key => "testing", create => 1);
1308
1309 $href=>{a} = 1;
1310
1311 # Call tied() on the dereferenced variable to access object methods
1312 # and information
1313
1314 tied(%$href)->ipcs;
1315
13391316 Parameters:
13401317
13411318 Hash, Optional: See the L</OPTIONS> section for a list of all available options.
1342 Most often, you'll want to send in the B<key>, B<create> and B<destroy> options.
1319 Most often, you'll want to send in the B<key> and B<create> options.
13431320
13441321 It is possible to get a reference to an array or scalar as well. Simply send in
13451322 either C<< var = > 'ARRAY' >> or C<< var => 'SCALAR' >> to do so.
13681345 =head2 ipcs
13691346
13701347 Returns the number of instantiated shared memory segments that currently exist
1371 on the system.
1348 on the system. This isn't precise; it simply does a C<wc -l> line count on your
1349 system's C<ipcs -m> call. It is guaranteed though to produce reliable results.
13721350
13731351 Return: Integer
1374
1375 =head2 spawn(%opts)
1376
1377 Spawns a forked process running in the background that holds the shared memory
1378 segments backing your variable open.
1379
1380 Parameters:
1381
1382 Paremters are sent in as a hash.
1383
1384 key => $glue
1385
1386 Mandatory, String/Integer: The glue that you will be accessing your data as.
1387
1388 mode => 0666
1389
1390 Optional, Integer: The read/write permissions on the variable. Defaults to
1391 C<0666>.
1392
1393 Example:
1394
1395 use IPC::Shareable;
1396
1397 # The following line sets things up and returns
1398
1399 IPC::Shareable->spawn(key => 'GLUE STRING');
1400
1401 Now, either within the same script, or any other script on the system, your
1402 data will be available at the key/glue C<GLUE STRING>. Call
1403 L<unspawn()|/unspawn($key, $destroy)> to remove it.
1404
1405 =head2 unspawn($key, $destroy)
1406
1407 This method will kill off the background process created with
1408 L<spawn()|/spawn(%opts)>.
1409
1410 Parameters:
1411
1412 $key
1413
1414 Mandatory, String/Integer: The glue (aka key) used in the call to C<spawn()>.
1415
1416 $destroy
1417
1418 Optional, Bool. If set to a true value, we will remove all semaphores and memory
1419 segments related to your data, thus removing the data in its entirety. If not
1420 set to a true value, we'll leave the memory segments in place, and you'll be
1421 able to re-attach to the data at any time. Defaults to false (C<0>).
14221352
14231353 =head2 lock($flags)
14241354
14271357 read/write lock is obtained. Acceptable values for C<$flags> are
14281358 the same as for the C<flock()> system call.
14291359
1430 Returns C<true> on success, and C<undef> on error. For non-blocking calls
1360 Returns C<true> on success, and C<undef> on error. For non-blocking calls
14311361 (see below), the method returns C<0> if it would have blocked.
14321362
14331363 Obtain an exclusive lock like this:
14341364
14351365 tied(%var)->lock(LOCK_EX); # same as default
14361366
1437 Only one process can hold an exclusive lock on the shared memory at
1438 a given time.
1367 Only one process can hold an exclusive lock on the shared memory at a given
1368 time.
14391369
14401370 Obtain a shared (read) lock:
14411371
14591389 details.
14601390
14611391 Locks are inherited through forks, which means that two processes actually
1462 can possess an exclusive lock at the same time. Don't do that.
1392 can possess an exclusive lock at the same time. Don't do that.
14631393
14641394 The constants C<LOCK_EX>, C<LOCK_SH>, C<LOCK_NB>, and C<LOCK_UN> are available
14651395 for import using any of the following export tags:
15221452
15231453 IPC::Shareable provides methods to implement application-level
15241454 advisory locking of the shared data structures. These methods are
1525 called C<shlock()> and C<shunlock()>. To use them you must first get the
1455 called C<lock()> and C<unlock()>. To use them you must first get the
15261456 object underlying the tied variable, either by saving the return
15271457 value of the original call to C<tie()> or by using the built-in C<tied()>
15281458 function.
15471477 also get shared locks or attempt to get a lock without blocking.
15481478
15491479 L<IPC::Shareable> makes the constants C<LOCK_EX>, C<LOCK_SH>, C<LOCK_UN>, and
1550 C<LOCK_NB> exportable to your address space with the export tags
1551 C<:lock>, C<:flock>, or C<:all>. The values should be the same as
1552 the standard C<flock> option arguments.
1480 C<LOCK_NB> exportable to your address space with the export tags C<:lock>,
1481 C<:flock>, or C<:all>. The values should be the same as the standard C<flock>
1482 option arguments.
15531483
15541484 if (tied(%hash)->lock(LOCK_SH|LOCK_NB)){
15551485 print "The value is $hash{a}\n";
15561486 tied(%hash)->unlock;
15571487 } else {
1558 print "Another process has an exlusive lock.\n";
1488 print "Another process has an exclusive lock.\n";
15591489 }
15601490
15611491 If no argument is provided to C<lock>, it defaults to C<LOCK_EX>.
15681498
15691499 Using the advisory locks can speed up processes that are doing several writes/
15701500 reads at the same time.
1571
1572 =head1 REFERENCES
1573
1574 Although references can reside within a shared data structure, the tied variable
1575 can not be a reference itself.
15761501
15771502 =head1 DESTRUCTION
15781503
16541579 method, you must send that integer in as a parameter so we know which segments
16551580 to clean up.
16561581
1582 my $protect_key = 93432;
1583
1584 IPC::Shareable->clean_up_protected($protect_key);
1585
1586 # or
1587
1588 tied($var)->clean_up_protected($protect_key;
1589
1590 # or
1591
1592 $knot->clean_up_protected($protect_key)
1593
16571594 Parameters:
16581595
16591596 $protect_key
16821619
16831620 =item 1
16841621
1685 If the process has been smoked by an untrapped signal, the binding
1686 will remain in shared memory. If you're cautious, you might try
1622 If the process has been smoked by an untrapped signal, the binding will remain
1623 in shared memory. If you're cautious, you might try:
16871624
16881625 $SIG{INT} = \&catch_int;
16891626 sub catch_int {
17091646 signals. Under normal circumstances, C<IPC::Shareable>'s C<END> method
17101647 unlocks any locked variables when the process exits. However, if an
17111648 untrapped signal is received while a process holds an exclusive lock,
1712 C<DESTROY> will not be called and the lock may be maintained even though
1649 C<END> will not be called and the lock may be maintained even though
17131650 the process has exited. If this scares you, you might be better off
17141651 implementing your own locking methods.
17151652
17311668 There is a program called C<ipcs>(1/8) (and C<ipcrm>(1/8)) that is
17321669 available on at least Solaris and Linux that might be useful for
17331670 cleaning moribund shared memory segments or semaphore sets produced
1734 by bugs in either IPC::Shareable or applications using it.
1671 by bugs in either L<IPC::Shareable> or applications using it.
17351672
17361673 Examples:
17371674
17691706 iterating over a hash tied to L<IPC::Shareable>, but we attempt this
17701707 optimization if you do not).
17711708
1772 The C<fetch>/C<thaw> operation is performed
1709 For tied hashes, the C<fetch>/C<thaw> operation is performed
17731710 when the first key is accessed. Subsequent key and and value
17741711 accesses are done without accessing shared memory. Doing an
17751712 assignment to the hash or fetching another value between key
1776 accesses causes the hash to be replaced from shared memory. The
1713 accesses causes the hash to be replaced from shared memory. The
17771714 state of the iterator in this case is not defined by the Perl
1778 documentation. Caveat Emptor.
1715 documentation. Caveat Emptor.
17791716
17801717 =back
17811718
18011738
18021739 L<perltie>, L<Storable>, C<shmget>, C<ipcs>, C<ipcrm> and other SysV IPC manual
18031740 pages.
1804
1805
33 use Data::Dumper;
44 use Test::More;
55
6 BEGIN { use_ok('IPC::Shareable') };
6 BEGIN {
7 if (!$ENV{CI_TESTING}) {
8 plan skip_all => "Not on a valid CI platform...";
9 }
10 use_ok('IPC::Shareable');
11 };
712
8 my $a = tie my $x, 'IPC::Shareable';
9 my $b = tie my $y, 'IPC::Shareable', {create => 1, destroy => 1};
13 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
14 my $segs = IPC::Shareable::ipcs();
15 print "Starting with $segs segments\n";
1016
11 is $a->{_key}, 0, "tie with no glue or options is IPC_PRIVATE ok";
12 is $b->{_key}, 0, "tie with no glue but with options is IPC_PRIVATE ok";
17 is $segs, $segs, "Initial test ok";
1318
14 done_testing();
19 {
20 my $a = tie my $x, 'IPC::Shareable';
21 my $b = tie my $y, 'IPC::Shareable', { create => 1, destroy => 1 };
22
23 is $a->{_key}, 0, "tie with no glue or options is IPC_PRIVATE ok";
24 is $b->{_key}, 0, "tie with no glue but with options is IPC_PRIVATE ok";
25
26 $a->remove;
27
28 # Store existing segments in a shared hash to test against
29 # at conclusion of test suite run
30
31 tie my %store, 'IPC::Shareable', { key => 'async_tests', create => 1 };
32
33 $store{segs} = $segs;
34 }
35
36 IPC::Shareable::_end;
37 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
38
39 done_testing();
99 }
1010 }
1111
12 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
13
1214 my $ok = eval {
1315 tie my $sv, 'IPC::Shareable', {key => 'test02', destroy => 1};
1416 1;
1719 is $ok, undef, "We croak ok if create is not set and segment doesn't yet exist";
1820 like $@, qr/Could not acquire/, "...and error is sane.";
1921
22 IPC::Shareable::_end;
23
24 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
25
2026 done_testing;
2127
1010 plan skip_all => "Not on a legit CI platform...";
1111 }
1212 }
13
14 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1315
1416 # deprecated string key param
1517 {
177179 qr/available key after 10 tries/,
178180 "...the error shows it attempted multiple times";
179181 }
182
183 IPC::Shareable::_end;
184
185 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
186
180187 done_testing();
88 plan skip_all => "Not on a legit CI platform...";
99 }
1010 }
11
12 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1113
1214 tie my $sv, 'IPC::Shareable', {destroy => 1};
1315
2931 is $sv, $mod.'foo', "SCALAR regression store/fetch ok";
3032 }
3133
34 IPC::Shareable::_end;
35 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
36
3237 done_testing();
1010 plan skip_all => "Not on a legit CI platform...";
1111 }
1212 }
13
14 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1315
1416 my $mod = 'IPC::Shareable';
1517
3941 # parent
4042
4143 my $ph = $mod->new(key => 'hash2', create => 1, destroy => 1);
44 like tied(%$ph), qr/IPC::Shareable/, "new() tied hash is proper object ok";
45 like tied(%$ph)->can('ipcs'), qr/CODE/, "...and it can call its methods ok";
46
4247 my $pa = $mod->new(key => 'array2', create => 1, destroy => 1, var => 'ARRAY');
48 like tied(@$pa), qr/IPC::Shareable/, "new() tied array is proper object ok";
49 like tied(@$pa)->can('ipcs'), qr/CODE/, "...and it can call its methods ok";
50
4351 my $ps = $mod->new(key => 'scalar2', create => 1, destroy => 1, var => 'SCALAR');
52 like tied($$ps), qr/IPC::Shareable/, "new() tied scalar is proper object ok";
53 like tied($$ps)->can('ipcs'), qr/CODE/, "...and it can call its methods ok";
4454
4555 kill ALRM => $pid;
4656 waitpid($pid, 0);
6070
6171 IPC::Shareable->clean_up_all;
6272
73 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
74
6375 done_testing();
6476 }
6577
99 plan skip_all => "Not on a legit CI platform...";
1010 }
1111 }
12
13 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1214
1315 my $mod = 'IPC::Shareable';
1416
2325 is ref $k, 'IPC::Shareable', "tied() returns a proper IPC::Shareable object ok";
2426 is exists $k->{attributes}, 1, "...and it has proper attributes ok";
2527
28 IPC::Shareable::_end;
29 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
30
2631 done_testing();
88 plan skip_all => "Not on a legit CI platform...";
99 }
1010 }
11
12 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1113
1214 tie my @av, 'IPC::Shareable', { destroy => 1 };
1315
6365 is $gone[0], 'fie', "splice 3 ok";
6466 is $gone[1], 'foe', "splice 4 ok";
6567
68 IPC::Shareable::_end;
69 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
70
6671 done_testing();
99 plan skip_all => "Not on a legit CI platform...";
1010 }
1111 }
12
13 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1214
1315 my $mod = 'IPC::Shareable';
1416
7880
7981 is %hv, '', "hash deleted after clean_up()";
8082
83 IPC::Shareable::_end;
84 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
85
8186 done_testing();
8287
8388
99 plan skip_all => "Not on a legit CI platform...";
1010 }
1111 }
12
13 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1214
1315 my $k = tie my $sv, 'IPC::Shareable', 'testing', {create => 1, destroy => 1};
1416
5961
6062 is $k->attributes('no_exist'), undef, "attributes() on an undefined attr is undef";
6163
64 IPC::Shareable::_end;
65 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
66
6267 done_testing;
1010 plan skip_all => "Not on a legit CI platform...";
1111 }
1212 }
13
14 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1315
1416 # scalar ref
1517
8991
9092 IPC::Shareable->clean_up_all;
9193
94 IPC::Shareable::_end;
95 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
96
9297 done_testing();
1010 plan skip_all => "Not on a legit CI platform...";
1111 }
1212 }
13
14 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1315
1416 my $awake = 0;
1517 local $SIG{ALRM} = sub { $awake = 1 };
4547 IPC::Shareable->clean_up_all;
4648 }
4749
50 IPC::Shareable::_end;
51 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
52
4853 done_testing();
1010 plan skip_all => "Not on a legit CI platform...";
1111 }
1212 }
13
14 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1315
1416 my $sv;
1517
5153 is $sv, 200, "in parent: locked and updated SV to 200";
5254 }
5355
56 IPC::Shareable::_end;
57 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
58
5459 done_testing();
99 plan skip_all => "Not on a legit CI platform...";
1010 }
1111 }
12
13 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1214
1315 my $t = tie my $sv, 'IPC::Shareable', {
1416 create => 1,
6668 is $t->sem->getval($_), $none[$_], "after share nb lock unlock, sem $_ set to $none[$_] ok";
6769 }
6870
71 IPC::Shareable::_end;
72 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
73
6974 done_testing();
1313 }
1414 }
1515
16 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
17
1618 sub shm_cleaned {
1719 # --- shmread should barf if the segment has really been cleaned
1820 my $id = shift;
192194 }
193195 }
194196
197 IPC::Shareable::_end;
198 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
199
195200 done_testing();
99 plan skip_all => "Not on a legit CI platform...";
1010 }
1111 }
12
13 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1214
1315 my $t = 1;
1416 my $ok = 1;
7779 IPC::Shareable->clean_up_all;
7880 }
7981
82 IPC::Shareable::_end;
83 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
84
8085 done_testing();
99 plan skip_all => "Not on a legit CI platform...";
1010 }
1111 }
12
13 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1214
1315 plan tests => 8;
1416
9092 }
9193 }
9294
95 IPC::Shareable::_end;
96 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
97
9398 #done_testing();
1010 plan skip_all => "Not on a legit CI platform...";
1111 }
1212 }
13
14 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1315
1416 my $t = 1;
1517 my $ok = 1;
7476 is defined $hv, '', "HV cleaned after clean_up_all()";
7577 }
7678
79 IPC::Shareable::_end;
80 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
81
7782 done_testing();
99 plan skip_all => "Not on a legit CI platform...";
1010 }
1111 }
12
13 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1214
1315 my $t = 1;
1416 my $ok = 1;
4850 is $d->first('foo'), 'foo', "shared obj first() returns ok, again";
4951 is $d->second('bar'), 'bar', "shared obj second() returns ok, again";
5052
53 IPC::Shareable::_end;
54 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
55
5156 done_testing();
5257
99 plan skip_all => "Not on a legit CI platform...";
1010 }
1111 }
12
13 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1214
1315 my $t = 1;
1416 my $ok = 1;
8789 is defined $d, '', "parent: after clean_up_all(), everything's gone";
8890 }
8991
92 IPC::Shareable::_end;
93 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
94
9095 done_testing();
9196
1111 plan skip_all => "Not on a legit CI platform...";
1212 }
1313 }
14
15 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1416
1517 my $t = 1;
1618 my $ok = 1;
8082 is %thash, '', "data cleaned up after clean_up_all()";
8183 }
8284
85 IPC::Shareable::_end;
86 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
87
8388 done_testing();
99 }
1010 }
1111
12 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
13
1214 tie my %hv, 'IPC::Shareable', {destroy => 1};
1315
1416 $hv{a} = 'foo';
1921
2022 is %hv, '', "data is removed after tied(\$data)->clean_up()";
2123
24 IPC::Shareable::_end;
25 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
26
2227 done_testing();
1010 plan skip_all => "Not on a legit CI platform...";
1111 }
1212 }
13
14 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1315
1416 my $k = tie my $sv, 'IPC::Shareable', 'test', { create => 1, destroy => 1 };
1517
4951
5052 is $knot_sem->id, $tied_sem->id, "knot and tied sem() hashes have the same id";
5153
54 IPC::Shareable::_end;
55 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
56
5257 done_testing();
5358
1010 plan skip_all => "Not on a legit CI platform...";
1111 }
1212 }
13
14 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1315
1416 # array
1517 {
9698 IPC::Shareable->clean_up_all;
9799 }
98100
101 IPC::Shareable::_end;
102 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
103
99104 done_testing;
100105
101106 sub seg_count {
1010 plan skip_all => "Not on a legit CI platform...";
1111 }
1212 }
13
14 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1315
1416 # array
1517 {
9698 IPC::Shareable->clean_up_all;
9799 }
98100
101 IPC::Shareable::_end;
102 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
103
99104 done_testing;
100105
101106 sub seg_count {
1212 plan skip_all => "This test script can't be run on a perl < 64-bit";
1313 }
1414 }
15
16 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1517
1618 use constant BYTES => 2000000; # ~2MB
1719
104106
105107 $k->clean_up_all;
106108
109 IPC::Shareable::_end;
110 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
111
107112 done_testing();
88 plan skip_all => "Not on a legit CI platform...";
99 }
1010 }
11
12 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1113
1214 my $k = tie my $sv, 'IPC::Shareable', {
1315 create => 1,
2527
2628 (tied $sv)->clean_up_all;
2729
30 IPC::Shareable::_end;
31 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
32
2833 done_testing();
88 plan skip_all => "Not on a legit CI platform...";
99 }
1010 }
11
12 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1113
1214 my $mod = 'IPC::Shareable';
1315
3335
3436 IPC::Shareable->clean_up_all;
3537
38 IPC::Shareable::_end;
39 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
40
3641 done_testing();
+0
-31
t/71-unspawn.t less more
0 use warnings;
1 use strict;
2
3 use Config;
4 use IPC::Shareable;
5 use Test::More;
6
7 BEGIN {
8 if (! $ENV{CI_TESTING}) {
9 plan skip_all => "Not on a legit CI platform...";
10 }
11 if ($Config{nvsize} != 8) {
12 plan skip_all => "Storable not compatible with long doubles";
13 }
14 }
15
16 system "$^X t/_spawn";
17
18 tie my %h, 'IPC::Shareable', {
19 key => 'aaaa',
20 # destroy => 1,
21 mode => 0666,
22 };
23
24 is $h{t70}->[1], 5, "hash element ok";
25
26 IPC::Shareable->unspawn('aaaa');
27
28 is %h, 1, "hash still exists with unspawn and no destroy";
29
30 done_testing();
+0
-30
t/72-unspawn_destroy.t less more
0 use warnings;
1 use strict;
2
3 use Config;
4 use Data::Dumper;
5 use IPC::Shareable;
6 use Test::More;
7
8 BEGIN {
9 if (! $ENV{CI_TESTING}) {
10 plan skip_all => "Not on a legit CI platform...";
11 }
12 if ($Config{nvsize} != 8) {
13 plan skip_all => "Storable not compatible with long doubles";
14 }
15 }
16
17 tie my %h, 'IPC::Shareable', {
18 key => 'aaaa',
19 destroy => 1,
20 mode => 0666,
21 };
22
23 is $h{t70}->[1], 5, "hash element ok";
24
25 IPC::Shareable->unspawn('aaaa', 1);
26
27 is %h, '', "hash deleted after calling unspawn() with destroy => 1";
28
29 done_testing();
88 plan skip_all => "Not on a legit CI platform...";
99 }
1010 }
11
12 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1113
1214 # non-graceful
1315 {
6466 is
6567 $@,
6668 '',
67 "with 'graceful', we silently exit if two attemps made on same exclusive seg";
69 "with 'graceful', we silently exit if two attempts made on same exclusive seg";
70
71 IPC::Shareable::_end;
72 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
6873
6974 done_testing;
7075 };
88 plan skip_all => "Not on a legit CI platform...";
99 }
1010 }
11
12 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1113
1214 # bad param
1315
3638 END {
3739 is $proc, -1, "singleton() on second call doesn't return anything ok";
3840 is $warning, undef, "singleton outputs no warnings by default";
41
42 IPC::Shareable::_end;
43 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
44
3945 done_testing;
4046 };
88 plan skip_all => "Not on a legit CI platform...";
99 }
1010 }
11
12 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1113
1214 # singleton no exit notice
1315 my ($proc, $warning);
3335 qr/exited due to exclusive shared memory collision/,
3436 "singleton() warns if warn is enabled";
3537
38 IPC::Shareable::_end;
39 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
40
3641 done_testing;
3742 };
1111 plan skip_all => "Not on a legit CI platform...";
1212 }
1313 }
14
15 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1416
1517 {
1618 # exclusive duplicate
4042
4143 }
4244
45 IPC::Shareable::_end;
46 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
47
4348 done_testing();
00 use warnings;
11 use strict;
22
3 use Data::Dumper;
43 use IPC::Shareable;
54 use Test::More;
5
6 my $segs_before;
67
78 BEGIN {
89 if (! $ENV{CI_TESTING}) {
910 plan skip_all => "Not on a legit CI platform...";
1011 }
1112
12 my $async_loaded = eval {
13 require Async::Event::Interval;
14 1;
13 if (! $ENV{RELEASE_TESTING}) {
14 plan skip_all => "Developer only test...";
15 }
16
17 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
18 $segs_before = IPC::Shareable::ipcs();
19 }
20
21 use Async::Event::Interval;
22
23 {
24 tie my %shared_data, 'IPC::Shareable', {
25 key => 'fork rand dup keys',
26 create => 1,
27 destroy => 1
1528 };
1629
17 if (! $async_loaded) {
18 plan skip_all => "Async::Event::Interval not loaded...";
19 }
30 my $event_one = Async::Event::Interval->new(0, sub {$shared_data{$$}{called}++});
31 my $event_two = Async::Event::Interval->new(0, sub {$shared_data{$$}{called}++});
32
33 $event_one->start;
34 $event_two->start;
35
36 sleep 1;
37
38 $event_one->stop;
39 $event_two->stop;
40
41 my $one_pid = $event_one->pid;
42 my $two_pid = $event_two->pid;
43
44 is exists $shared_data{$one_pid}{called}, 1, "Event one got a rand shm key ok";
45 is exists $shared_data{$two_pid}{called}, 1, "Adding srand() ensures _shm_key_rand() gives out rand key in fork()";
46
47 IPC::Shareable::clean_up_all;
2048 }
2149
22 tie my %shared_data, 'IPC::Shareable', {
23 key => '123456789',
24 create => 1,
25 destroy => 1
26 };
50 Async::Event::Interval::_end;
51 IPC::Shareable::_end;
2752
28 $shared_data{$$}{called}++;
53 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
54 my $segs_after = IPC::Shareable::ipcs();
2955
30 my $event_one = Async::Event::Interval->new(0, sub {$shared_data{$$}{called}++});
31 my $event_two = Async::Event::Interval->new(0, sub {$shared_data{$$}{called}++});
32
33 $event_one->start;
34 $event_two->start;
35
36 sleep 1;
37
38 $event_one->stop;
39 $event_two->stop;
40
41 my $one_pid = $event_one->pid;
42 my $two_pid = $event_two->pid;
43
44 is exists $shared_data{$one_pid}{called}, 1, "Event one got a rand shm key ok";
45 is exists $shared_data{$two_pid}{called}, 1, "Adding srand() ensures _shm_key_rand() gives out rand key in fork()";
46
47 (tied %shared_data)->remove;
56 is $segs_after, $segs_before, "All segs, even those created in separate procs, cleaned up ok";
4857
4958 done_testing();
99 }
1010 }
1111
12 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
13
1214 my @command = ('date');
1315 my $rc = system( @command );
1416
1517 is $rc, 0, "system() returns success ok after moving CHLD handler";
1618
19 IPC::Shareable::_end;
20 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
21
1722 done_testing();
99 plan skip_all => "Not on a legit CI platform...";
1010 }
1111 }
12
13 warn "Segs Before: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
1214
1315 my $protect_lock = 292;
1416
8587 $segs = keys %{ IPC::Shareable::global_register() };
8688 is $segs, 0, "After clean_up_protected(), global register has 0 segments ok";
8789
90 IPC::Shareable::_end;
91 warn "Segs After: " . IPC::Shareable::ipcs() . "\n" if $ENV{PRINT_SEGS};
92
8893 done_testing();
+0
-42
t/85-spawn_object_contains_data.t less more
0 use warnings;
1 use strict;
2
3 use lib 't/';
4 use Test::More;
5
6 BEGIN {
7 if (! $ENV{CI_TESTING}) {
8 plan skip_all => "Not on a legit CI platform...";
9 }
10 if (!$ENV{IPC_SPAWN_TEST}) {
11 plan skip_all => "IPC_SPAWN_TEST env var not set";
12 }
13 }
14
15 use SpawnTest;
16 use IPC::Shareable;
17
18 if (! $ENV{CI_TESTING}) {
19 plan skip_all => "Not on a legit CI platform...";
20 }
21 if (! $ENV{IPC_SPAWN_TEST}) {
22 plan skip_all => "IPC_SPAWN_TEST env var not set";
23 }
24
25 my $obj = SpawnTest->new;
26
27 $obj->add(27);
28 is $obj->{data}{add}, 27, "add() adds 27 ok";
29 $obj->add(27);
30 is $obj->{data}{add}, 54, "add() with 27 again is 54 ok";
31
32
33 for (0..10){
34 $obj->push($_);
35 is $obj->{data}{array}[$_], $_, "push() with $_ is $_ ok";
36 }
37
38 $obj->push(99);
39 is $obj->{data}{array}[11], 99, "push() pushes 99 into last elem ok";
40
41 done_testing();
+0
-36
t/86-unspawn_object_contains_data.t less more
0 use warnings;
1 use strict;
2
3 use lib 't/';
4
5 use Test::More;
6
7 BEGIN {
8 if (! $ENV{CI_TESTING}) {
9 plan skip_all => "Not on a legit CI platform...";
10 }
11 if (!$ENV{IPC_SPAWN_TEST}) {
12 plan skip_all => "IPC_SPAWN_TEST env var not set";
13 }
14 }
15
16 use SpawnTest;
17 use IPC::Shareable;
18
19 my $obj = SpawnTest->new;
20
21 is $obj->{data}{add}, 54, "data retained 54 in add()";
22 $obj->add(27);
23 is $obj->{data}{add}, 81, "add() with 27 again works ok (81)";
24
25
26 for (0..10){
27 is $obj->{data}{array}[$_], $_, "push() with $_ is $_ ok";
28 }
29
30 $obj->push(100);
31 is $obj->{data}{array}[12], 100, "push() pushes 100 into new last elem ok";
32
33 $obj->clean;
34
35 done_testing();
0 use 5.006;
1 use strict;
2 use warnings;
3
4 use IPC::Shareable;
5 use Test::More;
6
7 BEGIN {
8 use_ok( 'IPC::Shareable' ) || print "Bail out!\n";
9 }
10
11 if (! $ENV{CI_TESTING}) {
12 done_testing();
13 exit;
14 }
15
16 tie my %store, 'IPC::Shareable', {key => 'async_tests', destroy => 1};
17
18 my $start_segs = $store{segs};
19 IPC::Shareable::clean_up_all;
20
21 my $segs = IPC::Shareable::ipcs();
22
23 is $segs, $start_segs, "All test segments cleaned up after test run";
24
25 print "Started with $start_segs, ending with $segs\n";
26
27 done_testing();
+0
-35
t/SpawnTest.pm less more
0 package SpawnTest;
1
2 use warnings;
3 use strict;
4
5 use IPC::Shareable;
6
7 system "perl t/_spawn_class";
8
9 tie my %h, 'IPC::Shareable', {
10 key => 'bbbb',
11 };
12
13 sub new {
14 my ($class) = @_;
15 return bless { data => \%h }, $class;
16 }
17 sub add {
18 my ($self, $num) = @_;
19 die "need a num param\n" if ! defined $num;
20 $self->data->{add} += $num;
21 }
22 sub push {
23 my ($self, $value) = @_;
24 die "need a value param\n" if ! defined $value;
25 push @{ $self->data->{array} }, $value;
26 }
27 sub data {
28 return $_[0]->{data};
29 }
30
31 sub clean {
32 IPC::Shareable->unspawn('bbbb', 1);
33 }
34 1;
+0
-16
t/_spawn less more
0 use warnings;
1 use strict;
2
3 use IPC::Shareable;
4
5 IPC::Shareable->spawn(
6 key => 'aaaa'
7 );
8
9 sleep 1;
10
11 tie my %h, 'IPC::Shareable', {
12 key => 'aaaa',
13 };
14
15 $h{t70}->[1] = 5;
+0
-13
t/_spawn_class less more
0 use warnings;
1 use strict;
2
3 use IPC::Shareable;
4
5 IPC::Shareable->spawn(
6 key => 'bbbb',
7
8 create => 1
9 );
10
11 sleep 1;
12 exit 0;