1*b39c5158Smillertuse strict; 2*b39c5158Smillertuse warnings; 3*b39c5158Smillert 4*b39c5158SmillertBEGIN { 5*b39c5158Smillert use Config; 6*b39c5158Smillert if (! $Config{'useithreads'}) { 7*b39c5158Smillert print("1..0 # SKIP Perl not compiled with 'useithreads'\n"); 8*b39c5158Smillert exit(0); 9*b39c5158Smillert } 10*b39c5158Smillert} 11*b39c5158Smillert 12*b39c5158Smillertuse ExtUtils::testlib; 13*b39c5158Smillert 14*b39c5158Smillertmy $Base = 0; 15*b39c5158Smillertsub ok { 16*b39c5158Smillert my ($id, $ok, $name) = @_; 17*b39c5158Smillert $id += $Base; 18*b39c5158Smillert 19*b39c5158Smillert # You have to do it this way or VMS will get confused. 20*b39c5158Smillert if ($ok) { 21*b39c5158Smillert print("ok $id - $name\n"); 22*b39c5158Smillert } else { 23*b39c5158Smillert print("not ok $id - $name\n"); 24*b39c5158Smillert printf("# Failed test at line %d\n", (caller)[2]); 25*b39c5158Smillert } 26*b39c5158Smillert 27*b39c5158Smillert return ($ok); 28*b39c5158Smillert} 29*b39c5158Smillert 30*b39c5158SmillertBEGIN { 31*b39c5158Smillert $| = 1; 32*b39c5158Smillert print("1..32\n"); ### Number of tests that will be run ### 33*b39c5158Smillert}; 34*b39c5158Smillert 35*b39c5158Smillertuse threads; 36*b39c5158Smillertuse threads::shared; 37*b39c5158Smillertok(1, 1, 'Loaded'); 38*b39c5158Smillert$Base++; 39*b39c5158Smillert 40*b39c5158Smillert### Start of Testing ### 41*b39c5158Smillert 42*b39c5158Smillert# test locking 43*b39c5158Smillert{ 44*b39c5158Smillert my $lock : shared; 45*b39c5158Smillert my $tr; 46*b39c5158Smillert 47*b39c5158Smillert # test that a subthread can't lock until parent thread has unlocked 48*b39c5158Smillert 49*b39c5158Smillert { 50*b39c5158Smillert lock($lock); 51*b39c5158Smillert ok(1, 1, "set first lock"); 52*b39c5158Smillert $tr = async { 53*b39c5158Smillert lock($lock); 54*b39c5158Smillert ok(3, 1, "set lock in subthread"); 55*b39c5158Smillert }; 56*b39c5158Smillert threads->yield; 57*b39c5158Smillert ok(2, 1, "still got lock"); 58*b39c5158Smillert } 59*b39c5158Smillert $tr->join; 60*b39c5158Smillert 61*b39c5158Smillert $Base += 3; 62*b39c5158Smillert 63*b39c5158Smillert # ditto with ref to thread 64*b39c5158Smillert 65*b39c5158Smillert { 66*b39c5158Smillert my $lockref = \$lock; 67*b39c5158Smillert lock($lockref); 68*b39c5158Smillert ok(1,1,"set first lockref"); 69*b39c5158Smillert $tr = async { 70*b39c5158Smillert lock($lockref); 71*b39c5158Smillert ok(3,1,"set lockref in subthread"); 72*b39c5158Smillert }; 73*b39c5158Smillert threads->yield; 74*b39c5158Smillert ok(2,1,"still got lockref"); 75*b39c5158Smillert } 76*b39c5158Smillert $tr->join; 77*b39c5158Smillert 78*b39c5158Smillert $Base += 3; 79*b39c5158Smillert 80*b39c5158Smillert # make sure recursive locks unlock at the right place 81*b39c5158Smillert { 82*b39c5158Smillert lock($lock); 83*b39c5158Smillert ok(1,1,"set first recursive lock"); 84*b39c5158Smillert lock($lock); 85*b39c5158Smillert threads->yield; 86*b39c5158Smillert { 87*b39c5158Smillert lock($lock); 88*b39c5158Smillert threads->yield; 89*b39c5158Smillert } 90*b39c5158Smillert $tr = async { 91*b39c5158Smillert lock($lock); 92*b39c5158Smillert ok(3,1,"set recursive lock in subthread"); 93*b39c5158Smillert }; 94*b39c5158Smillert { 95*b39c5158Smillert lock($lock); 96*b39c5158Smillert threads->yield; 97*b39c5158Smillert { 98*b39c5158Smillert lock($lock); 99*b39c5158Smillert threads->yield; 100*b39c5158Smillert lock($lock); 101*b39c5158Smillert threads->yield; 102*b39c5158Smillert } 103*b39c5158Smillert } 104*b39c5158Smillert ok(2,1,"still got recursive lock"); 105*b39c5158Smillert } 106*b39c5158Smillert $tr->join; 107*b39c5158Smillert 108*b39c5158Smillert $Base += 3; 109*b39c5158Smillert 110*b39c5158Smillert # Make sure a lock factory gives out fresh locks each time 111*b39c5158Smillert # for both attribute and run-time shares 112*b39c5158Smillert 113*b39c5158Smillert sub lock_factory1 { my $lock : shared; return \$lock; } 114*b39c5158Smillert sub lock_factory2 { my $lock; share($lock); return \$lock; } 115*b39c5158Smillert 116*b39c5158Smillert my (@locks1, @locks2); 117*b39c5158Smillert push @locks1, lock_factory1() for 1..2; 118*b39c5158Smillert push @locks1, lock_factory2() for 1..2; 119*b39c5158Smillert push @locks2, lock_factory1() for 1..2; 120*b39c5158Smillert push @locks2, lock_factory2() for 1..2; 121*b39c5158Smillert 122*b39c5158Smillert ok(1,1,"lock factory: locking all locks"); 123*b39c5158Smillert lock $locks1[0]; 124*b39c5158Smillert lock $locks1[1]; 125*b39c5158Smillert lock $locks1[2]; 126*b39c5158Smillert lock $locks1[3]; 127*b39c5158Smillert ok(2,1,"lock factory: locked all locks"); 128*b39c5158Smillert $tr = async { 129*b39c5158Smillert ok(3,1,"lock factory: child: locking all locks"); 130*b39c5158Smillert lock $locks2[0]; 131*b39c5158Smillert lock $locks2[1]; 132*b39c5158Smillert lock $locks2[2]; 133*b39c5158Smillert lock $locks2[3]; 134*b39c5158Smillert ok(4,1,"lock factory: child: locked all locks"); 135*b39c5158Smillert }; 136*b39c5158Smillert $tr->join; 137*b39c5158Smillert 138*b39c5158Smillert $Base += 4; 139*b39c5158Smillert} 140*b39c5158Smillert 141*b39c5158Smillert 142*b39c5158Smillert# test cond_signal() 143*b39c5158Smillert{ 144*b39c5158Smillert my $lock : shared; 145*b39c5158Smillert 146*b39c5158Smillert sub foo { 147*b39c5158Smillert lock($lock); 148*b39c5158Smillert ok(1,1,"cond_signal: created first lock"); 149*b39c5158Smillert my $tr2 = threads->create(\&bar); 150*b39c5158Smillert cond_wait($lock); 151*b39c5158Smillert $tr2->join(); 152*b39c5158Smillert ok(5,1,"cond_signal: joined"); 153*b39c5158Smillert } 154*b39c5158Smillert 155*b39c5158Smillert sub bar { 156*b39c5158Smillert ok(2,1,"cond_signal: child before lock"); 157*b39c5158Smillert lock($lock); 158*b39c5158Smillert ok(3,1,"cond_signal: child locked"); 159*b39c5158Smillert cond_signal($lock); 160*b39c5158Smillert ok(4,1,"cond_signal: signalled"); 161*b39c5158Smillert } 162*b39c5158Smillert 163*b39c5158Smillert my $tr = threads->create(\&foo); 164*b39c5158Smillert $tr->join(); 165*b39c5158Smillert 166*b39c5158Smillert $Base += 5; 167*b39c5158Smillert 168*b39c5158Smillert # ditto, but with lockrefs 169*b39c5158Smillert 170*b39c5158Smillert my $lockref = \$lock; 171*b39c5158Smillert sub foo2 { 172*b39c5158Smillert lock($lockref); 173*b39c5158Smillert ok(1,1,"cond_signal: ref: created first lock"); 174*b39c5158Smillert my $tr2 = threads->create(\&bar2); 175*b39c5158Smillert cond_wait($lockref); 176*b39c5158Smillert $tr2->join(); 177*b39c5158Smillert ok(5,1,"cond_signal: ref: joined"); 178*b39c5158Smillert } 179*b39c5158Smillert 180*b39c5158Smillert sub bar2 { 181*b39c5158Smillert ok(2,1,"cond_signal: ref: child before lock"); 182*b39c5158Smillert lock($lockref); 183*b39c5158Smillert ok(3,1,"cond_signal: ref: child locked"); 184*b39c5158Smillert cond_signal($lockref); 185*b39c5158Smillert ok(4,1,"cond_signal: ref: signalled"); 186*b39c5158Smillert } 187*b39c5158Smillert 188*b39c5158Smillert $tr = threads->create(\&foo2); 189*b39c5158Smillert $tr->join(); 190*b39c5158Smillert 191*b39c5158Smillert $Base += 5; 192*b39c5158Smillert} 193*b39c5158Smillert 194*b39c5158Smillert 195*b39c5158Smillert# test cond_broadcast() 196*b39c5158Smillert{ 197*b39c5158Smillert my $counter : shared = 0; 198*b39c5158Smillert 199*b39c5158Smillert # broad(N) forks off broad(N-1) and goes into a wait, in such a way 200*b39c5158Smillert # that it's guaranteed to reach the wait before its child enters the 201*b39c5158Smillert # locked region. When N reaches 0, the child instead does a 202*b39c5158Smillert # cond_broadcast to wake all its ancestors. 203*b39c5158Smillert 204*b39c5158Smillert sub broad { 205*b39c5158Smillert my $n = shift; 206*b39c5158Smillert my $th; 207*b39c5158Smillert { 208*b39c5158Smillert lock($counter); 209*b39c5158Smillert if ($n > 0) { 210*b39c5158Smillert $counter++; 211*b39c5158Smillert $th = threads->create(\&broad, $n-1); 212*b39c5158Smillert cond_wait($counter); 213*b39c5158Smillert $counter += 10; 214*b39c5158Smillert } 215*b39c5158Smillert else { 216*b39c5158Smillert ok(1, $counter == 3, "cond_broadcast: all three waiting"); 217*b39c5158Smillert cond_broadcast($counter); 218*b39c5158Smillert } 219*b39c5158Smillert } 220*b39c5158Smillert $th->join if $th; 221*b39c5158Smillert } 222*b39c5158Smillert 223*b39c5158Smillert threads->create(\&broad, 3)->join; 224*b39c5158Smillert ok(2, $counter == 33, "cond_broadcast: all three threads woken"); 225*b39c5158Smillert 226*b39c5158Smillert $Base += 2; 227*b39c5158Smillert 228*b39c5158Smillert 229*b39c5158Smillert # ditto, but with refs and shared() 230*b39c5158Smillert 231*b39c5158Smillert my $counter2 = 0; 232*b39c5158Smillert share($counter2); 233*b39c5158Smillert my $r = \$counter2; 234*b39c5158Smillert 235*b39c5158Smillert sub broad2 { 236*b39c5158Smillert my $n = shift; 237*b39c5158Smillert my $th; 238*b39c5158Smillert { 239*b39c5158Smillert lock($r); 240*b39c5158Smillert if ($n > 0) { 241*b39c5158Smillert $$r++; 242*b39c5158Smillert $th = threads->create(\&broad2, $n-1); 243*b39c5158Smillert cond_wait($r); 244*b39c5158Smillert $$r += 10; 245*b39c5158Smillert } 246*b39c5158Smillert else { 247*b39c5158Smillert ok(1, $$r == 3, "cond_broadcast: ref: all three waiting"); 248*b39c5158Smillert cond_broadcast($r); 249*b39c5158Smillert } 250*b39c5158Smillert } 251*b39c5158Smillert $th->join if $th; 252*b39c5158Smillert } 253*b39c5158Smillert 254*b39c5158Smillert threads->create(\&broad2, 3)->join;; 255*b39c5158Smillert ok(2, $$r == 33, "cond_broadcast: ref: all three threads woken"); 256*b39c5158Smillert 257*b39c5158Smillert $Base += 2; 258*b39c5158Smillert} 259*b39c5158Smillert 260*b39c5158Smillert 261*b39c5158Smillert# test warnings; 262*b39c5158Smillert{ 263*b39c5158Smillert my $warncount = 0; 264*b39c5158Smillert local $SIG{__WARN__} = sub { $warncount++ }; 265*b39c5158Smillert 266*b39c5158Smillert my $lock : shared; 267*b39c5158Smillert 268*b39c5158Smillert cond_signal($lock); 269*b39c5158Smillert ok(1, $warncount == 1, 'get warning on cond_signal'); 270*b39c5158Smillert cond_broadcast($lock); 271*b39c5158Smillert ok(2, $warncount == 2, 'get warning on cond_broadcast'); 272*b39c5158Smillert no warnings 'threads'; 273*b39c5158Smillert cond_signal($lock); 274*b39c5158Smillert ok(3, $warncount == 2, 'get no warning on cond_signal'); 275*b39c5158Smillert cond_broadcast($lock); 276*b39c5158Smillert ok(4, $warncount == 2, 'get no warning on cond_broadcast'); 277*b39c5158Smillert 278*b39c5158Smillert $Base += 4; 279*b39c5158Smillert} 280*b39c5158Smillert 281*b39c5158Smillertexit(0); 282*b39c5158Smillert 283*b39c5158Smillert# EOF 284