develooper Front page | perl.perl5.porters | Postings from November 2003

[PATCH] cond_wait() and arbitrary lock variables

Thread Next
From:
Mike Pomraning
Date:
November 24, 2003 06:07
Subject:
[PATCH] cond_wait() and arbitrary lock variables
Message ID:
Pine.LNX.4.58.0311232311320.5397@localhost.localdomain
The following patch against 5.8.2 allows a shared variable to be cond_wait()d
with a distinct, shared lock variable:

   use threads::shared;

   cond_wait($v);           # $v is both condition and mutex
   cond_wait($v, $v);       # same as above, but explicit

   cond_wait($v, $lockvar); # $v's predicate is protected by $lockvar, which
                            # presumably protects other predicates as well

This is useful for, e.g., a Queue object which has client threads waiting on
one of two interesting predicates:  "items ready" ($q->dequeue) or "queue
empty" ($q->await_empty).


--- ext/threads/shared/shared.xs.orig	2003-11-02 15:50:30.000000000 -0600
+++ ext/threads/shared/shared.xs	2003-11-23 23:26:32.000000000 -0600
@@ -1039,21 +1039,38 @@
 	Perl_sharedsv_lock(aTHX_ shared);

 void
-cond_wait_enabled(SV *ref)
-	PROTOTYPE: \[$@%]
-	CODE:
+cond_wait_enabled(SV *ref_cond, SV *ref_lock = 0)
+	PROTOTYPE: \[$@%];\[$@%]
+	PREINIT:
 	shared_sv* shared;
+	perl_cond* user_condition;
 	int locks;
-	if(!SvROK(ref))
+	int same = 0;
+
+	CODE:
+	if (!ref_lock || ref_lock == ref_cond) same = 1;
+
+	if(!SvROK(ref_cond))
             Perl_croak(aTHX_ "Argument to cond_wait needs to be passed as ref");
-	ref = SvRV(ref);
-	if(SvROK(ref))
-	    ref = SvRV(ref);
-	shared = Perl_sharedsv_find(aTHX_ ref);
+	ref_cond = SvRV(ref_cond);
+	if(SvROK(ref_cond))
+	    ref_cond = SvRV(ref_cond);
+	shared = Perl_sharedsv_find(aTHX_ ref_cond);
 	if(!shared)
 	    croak("cond_wait can only be used on shared values");
-	if(shared->lock.owner != aTHX)
-	    croak("You need a lock before you can cond_wait");
+
+	user_condition = &shared->user_cond;
+	if (! same) {
+	    if (!SvROK(ref_lock))
+	        Perl_croak(aTHX_ "cond_wait lock needs to be passed as ref");
+	    ref_lock = SvRV(ref_lock);
+	    if (SvROK(ref_lock)) ref_lock = SvRV(ref_lock);
+	    shared = Perl_sharedsv_find(aTHX_ ref_lock);
+	    if (!shared)
+	        croak("cond_wait lock must be a shared value");
+	}
+    if(shared->lock.owner != aTHX)
+        croak("You need a lock before you can cond_wait");
 	/* Stealing the members of the lock object worries me - NI-S */
 	MUTEX_LOCK(&shared->lock.mutex);
 	shared->lock.owner = NULL;
@@ -1063,10 +1080,12 @@
 	/* 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);
+	COND_WAIT(user_condition, &shared->lock.mutex);
 	while(shared->lock.owner != NULL) {
-		COND_WAIT(&shared->lock.cond,&shared->lock.mutex);
-	}
+		/* OK -- we got the signal, now wait for threads to give us
+		back the lock */
+		COND_WAIT(&shared->lock.cond, &shared->lock.mutex);
+	}
 	shared->lock.owner = aTHX;
 	shared->lock.locks = locks;
 	MUTEX_UNLOCK(&shared->lock.mutex);
--- ext/threads/shared/shared.pm.orig	2003-11-22 22:40:15.000000000 -0600
+++ ext/threads/shared/shared.pm	2003-11-23 23:09:41.000000000 -0600
@@ -24,10 +24,10 @@
 # saves on average about 4K of memory per thread.

         eval <<'EOD';
-sub cond_wait      (\[$@%]) { undef }
-sub cond_signal    (\[$@%]) { undef }
-sub cond_broadcast (\[$@%]) { undef }
-sub share          (\[$@%]) { return $_[0] }
+sub cond_wait      (\[$@%];\[$@%]) { undef }
+sub cond_signal    (\[$@%])        { undef }
+sub cond_broadcast (\[$@%])        { undef }
+sub share          (\[$@%])        { return $_[0] }
 EOD
     }
 }
@@ -122,6 +122,8 @@

 =item cond_wait VARIABLE

+=item cond_wait CONDVAR LOCKVAR
+
 The C<cond_wait> function takes a B<locked> variable as a parameter,
 unlocks the variable, and blocks until another thread does a
 C<cond_signal> or C<cond_broadcast> for that same locked variable.
@@ -134,6 +136,11 @@
 blocked wait state are atomic, The two actions of exiting from the
 blocked wait state and relocking the variable are not.

+In its second form, C<cond_wait> takes a shared, B<unlocked> variable
+followed by a shared, B<locked> variable.  The second variable is
+unlocked and thread execution suspended until another thread signals
+the first variable.
+
 It is important to note that the variable can be notified even if
 no thread C<cond_signal> or C<cond_broadcast> on the variable.
 It is therefore important to check the value of the variable and



-Mike

Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About