aboutsummaryrefslogtreecommitdiff
path: root/src/libthread/rendez.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libthread/rendez.c')
-rw-r--r--src/libthread/rendez.c104
1 files changed, 104 insertions, 0 deletions
diff --git a/src/libthread/rendez.c b/src/libthread/rendez.c
new file mode 100644
index 00000000..62b825b5
--- /dev/null
+++ b/src/libthread/rendez.c
@@ -0,0 +1,104 @@
+#include "threadimpl.h"
+
+Rgrp _threadrgrp;
+static int isdirty;
+int _threadhighnrendez;
+int _threadnrendez;
+static int nrendez;
+
+static ulong
+finish(Thread *t, ulong val)
+{
+ ulong ret;
+
+ ret = t->rendval;
+ t->rendval = val;
+ while(t->state == Running)
+ sleep(0);
+ lock(&t->proc->lock);
+ if(t->state == Rendezvous){ /* not always true: might be Dead */
+ t->state = Ready;
+ _threadready(t);
+ }
+ unlock(&t->proc->lock);
+ return ret;
+}
+
+ulong
+_threadrendezvous(ulong tag, ulong val)
+{
+ ulong ret;
+ Thread *t, **l;
+
+ lock(&_threadrgrp.lock);
+_threadnrendez++;
+ l = &_threadrgrp.hash[tag%nelem(_threadrgrp.hash)];
+ for(t=*l; t; l=&t->rendhash, t=*l){
+ if(t->rendtag==tag){
+ _threaddebug(DBGREND, "Rendezvous with thread %d.%d", t->proc->pid, t->id);
+ *l = t->rendhash;
+ ret = finish(t, val);
+ --nrendez;
+ unlock(&_threadrgrp.lock);
+ return ret;
+ }
+ }
+
+ /* Going to sleep here. */
+ t = _threadgetproc()->thread;
+ t->rendbreak = 0;
+ t->inrendez = 1;
+ t->rendtag = tag;
+ t->rendval = val;
+ t->rendhash = *l;
+ *l = t;
+ t->nextstate = Rendezvous;
+ ++nrendez;
+ if(nrendez > _threadhighnrendez)
+ _threadhighnrendez = nrendez;
+ _threaddebug(DBGREND, "Rendezvous for tag %lud", t->rendtag);
+ unlock(&_threadrgrp.lock);
+ _sched();
+ t->inrendez = 0;
+ _threaddebug(DBGREND, "Woke after rendezvous; val is %lud", t->rendval);
+ return t->rendval;
+}
+
+/*
+ * This is called while holding _threadpq.lock and p->lock,
+ * so we can't lock _threadrgrp.lock. Instead our caller has
+ * to call _threadbreakrendez after dropping those locks.
+ */
+void
+_threadflagrendez(Thread *t)
+{
+ t->rendbreak = 1;
+ isdirty = 1;
+}
+
+void
+_threadbreakrendez(void)
+{
+ int i;
+ Thread *t, **l;
+
+ if(isdirty == 0)
+ return;
+ lock(&_threadrgrp.lock);
+ if(isdirty == 0){
+ unlock(&_threadrgrp.lock);
+ return;
+ }
+ isdirty = 0;
+ for(i=0; i<nelem(_threadrgrp.hash); i++){
+ l = &_threadrgrp.hash[i];
+ for(t=*l; t; t=*l){
+ if(t->rendbreak){
+ *l = t->rendhash;
+ finish(t, ~0);
+ }else
+ l=&t->rendhash;
+ }
+ }
+ unlock(&_threadrgrp.lock);
+}