Re: [PATCH 5.6.0]Add non-blocking thread doneness checking
Hugo van der Sanden [Thu, 26 Oct 2000 01:55:17 +0000 (02:55 +0100)]
Message-Id: <200010260055.BAA27869@crypt.compulink.co.uk>

minus one unneeded mutex lock/unlock pointed out by Dan Sugalski.

p4raw-id: //depot/perl@7449

ext/Thread/Thread.pm
ext/Thread/Thread.xs
t/lib/thr5005.t

index 22ae4ef..f8a8a26 100644 (file)
@@ -34,7 +34,6 @@ Thread - manipulate threads in Perl (EXPERIMENTAL, subject to change)
     my $tid = Thread->self->tid; 
     my $tlist = Thread->list;
 
-
     lock($scalar);
     yield();
 
@@ -191,7 +190,7 @@ assigned starting with one.
 
 The C<flags> method returns the flags for the thread. This is the
 integer value corresponding to the internal flags for the thread, and
-the value man not be all that meaningful to you.
+the value may not be all that meaningful to you.
 
 =item done
 
index 27e2533..c911279 100644 (file)
@@ -189,9 +189,9 @@ threadstart(void *arg)
     SvREFCNT_dec(PL_lastscream);
     SvREFCNT_dec(PL_defoutgv);
     Safefree(PL_reg_poscache);
-    thr->thr_done = 1;
 
     MUTEX_LOCK(&thr->mutex);
+    thr->thr_done = 1;
     DEBUG_S(PerlIO_printf(Perl_debug_log,
                          "%p: threadstart finishing: state is %u\n",
                          thr, ThrSTATE(thr)));
@@ -453,7 +453,7 @@ done(t)
        Thread  t
     PPCODE:
 #ifdef USE_THREADS
-     PUSHs(t->thr_done ? &PL_sv_yes : &PL_sv_no);
+       PUSHs(t->thr_done ? &PL_sv_yes : &PL_sv_no);
 #endif
 
 void
index 680e1af..bc6aed7 100755 (executable)
@@ -13,7 +13,7 @@ BEGIN {
     $ENV{PERL_DESTRUCT_LEVEL} = 0 unless $ENV{PERL_DESTRUCT_LEVEL} > 3;
 }
 $| = 1;
-print "1..22\n";
+print "1..74\n";
 use Thread 'yield';
 print "ok 1\n";
 
@@ -129,3 +129,79 @@ $thr1->join;
 $thr2->join;
 $thr3->join;
 print "ok 22\n";
+
+{
+    my $THRf_STATE_MASK = 7;
+    my $THRf_R_JOINABLE = 0;
+    my $THRf_R_JOINED = 1;
+    my $THRf_R_DETACHED = 2;
+    my $THRf_ZOMBIE = 3;
+    my $THRf_DEAD = 4;
+    my $THRf_DID_DIE = 8;
+    sub _test {
+       my($test, $t, $state, $die) = @_;
+       my $flags = $t->flags;
+       if (($flags & $THRf_STATE_MASK) == $state
+               && !($flags & $THRf_DID_DIE) == !$die) {
+           print "ok $test\n";
+       } else {
+           print <<BAD;
+not ok $test\t# got flags $flags not @{[ $state + ($die ? $THRf_DID_DIE : 0) ]}
+BAD
+       }
+    }
+
+    my @t;
+    push @t, (
+       Thread->new(sub { sleep 4; die "thread die\n" }),
+       Thread->new(sub { die "thread die\n" }),
+       Thread->new(sub { sleep 4; 1 }),
+       Thread->new(sub { 1 }),
+    ) for 1, 2;
+    $_->detach for @t[grep $_ & 4, 0..$#t];
+
+    sleep 1;
+    my $test = 23;
+    for (0..7) {
+       my $t = $t[$_];
+       my $flags = ($_ & 1)
+           ? ($_ & 4) ? $THRf_DEAD : $THRf_ZOMBIE
+           : ($_ & 4) ? $THRf_R_DETACHED : $THRf_R_JOINABLE;
+       _test($test++, $t, $flags, (($_ & 3) != 1) ? 0 : $THRf_DID_DIE);
+       printf "%sok %s\n", !$t->done == !($_ & 1) ? "" : "not ", $test++;
+    }
+#   $test = 39;
+    for (grep $_ & 1, 0..$#t) {
+       next if $_ & 4;         # can't join detached threads
+       $t[$_]->eval;
+       my $die = ($_ & 2) ? "" : "thread die\n";
+       printf "%sok %s\n", $@ eq $die ? "" : "not ", $test++;
+    }
+#   $test = 41;
+    for (0..7) {
+       my $t = $t[$_];
+       my $flags = ($_ & 1)
+           ? ($_ & 4) ? $THRf_DEAD : $THRf_DEAD
+           : ($_ & 4) ? $THRf_R_DETACHED : $THRf_R_JOINABLE;
+       _test($test++, $t, $flags, (($_ & 3) != 1) ? 0 : $THRf_DID_DIE);
+       printf "%sok %s\n", !$t->done == !($_ & 1) ? "" : "not ", $test++;
+    }
+#   $test = 57;
+    for (grep !($_ & 1), 0..$#t) {
+       next if $_ & 4;         # can't join detached threads
+       $t[$_]->eval;
+       my $die = ($_ & 2) ? "" : "thread die\n";
+       printf "%sok %s\n", $@ eq $die ? "" : "not ", $test++;
+    }
+    sleep 1;   # make sure even the detached threads are done sleeping
+#   $test = 59;
+    for (0..7) {
+       my $t = $t[$_];
+       my $flags = ($_ & 1)
+           ? ($_ & 4) ? $THRf_DEAD : $THRf_DEAD
+           : ($_ & 4) ? $THRf_DEAD : $THRf_DEAD;
+       _test($test++, $t, $flags, ($_ & 2) ? 0 : $THRf_DID_DIE);
+       printf "%sok %s\n", $t->done ? "" : "not ", $test++;
+    }
+#   $test = 75;
+}