1b39c5158Smillertuse strict; 2b39c5158Smillertuse warnings; 3b39c5158Smillert 4b39c5158SmillertBEGIN { 5b39c5158Smillert require($ENV{PERL_CORE} ? '../../t/test.pl' : './t/test.pl'); 6b39c5158Smillert 7b39c5158Smillert use Config; 8b39c5158Smillert if (! $Config{'useithreads'}) { 9b39c5158Smillert skip_all(q/Perl not compiled with 'useithreads'/); 10b39c5158Smillert } 11b39c5158Smillert} 12b39c5158Smillert 13b39c5158Smillertuse ExtUtils::testlib; 14*e0680481Safresh1use Data::Dumper; 15b39c5158Smillert 16b39c5158Smillertuse threads; 17b39c5158Smillert 18b39c5158SmillertBEGIN { 19b39c5158Smillert if (! eval 'use threads::shared; 1') { 20b39c5158Smillert skip_all('threads::shared not available'); 21b39c5158Smillert } 22b39c5158Smillert 23b39c5158Smillert $| = 1; 24898184e3Ssthen print("1..35\n"); ### Number of tests that will be run ### 25b39c5158Smillert}; 26b39c5158Smillert 27b39c5158Smillertprint("ok 1 - Loaded\n"); 28b39c5158Smillert 29b39c5158Smillert### Start of Testing ### 30b39c5158Smillert 31b39c5158Smillertsub content { 32b39c5158Smillert print shift; 33b39c5158Smillert return shift; 34b39c5158Smillert} 35b39c5158Smillert{ 36b39c5158Smillert my $t = threads->create(\&content, "ok 2\n", "ok 3\n", 1..1000); 37b39c5158Smillert print $t->join(); 38b39c5158Smillert} 39b39c5158Smillert{ 40b39c5158Smillert my $lock : shared; 41b39c5158Smillert my $t; 42b39c5158Smillert { 43b39c5158Smillert lock($lock); 44b39c5158Smillert $t = threads->create(sub { lock($lock); print "ok 5\n"}); 45b39c5158Smillert print "ok 4\n"; 46b39c5158Smillert } 47b39c5158Smillert $t->join(); 48b39c5158Smillert} 49b39c5158Smillert 50b39c5158Smillertsub dorecurse { 51b39c5158Smillert my $val = shift; 52b39c5158Smillert my $ret; 53b39c5158Smillert print $val; 54b39c5158Smillert if(@_) { 55b39c5158Smillert $ret = threads->create(\&dorecurse, @_); 56b39c5158Smillert $ret->join; 57b39c5158Smillert } 58b39c5158Smillert} 59b39c5158Smillert{ 60b39c5158Smillert my $t = threads->create(\&dorecurse, map { "ok $_\n" } 6..10); 61b39c5158Smillert $t->join(); 62b39c5158Smillert} 63b39c5158Smillert 64b39c5158Smillert{ 65b39c5158Smillert # test that sleep lets other thread run 66b39c5158Smillert my $t = threads->create(\&dorecurse, "ok 11\n"); 67b39c5158Smillert threads->yield; # help out non-preemptive thread implementations 68b39c5158Smillert sleep 1; 69b39c5158Smillert print "ok 12\n"; 70b39c5158Smillert $t->join(); 71b39c5158Smillert} 72b39c5158Smillert{ 73b39c5158Smillert my $lock : shared; 74b39c5158Smillert sub islocked { 75b39c5158Smillert lock($lock); 76b39c5158Smillert my $val = shift; 77b39c5158Smillert my $ret; 78b39c5158Smillert print $val; 79b39c5158Smillert if (@_) { 80b39c5158Smillert $ret = threads->create(\&islocked, shift); 81b39c5158Smillert } 82b39c5158Smillert return $ret; 83b39c5158Smillert } 84b39c5158Smillertmy $t = threads->create(\&islocked, "ok 13\n", "ok 14\n"); 85b39c5158Smillert$t->join->join; 86b39c5158Smillert} 87b39c5158Smillert 88b39c5158Smillert 89b39c5158Smillert 90b39c5158Smillertsub testsprintf { 91b39c5158Smillert my $testno = shift; 92b39c5158Smillert my $same = sprintf( "%0.f", $testno); 93b39c5158Smillert return $testno eq $same; 94b39c5158Smillert} 95b39c5158Smillert 96b39c5158Smillertsub threaded { 97b39c5158Smillert my ($string, $string_end) = @_; 98b39c5158Smillert 99b39c5158Smillert # Do the match, saving the output in appropriate variables 100b39c5158Smillert $string =~ /(.*)(is)(.*)/; 101b39c5158Smillert # Yield control, allowing the other thread to fill in the match variables 102b39c5158Smillert threads->yield(); 103b39c5158Smillert # Examine the match variable contents; on broken perls this fails 104b39c5158Smillert return $3 eq $string_end; 105b39c5158Smillert} 106b39c5158Smillert 107b39c5158Smillert 108b39c5158Smillert{ 109b39c5158Smillert curr_test(15); 110b39c5158Smillert 111b39c5158Smillert my $thr1 = threads->create(\&testsprintf, 15); 112b39c5158Smillert my $thr2 = threads->create(\&testsprintf, 16); 113b39c5158Smillert 114b39c5158Smillert my $short = "This is a long string that goes on and on."; 115b39c5158Smillert my $shorte = " a long string that goes on and on."; 116b39c5158Smillert my $long = "This is short."; 117b39c5158Smillert my $longe = " short."; 118b39c5158Smillert my $foo = "This is bar bar bar."; 119b39c5158Smillert my $fooe = " bar bar bar."; 120b39c5158Smillert my $thr3 = new threads \&threaded, $short, $shorte; 121b39c5158Smillert my $thr4 = new threads \&threaded, $long, $longe; 122b39c5158Smillert my $thr5 = new threads \&testsprintf, 19; 123b39c5158Smillert my $thr6 = new threads \&testsprintf, 20; 124b39c5158Smillert my $thr7 = new threads \&threaded, $foo, $fooe; 125b39c5158Smillert 126b39c5158Smillert ok($thr1->join()); 127b39c5158Smillert ok($thr2->join()); 128b39c5158Smillert ok($thr3->join()); 129b39c5158Smillert ok($thr4->join()); 130b39c5158Smillert ok($thr5->join()); 131b39c5158Smillert ok($thr6->join()); 132b39c5158Smillert ok($thr7->join()); 133b39c5158Smillert} 134b39c5158Smillert 135b39c5158Smillert# test that 'yield' is importable 136b39c5158Smillert 137b39c5158Smillertpackage Test1; 138b39c5158Smillert 139b39c5158Smillertuse threads 'yield'; 140b39c5158Smillertyield; 141b39c5158Smillertmain::ok(1); 142b39c5158Smillert 143b39c5158Smillertpackage main; 144b39c5158Smillert 145b39c5158Smillert 146b39c5158Smillert# test async 147b39c5158Smillert 148b39c5158Smillert{ 149b39c5158Smillert my $th = async {return 1 }; 150b39c5158Smillert ok($th); 151b39c5158Smillert ok($th->join()); 152b39c5158Smillert} 153b39c5158Smillert{ 154b39c5158Smillert # There is a miniscule chance this test case may falsely fail 155b39c5158Smillert # since it tests using rand() 156b39c5158Smillert my %rand : shared; 157b39c5158Smillert rand(10); 158b39c5158Smillert threads->create( sub { $rand{int(rand(10000000000))}++ } ) foreach 1..25; 159b39c5158Smillert $_->join foreach threads->list; 160*e0680481Safresh1 ok((keys %rand >= 23), "Check that rand() is randomized in new threads") 161*e0680481Safresh1 or diag Dumper(\%rand); 162b39c5158Smillert} 163b39c5158Smillert 164b39c5158Smillert# bugid #24165 165b39c5158Smillert 1669f11ffb7Safresh1run_perl(prog => 'use threads 2.21;' . 167b39c5158Smillert 'sub a{threads->create(shift)} $t = a sub{};' . 168b39c5158Smillert '$t->tid; $t->join; $t->tid', 169b39c5158Smillert nolib => ($ENV{PERL_CORE}) ? 0 : 1, 170b39c5158Smillert switches => ($ENV{PERL_CORE}) ? [] : [ '-Mblib' ]); 171b39c5158Smillertis($?, 0, 'coredump in global destruction'); 172b39c5158Smillert 173b39c5158Smillert# Attempt to free unreferenced scalar... 174b39c5158Smillertfresh_perl_is(<<'EOI', 'ok', { }, 'thread sub via scalar'); 175b39c5158Smillert use threads; 176b39c5158Smillert my $test = sub {}; 177b39c5158Smillert threads->create($test)->join(); 178b39c5158Smillert print 'ok'; 179b39c5158SmillertEOI 180b39c5158Smillert 181b39c5158Smillert# Attempt to free unreferenced scalar... 182b39c5158Smillertfresh_perl_is(<<'EOI', 'ok', { }, 'thread sub via $_[0]'); 183b39c5158Smillert use threads; 184b39c5158Smillert sub thr { threads->new($_[0]); } 185b39c5158Smillert thr(sub { })->join; 186b39c5158Smillert print 'ok'; 187b39c5158SmillertEOI 188b39c5158Smillert 189b39c5158Smillert# [perl #45053] Memory corruption from eval return in void context 190b39c5158Smillertfresh_perl_is(<<'EOI', 'ok', { }, 'void eval return'); 191b39c5158Smillert use threads; 192b39c5158Smillert threads->create(sub { eval '1' }); 193b39c5158Smillert $_->join() for threads->list; 194b39c5158Smillert print 'ok'; 195b39c5158SmillertEOI 196b39c5158Smillert 197b39c5158Smillert# test CLONE_SKIP() functionality 198b39c5158SmillertSKIP: { 199b39c5158Smillert skip('CLONE_SKIP not implemented in Perl < 5.8.7', 5) if ($] < 5.008007); 200b39c5158Smillert 201b39c5158Smillert my %c : shared; 202b39c5158Smillert my %d : shared; 203b39c5158Smillert 204b39c5158Smillert # --- 205b39c5158Smillert 206b39c5158Smillert package A; 207b39c5158Smillert sub CLONE_SKIP { $c{"A-$_[0]"}++; 1; } 208b39c5158Smillert sub DESTROY { $d{"A-". ref $_[0]}++ } 209b39c5158Smillert 210b39c5158Smillert package A1; 211b39c5158Smillert our @ISA = qw(A); 212b39c5158Smillert sub CLONE_SKIP { $c{"A1-$_[0]"}++; 1; } 213b39c5158Smillert sub DESTROY { $d{"A1-". ref $_[0]}++ } 214b39c5158Smillert 215b39c5158Smillert package A2; 216b39c5158Smillert our @ISA = qw(A1); 217b39c5158Smillert 218b39c5158Smillert # --- 219b39c5158Smillert 220b39c5158Smillert package B; 221b39c5158Smillert sub CLONE_SKIP { $c{"B-$_[0]"}++; 0; } 222b39c5158Smillert sub DESTROY { $d{"B-" . ref $_[0]}++ } 223b39c5158Smillert 224b39c5158Smillert package B1; 225b39c5158Smillert our @ISA = qw(B); 226b39c5158Smillert sub CLONE_SKIP { $c{"B1-$_[0]"}++; 1; } 227b39c5158Smillert sub DESTROY { $d{"B1-" . ref $_[0]}++ } 228b39c5158Smillert 229b39c5158Smillert package B2; 230b39c5158Smillert our @ISA = qw(B1); 231b39c5158Smillert 232b39c5158Smillert # --- 233b39c5158Smillert 234b39c5158Smillert package C; 235b39c5158Smillert sub CLONE_SKIP { $c{"C-$_[0]"}++; 1; } 236b39c5158Smillert sub DESTROY { $d{"C-" . ref $_[0]}++ } 237b39c5158Smillert 238b39c5158Smillert package C1; 239b39c5158Smillert our @ISA = qw(C); 240b39c5158Smillert sub CLONE_SKIP { $c{"C1-$_[0]"}++; 0; } 241b39c5158Smillert sub DESTROY { $d{"C1-" . ref $_[0]}++ } 242b39c5158Smillert 243b39c5158Smillert package C2; 244b39c5158Smillert our @ISA = qw(C1); 245b39c5158Smillert 246b39c5158Smillert # --- 247b39c5158Smillert 248b39c5158Smillert package D; 249b39c5158Smillert sub DESTROY { $d{"D-" . ref $_[0]}++ } 250b39c5158Smillert 251b39c5158Smillert package D1; 252b39c5158Smillert our @ISA = qw(D); 253b39c5158Smillert 254b39c5158Smillert package main; 255b39c5158Smillert 256b39c5158Smillert { 257b39c5158Smillert my @objs; 258b39c5158Smillert for my $class (qw(A A1 A2 B B1 B2 C C1 C2 D D1)) { 259b39c5158Smillert push @objs, bless [], $class; 260b39c5158Smillert } 261b39c5158Smillert 262b39c5158Smillert sub f { 263b39c5158Smillert my $depth = shift; 264b39c5158Smillert my $cloned = ""; # XXX due to recursion, doesn't get initialized 265b39c5158Smillert $cloned .= "$_" =~ /ARRAY/ ? '1' : '0' for @objs; 266b39c5158Smillert is($cloned, ($depth ? '00010001111' : '11111111111'), 267b39c5158Smillert "objs clone skip at depth $depth"); 268b39c5158Smillert threads->create( \&f, $depth+1)->join if $depth < 2; 269b39c5158Smillert @objs = (); 270b39c5158Smillert } 271b39c5158Smillert f(0); 272b39c5158Smillert } 273b39c5158Smillert 274b39c5158Smillert curr_test(curr_test()+2); 275b39c5158Smillert ok(eq_hash(\%c, 276b39c5158Smillert { 277b39c5158Smillert qw( 278b39c5158Smillert A-A 2 279b39c5158Smillert A1-A1 2 280b39c5158Smillert A1-A2 2 281b39c5158Smillert B-B 2 282b39c5158Smillert B1-B1 2 283b39c5158Smillert B1-B2 2 284b39c5158Smillert C-C 2 285b39c5158Smillert C1-C1 2 286b39c5158Smillert C1-C2 2 287b39c5158Smillert ) 288b39c5158Smillert }), 289b39c5158Smillert "counts of calls to CLONE_SKIP"); 290b39c5158Smillert ok(eq_hash(\%d, 291b39c5158Smillert { 292b39c5158Smillert qw( 293b39c5158Smillert A-A 1 294b39c5158Smillert A1-A1 1 295b39c5158Smillert A1-A2 1 296b39c5158Smillert B-B 3 297b39c5158Smillert B1-B1 1 298b39c5158Smillert B1-B2 1 299b39c5158Smillert C-C 1 300b39c5158Smillert C1-C1 3 301b39c5158Smillert C1-C2 3 302b39c5158Smillert D-D 3 303b39c5158Smillert D-D1 3 304b39c5158Smillert ) 305b39c5158Smillert }), 306b39c5158Smillert "counts of calls to DESTROY"); 307b39c5158Smillert} 308b39c5158Smillert 309898184e3Ssthen# Bug 73330 - Apply magic to arg to ->object() 310898184e3Ssthen{ 311898184e3Ssthen my @tids :shared; 312898184e3Ssthen 313898184e3Ssthen my $thr = threads->create(sub { 314898184e3Ssthen lock(@tids); 315898184e3Ssthen push(@tids, threads->tid()); 316898184e3Ssthen cond_signal(@tids); 317898184e3Ssthen }); 318898184e3Ssthen 319898184e3Ssthen { 320898184e3Ssthen lock(@tids); 321898184e3Ssthen cond_wait(@tids) while (! @tids); 322898184e3Ssthen } 323898184e3Ssthen 324898184e3Ssthen ok(threads->object($_), 'Got threads object') foreach (@tids); 325898184e3Ssthen 326898184e3Ssthen $thr->join(); 327898184e3Ssthen} 328898184e3Ssthen 329b39c5158Smillertexit(0); 330b39c5158Smillert 331b39c5158Smillert# EOF 332