Fixed race condtions and deadlocks in interaction with
Artur Bergman [Sat, 27 Apr 2002 12:56:44 +0000 (12:56 +0000)]
cond_wait/cond_signal and lock.
Now we wait for a lock to gie up if we return from COND_WAIT
and we are still locked. We also notifiers potential
lockers that it is free for locking when we go into COND_WAIT.

p4raw-id: //depot/perl@16210

MANIFEST
ext/threads/shared/shared.xs
ext/threads/shared/t/cond.t [new file with mode: 0644]
ext/threads/shared/t/queue.t

index a82187f..3b8c010 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -662,6 +662,7 @@ ext/threads/shared/shared.xs    thread shared variables
 ext/threads/shared/t/0nothread.t       Tests for basic shared array functionality.
 ext/threads/shared/t/av_refs.t Tests for arrays containing references
 ext/threads/shared/t/av_simple.t       Tests for basic shared array functionality.
+ext/threads/shared/t/cond.t    Test condition variables
 ext/threads/shared/t/hv_refs.t Test shared hashes containing references
 ext/threads/shared/t/hv_simple.t       Tests for basic shared hash functionality.
 ext/threads/shared/t/no_share.t        Tests for disabled share on variables.
index 3d339e4..3442213 100644 (file)
@@ -982,7 +982,14 @@ cond_wait_enabled(SV *ref)
        shared->lock.owner = NULL;
        locks = shared->lock.locks;
        shared->lock.locks = 0;
+
+       /* since we are releasing the lock here we need to tell other
+       people that is ok to go ahead and use it */
+       COND_SIGNAL(&shared->lock.cond);
        COND_WAIT(&shared->user_cond, &shared->lock.mutex);
+       while(shared->lock.owner != NULL) {
+               COND_WAIT(&shared->lock.cond,&shared->lock.mutex);
+       }       
        shared->lock.owner = aTHX;
        shared->lock.locks = locks;
        MUTEX_UNLOCK(&shared->lock.mutex);
diff --git a/ext/threads/shared/t/cond.t b/ext/threads/shared/t/cond.t
new file mode 100644 (file)
index 0000000..c143c02
--- /dev/null
@@ -0,0 +1,40 @@
+BEGIN {
+    chdir 't' if -d 't';
+    push @INC ,'../lib';
+    require Config; import Config;
+    unless ($Config{'useithreads'}) {
+        print "1..0 # Skip: no threads\n";
+        exit 0;
+    }
+}
+print "1..5\n";
+use strict;
+
+
+use threads;
+
+use threads::shared;
+
+my $lock : shared;
+
+sub foo {
+    lock($lock);
+    print "ok 1\n";
+    sleep 2;
+    print "ok 2\n";
+    cond_wait($lock);
+    print "ok 5\n";
+}
+
+sub bar {
+    lock($lock);
+    print "ok 3\n";
+    cond_signal($lock);
+    print "ok 4\n";
+}
+
+my $tr  = threads->create(\&foo);
+my $tr2 = threads->create(\&bar);
+$tr->join();
+$tr2->join();
+
index 1b255b7..cf28eb4 100644 (file)
@@ -1,13 +1,13 @@
 
 
 BEGIN {
-#    chdir 't' if -d 't';
-#    push @INC ,'../lib';
-#    require Config; import Config;
-#    unless ($Config{'useithreads'}) {
+    chdir 't' if -d 't';
+    push @INC ,'../lib';
+    require Config; import Config;
+    unless ($Config{'useithreads'}) {
         print "1..0 # Skip: might still hang\n";
         exit 0;
-#    }
+    }
 }
 
 
@@ -16,6 +16,8 @@ use threads::queue;
 
 $q = new threads::shared::queue;
 
+print "1..26\n";
+
 sub reader {
     my $tid = threads->self->tid;
     my $i = 0;
@@ -23,8 +25,9 @@ sub reader {
        $i++;
 #      print "reader (tid $tid): waiting for element $i...\n";
        my $el = $q->dequeue;
+       print "ok\n";
 #      print "reader (tid $tid): dequeued element $i: value $el\n";
-       select(undef, undef, undef, rand(2));
+       select(undef, undef, undef, rand(1));
        if ($el == -1) {
            # end marker
 #          print "reader (tid $tid) returning\n";
@@ -33,16 +36,16 @@ sub reader {
     }
 }
 
-my $nthreads = 1;
+my $nthreads = 5;
 my @threads;
 
 for (my $i = 0; $i < $nthreads; $i++) {
     push @threads, threads->new(\&reader, $i);
 }
 
-for (my $i = 1; $i <= 10; $i++) {
+for (my $i = 1; $i <= 20; $i++) {
     my $el = int(rand(100));
-    select(undef, undef, undef, rand(2));
+    select(undef, undef, undef, rand(1));
 #    print "writer: enqueuing value $el\n";
     $q->enqueue($el);
 }
@@ -50,10 +53,9 @@ for (my $i = 1; $i <= 10; $i++) {
 $q->enqueue((-1) x $nthreads); # one end marker for each thread
 
 for(@threads) {
-       print "waiting for join\n";
+#      print "waiting for join\n";
        $_->join();
-       
 }
-
+print "ok\n";