#include <9pm/u.h>
#include <9pm/libc.h>
#include <9pm/ns.h>
typedef struct Tag Tag;
struct Tag
{
ulong tag;
ulong val;
Proc *proc;
Tag *hash;
Tag *free;
};
enum
{
NHASH = 32
};
static Tag *ht[NHASH];
static Tag *ft;
static Lock rendlock;
ulong
rendezvous(ulong tag, ulong val)
{
uint h;
ulong ret;
Tag *t, **l;
Proc *p;
lock(&rendlock);
h = tag&(NHASH-1);
for(l=&ht[h]; t=*l; l=&(*l)->hash){
if(t->tag == tag){
ret = t->val;
t->val = val;
p = t->proc;
*l = t->hash;
t->proc = nil;
pm_wake(p);
/* lock passes to process being wakened */
return ret;
}
}
if((t=ft) == nil){
t = mallocz(sizeof(*t), 1);
assert(t != nil);
}else
ft = ft->free;
t->tag = tag;
t->val = val;
t->hash = *l;
t->proc = getproc();
*l = t;
unlock(&rendlock);
/*
* there's a potential race here: if we get woken before we nap,
* the wake may be a no-op. thus nap only naps for small
* amounts of time and we poll t->tag. since we're using
* rendezvous as our synchronization primitive, i'm hesitant
* to build still other primitives and build rendezvous with them.
* losing this race is not at all likely: the time between
* unlocking the lock and napping is only a handful of instructions.
*
* depending on the implementation of pm_wake, the race may
* not be there at all: on some systems, pm_wake waits for the process
* to nap before waking it.
*/
while(t->proc != nil)
pm_nap();
/* lock inherited from waker, tag is unlinked from hash list */
ret = t->val;
t->free = ft;
ft = t;
unlock(&rendlock);
return ret;
}
syntax highlighted by Code2HTML, v. 0.9.1