1use strict; 2use warnings; 3 4BEGIN { 5 use Config; 6 if (! $Config{'useithreads'}) { 7 print("1..0 # SKIP Perl not compiled with 'useithreads'\n"); 8 exit(0); 9 } 10 if ($] < 5.010) { 11 print("1..0 # SKIP Needs Perl 5.10.0 or later\n"); 12 exit(0); 13 } 14} 15 16use ExtUtils::testlib; 17 18BEGIN { 19 $| = 1; 20 print("1..133\n"); ### Number of tests that will be run ### 21}; 22 23use threads; 24use threads::shared; 25 26my $TEST; 27BEGIN { 28 share($TEST); 29 $TEST = 1; 30} 31 32sub ok { 33 my ($ok, $name) = @_; 34 35 lock($TEST); 36 my $id = $TEST++; 37 38 # You have to do it this way or VMS will get confused. 39 if ($ok) { 40 print("ok $id - $name\n"); 41 } else { 42 print("not ok $id - $name\n"); 43 printf("# Failed test at line %d\n", (caller)[2]); 44 } 45 46 return ($ok); 47} 48 49ok(1, 'Loaded'); 50 51### Start of Testing ### 52 53my $ID :shared = -1; 54my (@created, @destroyed); 55 56{ package HashObj; 57 sub new { 58 my $class = shift; 59 my $self = &threads::shared::share({}); 60 $$self{'ID'} = ++$ID; 61 $created[$ID] = 1; 62 return bless($self, $class); 63 } 64 65 sub DESTROY { 66 my $self = shift; 67 $destroyed[$$self{'ID'}] = 1; 68 } 69} 70 71{ package AryObj; 72 sub new { 73 my $class = shift; 74 my $self = &threads::shared::share([]); 75 $$self[0] = ++$ID; 76 $created[$ID] = 1; 77 return bless($self, $class); 78 } 79 80 sub DESTROY { 81 my $self = shift; 82 $destroyed[$$self[0]] = 1; 83 } 84} 85 86{ package SclrObj; 87 sub new { 88 my $class = shift; 89 my $self = \do{ my $scalar = ++$ID; }; 90 $created[$ID] = 1; 91 threads::shared::share($self); 92 return bless($self, $class); 93 } 94 95 sub DESTROY { 96 my $self = shift; 97 $destroyed[$$self] = 1; 98 } 99} 100 101# Testing with normal array 102my @normal_ary; 103 104# Testing with hash object 105$normal_ary[0] = HashObj->new(); 106ok($created[$ID], 'Created hash object in normal array'); 107delete($normal_ary[0]); 108ok($destroyed[$ID], 'Deleted hash object in normal array'); 109 110$normal_ary[0] = HashObj->new(); 111ok($created[$ID], 'Created hash object in normal array'); 112$normal_ary[0] = undef; 113ok($destroyed[$ID], 'Undef hash object in normal array'); 114 115$normal_ary[0] = HashObj->new(); 116ok($created[$ID], 'Created hash object in normal array'); 117$normal_ary[0] = HashObj->new(); 118ok($created[$ID], 'Created hash object in normal array'); 119ok($destroyed[$ID-1], 'Replaced hash object in normal array'); 120@normal_ary = (); 121ok($destroyed[$ID], 'Hash object removed from cleared normal array'); 122 123$normal_ary[0] = HashObj->new(); 124ok($created[$ID], 'Created hash object in normal array'); 125undef(@normal_ary); 126ok($destroyed[$ID], 'Hash object removed from undef normal array'); 127 128# Testing with array object 129$normal_ary[0] = AryObj->new(); 130ok($created[$ID], 'Created array object in normal array'); 131delete($normal_ary[0]); 132ok($destroyed[$ID], 'Deleted array object in normal array'); 133 134$normal_ary[0] = AryObj->new(); 135ok($created[$ID], 'Created array object in normal array'); 136$normal_ary[0] = undef; 137ok($destroyed[$ID], 'Undef array object in normal array'); 138 139$normal_ary[0] = AryObj->new(); 140ok($created[$ID], 'Created array object in normal array'); 141$normal_ary[0] = AryObj->new(); 142ok($created[$ID], 'Created array object in normal array'); 143ok($destroyed[$ID-1], 'Replaced array object in normal array'); 144@normal_ary = (); 145ok($destroyed[$ID], 'Array object removed from cleared normal array'); 146 147$normal_ary[0] = AryObj->new(); 148ok($created[$ID], 'Created array object in normal array'); 149undef(@normal_ary); 150ok($destroyed[$ID], 'Array object removed from undef normal array'); 151 152# Testing with scalar object 153$normal_ary[0] = SclrObj->new(); 154ok($created[$ID], 'Created scalar object in normal array'); 155delete($normal_ary[0]); 156ok($destroyed[$ID], 'Deleted scalar object in normal array'); 157 158$normal_ary[0] = SclrObj->new(); 159ok($created[$ID], 'Created scalar object in normal array'); 160$normal_ary[0] = undef; 161ok($destroyed[$ID], 'Undef scalar object in normal array'); 162 163$normal_ary[0] = SclrObj->new(); 164ok($created[$ID], 'Created scalar object in normal array'); 165$normal_ary[0] = SclrObj->new(); 166ok($created[$ID], 'Created scalar object in normal array'); 167ok($destroyed[$ID-1], 'Replaced scalar object in normal array'); 168@normal_ary = (); 169ok($destroyed[$ID], 'Scalar object removed from cleared normal array'); 170 171$normal_ary[0] = SclrObj->new(); 172ok($created[$ID], 'Created scalar object in normal array'); 173undef(@normal_ary); 174ok($destroyed[$ID], 'Scalar object removed from undef normal array'); 175 176# Testing with normal hash 177my %normal_hash; 178 179# Testing with hash object 180$normal_hash{'obj'} = HashObj->new(); 181ok($created[$ID], 'Created hash object in normal hash'); 182delete($normal_hash{'obj'}); 183ok($destroyed[$ID], 'Deleted hash object in normal hash'); 184 185$normal_hash{'obj'} = HashObj->new(); 186ok($created[$ID], 'Created hash object in normal hash'); 187$normal_hash{'obj'} = undef; 188ok($destroyed[$ID], 'Undef hash object in normal hash'); 189 190$normal_hash{'obj'} = HashObj->new(); 191ok($created[$ID], 'Created hash object in normal hash'); 192$normal_hash{'obj'} = HashObj->new(); 193ok($created[$ID], 'Created hash object in normal hash'); 194ok($destroyed[$ID-1], 'Replaced hash object in normal hash'); 195%normal_hash = (); 196ok($destroyed[$ID], 'Hash object removed from cleared normal hash'); 197 198$normal_hash{'obj'} = HashObj->new(); 199ok($created[$ID], 'Created hash object in normal hash'); 200undef(%normal_hash); 201ok($destroyed[$ID], 'Hash object removed from undef normal hash'); 202 203# Testing with array object 204$normal_hash{'obj'} = AryObj->new(); 205ok($created[$ID], 'Created array object in normal hash'); 206delete($normal_hash{'obj'}); 207ok($destroyed[$ID], 'Deleted array object in normal hash'); 208 209$normal_hash{'obj'} = AryObj->new(); 210ok($created[$ID], 'Created array object in normal hash'); 211$normal_hash{'obj'} = undef; 212ok($destroyed[$ID], 'Undef array object in normal hash'); 213 214$normal_hash{'obj'} = AryObj->new(); 215ok($created[$ID], 'Created array object in normal hash'); 216$normal_hash{'obj'} = AryObj->new(); 217ok($created[$ID], 'Created array object in normal hash'); 218ok($destroyed[$ID-1], 'Replaced array object in normal hash'); 219%normal_hash = (); 220ok($destroyed[$ID], 'Array object removed from cleared normal hash'); 221 222$normal_hash{'obj'} = AryObj->new(); 223ok($created[$ID], 'Created array object in normal hash'); 224undef(%normal_hash); 225ok($destroyed[$ID], 'Array object removed from undef normal hash'); 226 227# Testing with scalar object 228$normal_hash{'obj'} = SclrObj->new(); 229ok($created[$ID], 'Created scalar object in normal hash'); 230delete($normal_hash{'obj'}); 231ok($destroyed[$ID], 'Deleted scalar object in normal hash'); 232 233$normal_hash{'obj'} = SclrObj->new(); 234ok($created[$ID], 'Created scalar object in normal hash'); 235$normal_hash{'obj'} = undef; 236ok($destroyed[$ID], 'Undef scalar object in normal hash'); 237 238$normal_hash{'obj'} = SclrObj->new(); 239ok($created[$ID], 'Created scalar object in normal hash'); 240$normal_hash{'obj'} = SclrObj->new(); 241ok($created[$ID], 'Created scalar object in normal hash'); 242ok($destroyed[$ID-1], 'Replaced scalar object in normal hash'); 243%normal_hash = (); 244ok($destroyed[$ID], 'Scalar object removed from cleared normal hash'); 245 246$normal_hash{'obj'} = SclrObj->new(); 247ok($created[$ID], 'Created scalar object in normal hash'); 248undef(%normal_hash); 249ok($destroyed[$ID], 'Scalar object removed from undef normal hash'); 250 251# Testing with shared array 252my @shared_ary :shared; 253 254# Testing with hash object 255$shared_ary[0] = HashObj->new(); 256ok($created[$ID], 'Created hash object in shared array'); 257delete($shared_ary[0]); 258ok($destroyed[$ID], 'Deleted hash object in shared array'); 259 260$shared_ary[0] = HashObj->new(); 261ok($created[$ID], 'Created hash object in shared array'); 262$shared_ary[0] = undef; 263ok($destroyed[$ID], 'Undef hash object in shared array'); 264 265$shared_ary[0] = HashObj->new(); 266ok($created[$ID], 'Created hash object in shared array'); 267$shared_ary[0] = HashObj->new(); 268ok($created[$ID], 'Created hash object in shared array'); 269ok($destroyed[$ID-1], 'Replaced hash object in shared array'); 270@shared_ary = (); 271ok($destroyed[$ID], 'Hash object removed from cleared shared array'); 272 273$shared_ary[0] = HashObj->new(); 274ok($created[$ID], 'Created hash object in shared array'); 275undef(@shared_ary); 276ok($destroyed[$ID], 'Hash object removed from undef shared array'); 277 278# Testing with array object 279$shared_ary[0] = AryObj->new(); 280ok($created[$ID], 'Created array object in shared array'); 281delete($shared_ary[0]); 282ok($destroyed[$ID], 'Deleted array object in shared array'); 283 284$shared_ary[0] = AryObj->new(); 285ok($created[$ID], 'Created array object in shared array'); 286$shared_ary[0] = undef; 287ok($destroyed[$ID], 'Undef array object in shared array'); 288 289$shared_ary[0] = AryObj->new(); 290ok($created[$ID], 'Created array object in shared array'); 291$shared_ary[0] = AryObj->new(); 292ok($created[$ID], 'Created array object in shared array'); 293ok($destroyed[$ID-1], 'Replaced array object in shared array'); 294@shared_ary = (); 295ok($destroyed[$ID], 'Array object removed from cleared shared array'); 296 297$shared_ary[0] = AryObj->new(); 298ok($created[$ID], 'Created array object in shared array'); 299undef(@shared_ary); 300ok($destroyed[$ID], 'Array object removed from undef shared array'); 301 302# Testing with scalar object 303$shared_ary[0] = SclrObj->new(); 304ok($created[$ID], 'Created scalar object in shared array'); 305delete($shared_ary[0]); 306ok($destroyed[$ID], 'Deleted scalar object in shared array'); 307 308$shared_ary[0] = SclrObj->new(); 309ok($created[$ID], 'Created scalar object in shared array'); 310$shared_ary[0] = undef; 311ok($destroyed[$ID], 'Undef scalar object in shared array'); 312 313$shared_ary[0] = SclrObj->new(); 314ok($created[$ID], 'Created scalar object in shared array'); 315$shared_ary[0] = SclrObj->new(); 316ok($created[$ID], 'Created scalar object in shared array'); 317ok($destroyed[$ID-1], 'Replaced scalar object in shared array'); 318@shared_ary = (); 319ok($destroyed[$ID], 'Scalar object removed from cleared shared array'); 320 321$shared_ary[0] = SclrObj->new(); 322ok($created[$ID], 'Created scalar object in shared array'); 323undef(@shared_ary); 324ok($destroyed[$ID], 'Scalar object removed from undef shared array'); 325 326# Testing with shared hash 327my %shared_hash :shared; 328 329# Testing with hash object 330$shared_hash{'obj'} = HashObj->new(); 331ok($created[$ID], 'Created hash object in shared hash'); 332delete($shared_hash{'obj'}); 333ok($destroyed[$ID], 'Deleted hash object in shared hash'); 334 335$shared_hash{'obj'} = HashObj->new(); 336ok($created[$ID], 'Created hash object in shared hash'); 337$shared_hash{'obj'} = undef; 338ok($destroyed[$ID], 'Undef hash object in shared hash'); 339 340$shared_hash{'obj'} = HashObj->new(); 341ok($created[$ID], 'Created hash object in shared hash'); 342$shared_hash{'obj'} = HashObj->new(); 343ok($created[$ID], 'Created hash object in shared hash'); 344ok($destroyed[$ID-1], 'Replaced hash object in shared hash'); 345%shared_hash = (); 346ok($destroyed[$ID], 'Hash object removed from cleared shared hash'); 347 348$shared_hash{'obj'} = HashObj->new(); 349ok($created[$ID], 'Created hash object in shared hash'); 350undef(%shared_hash); 351ok($destroyed[$ID], 'Hash object removed from undef shared hash'); 352 353# Testing with array object 354$shared_hash{'obj'} = AryObj->new(); 355ok($created[$ID], 'Created array object in shared hash'); 356delete($shared_hash{'obj'}); 357ok($destroyed[$ID], 'Deleted array object in shared hash'); 358 359$shared_hash{'obj'} = AryObj->new(); 360ok($created[$ID], 'Created array object in shared hash'); 361$shared_hash{'obj'} = undef; 362ok($destroyed[$ID], 'Undef array object in shared hash'); 363 364$shared_hash{'obj'} = AryObj->new(); 365ok($created[$ID], 'Created array object in shared hash'); 366$shared_hash{'obj'} = AryObj->new(); 367ok($created[$ID], 'Created array object in shared hash'); 368ok($destroyed[$ID-1], 'Replaced array object in shared hash'); 369%shared_hash = (); 370ok($destroyed[$ID], 'Array object removed from cleared shared hash'); 371 372$shared_hash{'obj'} = AryObj->new(); 373ok($created[$ID], 'Created array object in shared hash'); 374undef(%shared_hash); 375ok($destroyed[$ID], 'Array object removed from undef shared hash'); 376 377# Testing with scalar object 378$shared_hash{'obj'} = SclrObj->new(); 379ok($created[$ID], 'Created scalar object in shared hash'); 380delete($shared_hash{'obj'}); 381ok($destroyed[$ID], 'Deleted scalar object in shared hash'); 382 383$shared_hash{'obj'} = SclrObj->new(); 384ok($created[$ID], 'Created scalar object in shared hash'); 385$shared_hash{'obj'} = undef; 386ok($destroyed[$ID], 'Undef scalar object in shared hash'); 387 388$shared_hash{'obj'} = SclrObj->new(); 389ok($created[$ID], 'Created scalar object in shared hash'); 390$shared_hash{'obj'} = SclrObj->new(); 391ok($created[$ID], 'Created scalar object in shared hash'); 392ok($destroyed[$ID-1], 'Replaced scalar object in shared hash'); 393%shared_hash = (); 394ok($destroyed[$ID], 'Scalar object removed from cleared shared hash'); 395 396$shared_hash{'obj'} = SclrObj->new(); 397ok($created[$ID], 'Created scalar object in shared hash'); 398undef(%shared_hash); 399ok($destroyed[$ID], 'Scalar object removed from undef shared hash'); 400 401# Testing with shared scalar 402{ 403 my $shared_scalar : shared; 404 # Use a separate thread to make sure we have no private SV 405 async { $shared_scalar = SclrObj->new(); }->join(); 406} 407ok($destroyed[$ID], 'Scalar object removed from shared scalar'); 408 409# 410# RT #122950 abandoning array elements (e.g. by setting $#ary) 411# should trigger destructors 412 413{ 414 package rt122950; 415 416 my $count = 0; 417 sub DESTROY { $count++ } 418 419 my $n = 4; 420 421 for my $type (0..1) { 422 my @a : shared; 423 $count = 0; 424 push @a, bless &threads::shared::share({}) for 1..$n; 425 for (1..$n) { 426 { # new scope to ensure tmps are freed, destructors called 427 if ($type) { 428 pop @a; 429 } 430 else { 431 $#a = $n - $_ - 1; 432 } 433 } 434 ::ok($count == $_, 435 "remove array object $_ by " . ($type ? "pop" : '$#a=N')); 436 } 437 } 438 439 my @a : shared; 440 $count = 0; 441 push @a, bless &threads::shared::share({}) for 1..$n; 442 { 443 undef @a; # this is implemented internally as $#a = -01 444 } 445 ::ok($count == $n, "remove array object by undef"); 446} 447 448# RT #131124 449# Emptying a shared array creates new temp SVs. If there are no spare 450# SVs, a new arena is allocated. shared.xs was mallocing a new arena 451# with the wrong perl context set, meaning that when the arena was later 452# freed, it would "panic: realloc from wrong pool" 453# 454 455{ 456 threads->new(sub { 457 my @a :shared; 458 push @a, bless &threads::shared::share({}) for 1..1000; 459 undef @a; # this creates lots of temp SVs 460 })->join; 461 ok(1, "#131124 undef array doesnt panic"); 462 463 threads->new(sub { 464 my @a :shared; 465 push @a, bless &threads::shared::share({}) for 1..1000; 466 @a = (); # this creates lots of temp SVs 467 })->join; 468 ok(1, "#131124 clear array doesnt panic"); 469} 470 471 472# EOF 473