2003-09-30 17:47:41 +00:00
|
|
|
/*
|
|
|
|
|
NAME
|
|
|
|
|
rendezvous - user level process synchronization
|
|
|
|
|
|
|
|
|
|
SYNOPSIS
|
|
|
|
|
ulong rendezvous(ulong tag, ulong value)
|
|
|
|
|
|
|
|
|
|
DESCRIPTION
|
|
|
|
|
The rendezvous system call allows two processes to synchro-
|
|
|
|
|
nize and exchange a value. In conjunction with the shared
|
|
|
|
|
memory system calls (see segattach(2) and fork(2)), it
|
|
|
|
|
enables parallel programs to control their scheduling.
|
|
|
|
|
|
|
|
|
|
Two processes wishing to synchronize call rendezvous with a
|
|
|
|
|
common tag, typically an address in memory they share. One
|
|
|
|
|
process will arrive at the rendezvous first; it suspends
|
|
|
|
|
execution until a second arrives. When a second process
|
|
|
|
|
meets the rendezvous the value arguments are exchanged
|
|
|
|
|
between the processes and returned as the result of the
|
|
|
|
|
respective rendezvous system calls. Both processes are
|
|
|
|
|
awakened when the rendezvous succeeds.
|
|
|
|
|
|
|
|
|
|
The set of tag values which two processes may use to
|
|
|
|
|
rendezvous-their tag space-is inherited when a process
|
|
|
|
|
forks, unless RFREND is set in the argument to rfork; see
|
|
|
|
|
fork(2).
|
|
|
|
|
|
|
|
|
|
If a rendezvous is interrupted the return value is ~0, so
|
|
|
|
|
that value should not be used in normal communication.
|
|
|
|
|
|
2003-10-01 02:53:00 +00:00
|
|
|
* This assumes we're using pthreads and simulates rendezvous using
|
|
|
|
|
* shared memory and mutexes.
|
2003-09-30 17:47:41 +00:00
|
|
|
*/
|
|
|
|
|
|
2004-03-25 23:03:57 +00:00
|
|
|
#include <u.h>
|
2003-10-01 02:53:00 +00:00
|
|
|
#include <pthread.h>
|
2003-11-23 18:12:54 +00:00
|
|
|
#include <signal.h>
|
2004-03-25 23:03:57 +00:00
|
|
|
#include <libc.h>
|
2003-09-30 17:47:41 +00:00
|
|
|
|
|
|
|
|
enum
|
|
|
|
|
{
|
|
|
|
|
VOUSHASH = 257,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
typedef struct Vous Vous;
|
|
|
|
|
struct Vous
|
|
|
|
|
{
|
|
|
|
|
Vous *link;
|
|
|
|
|
Lock lk;
|
|
|
|
|
ulong val;
|
|
|
|
|
ulong tag;
|
2003-10-01 02:53:00 +00:00
|
|
|
pthread_mutex_t mutex;
|
2003-09-30 17:47:41 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
ign(int x)
|
|
|
|
|
{
|
|
|
|
|
USED(x);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void /*__attribute__((constructor))*/
|
|
|
|
|
ignusr1(void)
|
|
|
|
|
{
|
|
|
|
|
signal(SIGUSR1, ign);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Vous vouspool[2048];
|
|
|
|
|
static int nvousused;
|
|
|
|
|
static Vous *vousfree;
|
|
|
|
|
static Vous *voushash[VOUSHASH];
|
|
|
|
|
static Lock vouslock;
|
|
|
|
|
|
|
|
|
|
static Vous*
|
|
|
|
|
getvous(void)
|
|
|
|
|
{
|
|
|
|
|
Vous *v;
|
|
|
|
|
|
|
|
|
|
if(vousfree){
|
|
|
|
|
v = vousfree;
|
|
|
|
|
vousfree = v->link;
|
2003-10-01 02:53:00 +00:00
|
|
|
}else if(nvousused < nelem(vouspool)){
|
2003-09-30 17:47:41 +00:00
|
|
|
v = &vouspool[nvousused++];
|
2003-10-01 02:53:00 +00:00
|
|
|
pthread_mutex_init(&v->mutex, NULL);
|
|
|
|
|
}else
|
2003-09-30 17:47:41 +00:00
|
|
|
abort();
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
putvous(Vous *v)
|
|
|
|
|
{
|
|
|
|
|
lock(&vouslock);
|
|
|
|
|
v->link = vousfree;
|
|
|
|
|
vousfree = v;
|
|
|
|
|
unlock(&vouslock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Vous*
|
2003-10-01 02:53:00 +00:00
|
|
|
findvous(ulong tag, ulong val, int *found)
|
2003-09-30 17:47:41 +00:00
|
|
|
{
|
|
|
|
|
int h;
|
|
|
|
|
Vous *v, **l;
|
|
|
|
|
|
|
|
|
|
lock(&vouslock);
|
|
|
|
|
h = tag%VOUSHASH;
|
|
|
|
|
for(l=&voushash[h], v=*l; v; l=&(*l)->link, v=*l){
|
|
|
|
|
if(v->tag == tag){
|
|
|
|
|
*l = v->link;
|
2003-10-01 02:53:00 +00:00
|
|
|
*found = 1;
|
2003-09-30 17:47:41 +00:00
|
|
|
unlock(&vouslock);
|
|
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
v = getvous();
|
|
|
|
|
v->link = voushash[h];
|
|
|
|
|
v->val = val;
|
|
|
|
|
v->tag = tag;
|
|
|
|
|
lock(&v->lk);
|
|
|
|
|
voushash[h] = v;
|
|
|
|
|
unlock(&vouslock);
|
2003-10-01 02:53:00 +00:00
|
|
|
*found = 0;
|
2003-09-30 17:47:41 +00:00
|
|
|
return v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#define DBG 0
|
|
|
|
|
ulong
|
|
|
|
|
rendezvous(ulong tag, ulong val)
|
|
|
|
|
{
|
2003-10-01 02:53:00 +00:00
|
|
|
int found;
|
2003-09-30 17:47:41 +00:00
|
|
|
ulong rval;
|
|
|
|
|
Vous *v;
|
|
|
|
|
|
2003-10-01 02:53:00 +00:00
|
|
|
v = findvous(tag, val, &found);
|
|
|
|
|
if(!found){
|
|
|
|
|
if(DBG)fprint(2, "tag %lux, sleeping on %p\n", tag, v);
|
2003-09-30 17:47:41 +00:00
|
|
|
/*
|
|
|
|
|
* No rendezvous partner was found; the next guy
|
|
|
|
|
* through will find v and wake us, so we must go
|
2003-10-01 02:53:00 +00:00
|
|
|
* to sleep. Do this by locking the mutex (it is
|
|
|
|
|
* unlocked) and then locking it again (our waker will
|
|
|
|
|
* unlock it for us).
|
2003-09-30 17:47:41 +00:00
|
|
|
*/
|
2003-10-01 02:53:00 +00:00
|
|
|
if(pthread_mutex_lock(&v->mutex) != 0)
|
|
|
|
|
abort();
|
2003-09-30 17:47:41 +00:00
|
|
|
unlock(&v->lk);
|
2003-10-01 02:53:00 +00:00
|
|
|
if(pthread_mutex_lock(&v->mutex) != 0)
|
|
|
|
|
abort();
|
2003-09-30 17:47:41 +00:00
|
|
|
rval = v->val;
|
2003-10-01 02:53:00 +00:00
|
|
|
pthread_mutex_unlock(&v->mutex);
|
|
|
|
|
if(DBG)fprint(2, " awake on %p\n", v);
|
|
|
|
|
unlock(&v->lk);
|
2003-09-30 17:47:41 +00:00
|
|
|
putvous(v);
|
|
|
|
|
}else{
|
|
|
|
|
/*
|
|
|
|
|
* Found someone to meet. Wake him:
|
|
|
|
|
*
|
2003-10-01 02:53:00 +00:00
|
|
|
* A. lock v->lk (waits for him to lock the mutex once.
|
|
|
|
|
* B. unlock the mutex (wakes him up)
|
2003-09-30 17:47:41 +00:00
|
|
|
*/
|
2003-10-01 02:53:00 +00:00
|
|
|
if(DBG)fprint(2, "found tag %lux on %p, waking\n", tag, v);
|
2003-09-30 17:47:41 +00:00
|
|
|
lock(&v->lk);
|
|
|
|
|
rval = v->val;
|
|
|
|
|
v->val = val;
|
2003-10-01 02:53:00 +00:00
|
|
|
if(pthread_mutex_unlock(&v->mutex) != 0)
|
2003-09-30 17:47:41 +00:00
|
|
|
abort();
|
2003-10-01 02:53:00 +00:00
|
|
|
/* lock passes to him */
|
2003-09-30 17:47:41 +00:00
|
|
|
}
|
|
|
|
|
return rval;
|
|
|
|
|
}
|
|
|
|
|
|