From: Artur Bergman Date: Sat, 27 Apr 2002 12:56:44 +0000 (+0000) Subject: Fixed race condtions and deadlocks in interaction with X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=89661126d223f04756e59db5fd133f962b0514c6;p=p5sagit%2Fp5-mst-13.2.git Fixed race condtions and deadlocks in interaction with 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 --- diff --git a/MANIFEST b/MANIFEST index a82187f..3b8c010 100644 --- 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. diff --git a/ext/threads/shared/shared.xs b/ext/threads/shared/shared.xs index 3d339e4..3442213 100644 --- a/ext/threads/shared/shared.xs +++ b/ext/threads/shared/shared.xs @@ -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 index 0000000..c143c02 --- /dev/null +++ b/ext/threads/shared/t/cond.t @@ -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(); + diff --git a/ext/threads/shared/t/queue.t b/ext/threads/shared/t/queue.t index 1b255b7..cf28eb4 100644 --- a/ext/threads/shared/t/queue.t +++ b/ext/threads/shared/t/queue.t @@ -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";