1b39c5158Smillertuse strict; 2b39c5158Smillertuse warnings; 3b39c5158Smillert 4b39c5158SmillertBEGIN { 5b39c5158Smillert # Import test.pl into its own package 6b39c5158Smillert { 7b39c5158Smillert package Test; 8b39c5158Smillert require($ENV{PERL_CORE} ? '../../t/test.pl' : './t/test.pl'); 9b39c5158Smillert } 10b39c5158Smillert 11b39c5158Smillert use Config; 12b39c5158Smillert if (! $Config{'useithreads'}) { 13b39c5158Smillert Test::skip_all(q/Perl not compiled with 'useithreads'/); 14b39c5158Smillert } 15b39c5158Smillert 16b39c5158Smillert if (! eval 'use Time::HiRes "time"; 1') { 17b39c5158Smillert Test::skip_all('Time::HiRes not available'); 18b39c5158Smillert } 19*898184e3Ssthen 20*898184e3Ssthen if ($^O eq 'linux' && $Config{archname} =~ /^m68k/) { 21*898184e3Ssthen print("1..0 # Skip: no TLS on m68k yet <http://bugs.debian.org/495826>\n"); 22*898184e3Ssthen exit(0); 23*898184e3Ssthen } 24*898184e3Ssthen 25b39c5158Smillert} 26b39c5158Smillert 27b39c5158Smillertuse ExtUtils::testlib; 28b39c5158Smillert 29b39c5158Smillertsub ok { 30b39c5158Smillert my ($id, $ok, $name) = @_; 31b39c5158Smillert 32b39c5158Smillert # You have to do it this way or VMS will get confused. 33b39c5158Smillert if ($ok) { 34b39c5158Smillert print("ok $id - $name\n"); 35b39c5158Smillert } else { 36b39c5158Smillert print("not ok $id - $name\n"); 37b39c5158Smillert printf("# Failed test at line %d\n", (caller)[2]); 38b39c5158Smillert } 39b39c5158Smillert 40b39c5158Smillert return ($ok); 41b39c5158Smillert} 42b39c5158Smillert 43b39c5158SmillertBEGIN { 44b39c5158Smillert $| = 1; 45*898184e3Ssthen print("1..63\n"); ### Number of tests that will be run ### 46b39c5158Smillert}; 47b39c5158Smillert 48b39c5158Smillertuse threads; 49b39c5158Smillertuse threads::shared; 50b39c5158Smillert 51b39c5158SmillertTest::watchdog(60); # In case we get stuck 52b39c5158Smillert 53b39c5158Smillertmy $TEST = 1; 54b39c5158Smillertok($TEST++, 1, 'Loaded'); 55b39c5158Smillert 56b39c5158Smillert### Start of Testing ### 57b39c5158Smillert 58b39c5158Smillert# subsecond cond_timedwait extended tests adapted from wait.t 59b39c5158Smillert 60b39c5158Smillert# The two skips later on in these tests refer to this quote from the 61b39c5158Smillert# pod/perl583delta.pod: 62b39c5158Smillert# 63b39c5158Smillert# =head1 Platform Specific Problems 64b39c5158Smillert# 65b39c5158Smillert# The regression test ext/threads/shared/t/wait.t fails on early RedHat 9 66b39c5158Smillert# and HP-UX 10.20 due to bugs in their threading implementations. 67b39c5158Smillert# RedHat users should see https://rhn.redhat.com/errata/RHBA-2003-136.html 68b39c5158Smillert# and consider upgrading their glibc. 69b39c5158Smillert 70b39c5158Smillert 71b39c5158Smillert# - TEST basics 72b39c5158Smillert 73b39c5158Smillertmy @wait_how = ( 74b39c5158Smillert "simple", # cond var == lock var; implicit lock; e.g.: cond_wait($c) 75b39c5158Smillert "repeat", # cond var == lock var; explicit lock; e.g.: cond_wait($c, $c) 76b39c5158Smillert "twain" # cond var != lock var; explicit lock; e.g.: cond_wait($c, $l) 77b39c5158Smillert); 78b39c5158Smillert 79*898184e3Ssthen# run cond_timedwait, and repeat if it times out (give up after 10 secs) 80*898184e3Ssthen 81*898184e3Ssthensub do_cond_timedwait { 82*898184e3Ssthen my $ok; 83*898184e3Ssthen my ($t0, $t1); 84*898184e3Ssthen if (@_ == 3) { 85*898184e3Ssthen $t0 = time(); 86*898184e3Ssthen $ok = cond_timedwait($_[0], time()+$_[1], $_[2]); 87*898184e3Ssthen $t1 = time(); 88*898184e3Ssthen } 89*898184e3Ssthen else { 90*898184e3Ssthen $t0 = time(); 91*898184e3Ssthen $ok = cond_timedwait($_[0], time()+$_[1]); 92*898184e3Ssthen $t1 = time(); 93*898184e3Ssthen } 94*898184e3Ssthen return ($ok, $t1-$t0) if $ok; 95*898184e3Ssthen 96*898184e3Ssthen # we timed out. Try again with no timeout to unblock the child 97*898184e3Ssthen if (@_ == 3) { 98*898184e3Ssthen cond_wait($_[0], $_[2]); 99*898184e3Ssthen } 100*898184e3Ssthen else { 101*898184e3Ssthen cond_wait($_[0]); 102*898184e3Ssthen } 103*898184e3Ssthen return ($ok, $t1-$t0); 104*898184e3Ssthen} 105*898184e3Ssthen 106b39c5158Smillert 107b39c5158SmillertSYNC_SHARED: { 108b39c5158Smillert my $test_type :shared; # simple|repeat|twain 109b39c5158Smillert 110b39c5158Smillert my $cond :shared; 111b39c5158Smillert my $lock :shared; 112*898184e3Ssthen my $ready :shared; 113b39c5158Smillert 114b39c5158Smillert ok($TEST++, 1, "Shared synchronization tests preparation"); 115b39c5158Smillert 116b39c5158Smillert # - TEST cond_timedwait success 117b39c5158Smillert 118b39c5158Smillert sub signaller 119b39c5158Smillert { 120b39c5158Smillert my $testno = $_[0]; 121b39c5158Smillert 122*898184e3Ssthen my ($t0, $t1); 123*898184e3Ssthen { 124*898184e3Ssthen lock($ready); 125*898184e3Ssthen $ready = 1; 126*898184e3Ssthen $t0 = time(); 127*898184e3Ssthen cond_signal($ready); 128*898184e3Ssthen } 129*898184e3Ssthen 130*898184e3Ssthen { 131b39c5158Smillert ok($testno++, 1, "$test_type: child before lock"); 132b39c5158Smillert $test_type =~ /twain/ ? lock($lock) : lock($cond); 133b39c5158Smillert ok($testno++, 1, "$test_type: child obtained lock"); 134b39c5158Smillert 135b39c5158Smillert if ($test_type =~ 'twain') { 136b39c5158Smillert no warnings 'threads'; # lock var != cond var, so disable warnings 137b39c5158Smillert cond_signal($cond); 138b39c5158Smillert } else { 139b39c5158Smillert cond_signal($cond); 140b39c5158Smillert } 141*898184e3Ssthen $t1 = time(); 142*898184e3Ssthen } # implicit unlock 143*898184e3Ssthen 144b39c5158Smillert ok($testno++, 1, "$test_type: child signalled condition"); 145b39c5158Smillert 146*898184e3Ssthen return($testno, $t1-$t0); 147b39c5158Smillert } 148b39c5158Smillert 149b39c5158Smillert sub ctw_ok 150b39c5158Smillert { 151b39c5158Smillert my ($testnum, $to) = @_; 152b39c5158Smillert 153b39c5158Smillert # Which lock to obtain? 154b39c5158Smillert $test_type =~ /twain/ ? lock($lock) : lock($cond); 155b39c5158Smillert ok($testnum++, 1, "$test_type: obtained initial lock"); 156b39c5158Smillert 157*898184e3Ssthen lock($ready); 158*898184e3Ssthen $ready = 0; 159*898184e3Ssthen 160*898184e3Ssthen my ($thr) = threads->create(\&signaller, $testnum); 161b39c5158Smillert my $ok = 0; 162*898184e3Ssthen cond_wait($ready) while !$ready; # wait for child to start up 163*898184e3Ssthen 164*898184e3Ssthen my $t; 165b39c5158Smillert for ($test_type) { 166*898184e3Ssthen ($ok, $t) = do_cond_timedwait($cond, $to), last if /simple/; 167*898184e3Ssthen ($ok, $t) = do_cond_timedwait($cond, $to, $cond), last if /repeat/; 168*898184e3Ssthen ($ok, $t) = do_cond_timedwait($cond, $to, $lock), last if /twain/; 169b39c5158Smillert die "$test_type: unknown test\n"; 170b39c5158Smillert } 171*898184e3Ssthen my $child_time; 172*898184e3Ssthen ($testnum, $child_time) = $thr->join(); 173*898184e3Ssthen if ($ok) { 174b39c5158Smillert ok($testnum++, $ok, "$test_type: condition obtained"); 175*898184e3Ssthen ok($testnum++, 1, "nothing to do here"); 176*898184e3Ssthen } 177*898184e3Ssthen else { 178*898184e3Ssthen # if cond_timewait timed out, make sure it was a reasonable 179*898184e3Ssthen # timeout: i.e. that both the parent and child over the 180*898184e3Ssthen # relevant interval exceeded the timeout 181*898184e3Ssthen ok($testnum++, $child_time >= $to, "test_type: child exceeded time"); 182*898184e3Ssthen print "# child time = $child_time\n"; 183*898184e3Ssthen ok($testnum++, $t >= $to, "test_type: parent exceeded time"); 184*898184e3Ssthen print "# parent time = $t\n"; 185*898184e3Ssthen } 186b39c5158Smillert return ($testnum); 187b39c5158Smillert } 188b39c5158Smillert 189b39c5158Smillert foreach (@wait_how) { 190b39c5158Smillert $test_type = "cond_timedwait [$_]"; 191*898184e3Ssthen my $thr = threads->create(\&ctw_ok, $TEST, 0.4); 192b39c5158Smillert $TEST = $thr->join(); 193b39c5158Smillert } 194b39c5158Smillert 195b39c5158Smillert # - TEST cond_timedwait timeout 196b39c5158Smillert 197b39c5158Smillert sub ctw_fail 198b39c5158Smillert { 199b39c5158Smillert my ($testnum, $to) = @_; 200b39c5158Smillert 201b39c5158Smillert if ($^O eq "hpux" && $Config{osvers} <= 10.20) { 202b39c5158Smillert # The lock obtaining would pass, but the wait will not. 203b39c5158Smillert ok($testnum++, 1, "$test_type: obtained initial lock"); 204b39c5158Smillert ok($testnum++, 0, "# SKIP see perl583delta"); 205b39c5158Smillert 206b39c5158Smillert } else { 207b39c5158Smillert $test_type =~ /twain/ ? lock($lock) : lock($cond); 208b39c5158Smillert ok($testnum++, 1, "$test_type: obtained initial lock"); 209b39c5158Smillert my $ok; 210b39c5158Smillert for ($test_type) { 211b39c5158Smillert $ok = cond_timedwait($cond, time() + $to), last if /simple/; 212b39c5158Smillert $ok = cond_timedwait($cond, time() + $to, $cond), last if /repeat/; 213b39c5158Smillert $ok = cond_timedwait($cond, time() + $to, $lock), last if /twain/; 214b39c5158Smillert die "$test_type: unknown test\n"; 215b39c5158Smillert } 216b39c5158Smillert ok($testnum++, ! defined($ok), "$test_type: timeout"); 217b39c5158Smillert } 218b39c5158Smillert 219b39c5158Smillert return ($testnum); 220b39c5158Smillert } 221b39c5158Smillert 222b39c5158Smillert foreach (@wait_how) { 223b39c5158Smillert $test_type = "cond_timedwait pause, timeout [$_]"; 224b39c5158Smillert my $thr = threads->create(\&ctw_fail, $TEST, 0.3); 225b39c5158Smillert $TEST = $thr->join(); 226b39c5158Smillert } 227b39c5158Smillert 228b39c5158Smillert foreach (@wait_how) { 229b39c5158Smillert $test_type = "cond_timedwait instant timeout [$_]"; 230b39c5158Smillert my $thr = threads->create(\&ctw_fail, $TEST, -0.60); 231b39c5158Smillert $TEST = $thr->join(); 232b39c5158Smillert } 233b39c5158Smillert 234b39c5158Smillert} # -- SYNCH_SHARED block 235b39c5158Smillert 236b39c5158Smillert 237b39c5158Smillert# same as above, but with references to lock and cond vars 238b39c5158Smillert 239b39c5158SmillertSYNCH_REFS: { 240b39c5158Smillert my $test_type :shared; # simple|repeat|twain 241b39c5158Smillert 242b39c5158Smillert my $true_cond :shared; 243b39c5158Smillert my $true_lock :shared; 244*898184e3Ssthen my $ready :shared; 245b39c5158Smillert 246b39c5158Smillert my $cond = \$true_cond; 247b39c5158Smillert my $lock = \$true_lock; 248b39c5158Smillert 249b39c5158Smillert ok($TEST++, 1, "Synchronization reference tests preparation"); 250b39c5158Smillert 251b39c5158Smillert # - TEST cond_timedwait success 252b39c5158Smillert 253b39c5158Smillert sub signaller2 254b39c5158Smillert { 255b39c5158Smillert my $testno = $_[0]; 256b39c5158Smillert 257*898184e3Ssthen my ($t0, $t1); 258*898184e3Ssthen { 259*898184e3Ssthen lock($ready); 260*898184e3Ssthen $ready = 1; 261*898184e3Ssthen $t0 = time(); 262*898184e3Ssthen cond_signal($ready); 263*898184e3Ssthen } 264*898184e3Ssthen 265*898184e3Ssthen { 266b39c5158Smillert ok($testno++, 1, "$test_type: child before lock"); 267b39c5158Smillert $test_type =~ /twain/ ? lock($lock) : lock($cond); 268b39c5158Smillert ok($testno++, 1, "$test_type: child obtained lock"); 269b39c5158Smillert 270b39c5158Smillert if ($test_type =~ 'twain') { 271b39c5158Smillert no warnings 'threads'; # lock var != cond var, so disable warnings 272b39c5158Smillert cond_signal($cond); 273b39c5158Smillert } else { 274b39c5158Smillert cond_signal($cond); 275b39c5158Smillert } 276*898184e3Ssthen $t1 = time(); 277*898184e3Ssthen } # implicit unlock 278*898184e3Ssthen 279b39c5158Smillert ok($testno++, 1, "$test_type: child signalled condition"); 280b39c5158Smillert 281*898184e3Ssthen return($testno, $t1-$t0); 282b39c5158Smillert } 283b39c5158Smillert 284b39c5158Smillert sub ctw_ok2 285b39c5158Smillert { 286b39c5158Smillert my ($testnum, $to) = @_; 287b39c5158Smillert 288b39c5158Smillert # Which lock to obtain? 289b39c5158Smillert $test_type =~ /twain/ ? lock($lock) : lock($cond); 290b39c5158Smillert ok($testnum++, 1, "$test_type: obtained initial lock"); 291b39c5158Smillert 292*898184e3Ssthen lock($ready); 293*898184e3Ssthen $ready = 0; 294*898184e3Ssthen 295*898184e3Ssthen my ($thr) = threads->create(\&signaller2, $testnum); 296b39c5158Smillert my $ok = 0; 297*898184e3Ssthen cond_wait($ready) while !$ready; # wait for child to start up 298*898184e3Ssthen 299*898184e3Ssthen my $t; 300b39c5158Smillert for ($test_type) { 301*898184e3Ssthen ($ok, $t) = do_cond_timedwait($cond, $to), last if /simple/; 302*898184e3Ssthen ($ok, $t) = do_cond_timedwait($cond, $to, $cond), last if /repeat/; 303*898184e3Ssthen ($ok, $t) = do_cond_timedwait($cond, $to, $lock), last if /twain/; 304b39c5158Smillert die "$test_type: unknown test\n"; 305b39c5158Smillert } 306*898184e3Ssthen my $child_time; 307*898184e3Ssthen ($testnum, $child_time) = $thr->join(); 308*898184e3Ssthen if ($ok) { 309b39c5158Smillert ok($testnum++, $ok, "$test_type: condition obtained"); 310*898184e3Ssthen ok($testnum++, 1, "nothing to do here"); 311*898184e3Ssthen } 312*898184e3Ssthen else { 313*898184e3Ssthen # if cond_timewait timed out, make sure it was a reasonable 314*898184e3Ssthen # timeout: i.e. that both the parent and child over the 315*898184e3Ssthen # relevant interval exceeded the timeout 316*898184e3Ssthen ok($testnum++, $child_time >= $to, "test_type: child exceeded time"); 317*898184e3Ssthen print "# child time = $child_time\n"; 318*898184e3Ssthen ok($testnum++, $t >= $to, "test_type: parent exceeded time"); 319*898184e3Ssthen print "# parent time = $t\n"; 320*898184e3Ssthen } 321b39c5158Smillert return ($testnum); 322b39c5158Smillert } 323b39c5158Smillert 324b39c5158Smillert foreach (@wait_how) { 325b39c5158Smillert $test_type = "cond_timedwait [$_]"; 326*898184e3Ssthen my $thr = threads->create(\&ctw_ok2, $TEST, 0.4); 327b39c5158Smillert $TEST = $thr->join(); 328b39c5158Smillert } 329b39c5158Smillert 330b39c5158Smillert # - TEST cond_timedwait timeout 331b39c5158Smillert 332b39c5158Smillert sub ctw_fail2 333b39c5158Smillert { 334b39c5158Smillert my ($testnum, $to) = @_; 335b39c5158Smillert 336b39c5158Smillert if ($^O eq "hpux" && $Config{osvers} <= 10.20) { 337b39c5158Smillert # The lock obtaining would pass, but the wait will not. 338b39c5158Smillert ok($testnum++, 1, "$test_type: obtained initial lock"); 339b39c5158Smillert ok($testnum++, 0, "# SKIP see perl583delta"); 340b39c5158Smillert 341b39c5158Smillert } else { 342b39c5158Smillert $test_type =~ /twain/ ? lock($lock) : lock($cond); 343b39c5158Smillert ok($testnum++, 1, "$test_type: obtained initial lock"); 344b39c5158Smillert my $ok; 345b39c5158Smillert for ($test_type) { 346b39c5158Smillert $ok = cond_timedwait($cond, time() + $to), last if /simple/; 347b39c5158Smillert $ok = cond_timedwait($cond, time() + $to, $cond), last if /repeat/; 348b39c5158Smillert $ok = cond_timedwait($cond, time() + $to, $lock), last if /twain/; 349b39c5158Smillert die "$test_type: unknown test\n"; 350b39c5158Smillert } 351b39c5158Smillert ok($testnum++, ! defined($ok), "$test_type: timeout"); 352b39c5158Smillert } 353b39c5158Smillert 354b39c5158Smillert return ($testnum); 355b39c5158Smillert } 356b39c5158Smillert 357b39c5158Smillert foreach (@wait_how) { 358b39c5158Smillert $test_type = "cond_timedwait pause, timeout [$_]"; 359b39c5158Smillert my $thr = threads->create(\&ctw_fail2, $TEST, 0.3); 360b39c5158Smillert $TEST = $thr->join(); 361b39c5158Smillert } 362b39c5158Smillert 363b39c5158Smillert foreach (@wait_how) { 364b39c5158Smillert $test_type = "cond_timedwait instant timeout [$_]"; 365b39c5158Smillert my $thr = threads->create(\&ctw_fail2, $TEST, -0.60); 366b39c5158Smillert $TEST = $thr->join(); 367b39c5158Smillert } 368b39c5158Smillert 369b39c5158Smillert} # -- SYNCH_REFS block 370b39c5158Smillert 371b39c5158Smillert# Done 372b39c5158Smillertexit(0); 373b39c5158Smillert 374b39c5158Smillert# EOF 375