diff options
author | rsc <devnull@localhost> | 2003-09-30 17:47:42 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2003-09-30 17:47:42 +0000 |
commit | 76193d7cb0457807b2f0b95f909ab5de19480cd7 (patch) | |
tree | 97e538c7e38181431e90289a0fe8b6b7ce1f8f3c /src/libthread/rendez.c | |
parent | ed7c8e8d02c02bdbff1e88a6d8d1419f39af48ad (diff) | |
download | plan9port-76193d7cb0457807b2f0b95f909ab5de19480cd7.tar.gz plan9port-76193d7cb0457807b2f0b95f909ab5de19480cd7.tar.bz2 plan9port-76193d7cb0457807b2f0b95f909ab5de19480cd7.zip |
Initial revision
Diffstat (limited to 'src/libthread/rendez.c')
-rw-r--r-- | src/libthread/rendez.c | 104 |
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); +} |