#include <pthread.h>
#include <string.h>
#include <u.h>
#include <libc.h>
pthread_mutex_t pm_rendlock;
enum
{
NHLOG = 7,
NHASH = (1<<NHLOG)
};
typedef struct Tag Tag;
struct Tag
{
ulong tag;
ulong val;
Tag* hash;
Tag* free;
pthread_cond_t cv;
};
static Tag* ht[NHASH];
static Tag* ft;
ulong
rendezvous(ulong tag, ulong value)
{
int h;
int err;
ulong rval;
Tag *t, *f, **l;
Pmspl s;
if(tag == 0)
pm_panic("rendezvous zero tag");
h = tag & (NHASH-1);
s = pm_splhi();
if((err = pthread_mutex_lock(&pm_rendlock)) != 0){
char buf[512];
pm_snprint(buf, sizeof buf, "pthread_mutex_lock failed: %s", strerror(err));
pm_panic(buf);
}
pm_fprint(2, "%d entering rend-pthread\n",getpid());
l = &ht[h];
for(t = *l; t; t = t->hash) {
if(t->tag == tag) {
rval = t->val;
t->val = value;
t->tag = 0;
pm_fprint(2, "%d leaving rend-pthread to sleep, perchance to dream\n", getpid());
if(pthread_mutex_unlock(&pm_rendlock))
pm_panic("pthread_mutex_unlock failed");
pm_splx(s);
if(pthread_cond_signal(&(t->cv)))
pm_panic("pthread_cond_signal failed");
return rval;
}
}
t = ft;
if(t == 0)
t = malloc(sizeof(Tag));
else
ft = t->free;
t->tag = tag;
t->val = value;
t->hash = *l;
if(pthread_cond_init(&(t->cv), NULL))
pm_panic("pthread_cond_init failed");
*l = t;
while(t->tag){
pthread_mutex_unlock(&pm_rendlock);
pm_splx(s);
pthread_cond_wait(&(t->cv), NULL);
s = pm_splhi();
pthread_mutex_lock(&pm_rendlock);
}
rval = t->val;
for(f = *l; f; f = f->hash){
if(f == t) {
*l = f->hash;
break;
}
l = &f->hash;
}
t->free = ft;
ft = t;
pm_fprint(2, "%d leaving rend-pthread\n",getpid());
if(pthread_mutex_unlock(&pm_rendlock))
pm_panic("pthread_mutex_unlock failed");
pm_splx(s);
return rval;
}
syntax highlighted by Code2HTML, v. 0.9.1