diff options
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); +} |