summaryrefslogtreecommitdiff
path: root/sys/src/libthread/rendez.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/libthread/rendez.c
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/libthread/rendez.c')
-rwxr-xr-xsys/src/libthread/rendez.c99
1 files changed, 99 insertions, 0 deletions
diff --git a/sys/src/libthread/rendez.c b/sys/src/libthread/rendez.c
new file mode 100755
index 000000000..8a6d0f8a6
--- /dev/null
+++ b/sys/src/libthread/rendez.c
@@ -0,0 +1,99 @@
+#include <u.h>
+#include <libc.h>
+#include <thread.h>
+#include "threadimpl.h"
+
+Rgrp _threadrgrp;
+static int isdirty;
+
+static void*
+finish(Thread *t, void *val)
+{
+ void *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;
+}
+
+void*
+_threadrendezvous(void *tag, void *val)
+{
+ void *ret;
+ Thread *t, **l;
+
+ lock(&_threadrgrp.lock);
+ l = &_threadrgrp.hash[((uintptr)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);
+ 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;
+ _threaddebug(DBGREND, "Rendezvous for tag %p", t->rendtag);
+ unlock(&_threadrgrp.lock);
+ _sched();
+ t->inrendez = 0;
+ _threaddebug(DBGREND, "Woke after rendezvous; val is %p", 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, (void*)~0);
+ }else
+ l=&t->rendhash;
+ }
+ }
+ unlock(&_threadrgrp.lock);
+}