mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
cleanups - lots of removed files now in thread library.
qlock.c - stubs to thread library notify.c - clean interface slightly.
This commit is contained in:
parent
b2ff538258
commit
5f8fa94796
27 changed files with 123 additions and 968 deletions
|
@ -1 +0,0 @@
|
|||
#include "ffork-pthread.c"
|
|
@ -1,45 +0,0 @@
|
|||
#include <lib9.h>
|
||||
#include "9proc.h"
|
||||
|
||||
extern int __isthreaded;
|
||||
int
|
||||
ffork(int flags, void(*fn)(void*), void *arg)
|
||||
{
|
||||
int pid;
|
||||
void *p;
|
||||
|
||||
_p9uproc(0);
|
||||
__isthreaded = 1;
|
||||
p = malloc(16384);
|
||||
if(p == nil)
|
||||
return -1;
|
||||
memset(p, 0xFE, 16384);
|
||||
pid = rfork_thread(RFPROC|flags, (char*)p+16000, (int(*)(void*))fn, arg);
|
||||
if(pid == 0)
|
||||
_p9uproc(0);
|
||||
return pid;
|
||||
}
|
||||
|
||||
/*
|
||||
* For FreeBSD libc.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
volatile long access_lock;
|
||||
volatile long lock_owner;
|
||||
volatile char *fname;
|
||||
volatile int lineno;
|
||||
} spinlock_t;
|
||||
|
||||
void
|
||||
_spinlock(spinlock_t *lk)
|
||||
{
|
||||
lock((Lock*)&lk->access_lock);
|
||||
}
|
||||
|
||||
int
|
||||
getfforkid(void)
|
||||
{
|
||||
return getpid();
|
||||
}
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
/*
|
||||
* Is nothing simple?
|
||||
*
|
||||
* We can't free the stack until we've finished executing,
|
||||
* but once we've finished executing, we can't do anything
|
||||
* at all, including call free. So instead we keep a linked list
|
||||
* of all stacks for all processes, and every few times we try
|
||||
* to allocate a new stack we scan the current stack list for
|
||||
* dead processes and reclaim those stacks.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <libc.h>
|
||||
#include "9proc.h"
|
||||
|
||||
int fforkstacksize = 16384;
|
||||
|
||||
typedef struct Stack Stack;
|
||||
struct Stack
|
||||
{
|
||||
Stack *next;
|
||||
Stack *fnext;
|
||||
int pid;
|
||||
};
|
||||
|
||||
static Lock stacklock;
|
||||
static Stack *freestacks;
|
||||
static Stack *allstacks;
|
||||
static int stackmallocs;
|
||||
static void gc(void);
|
||||
|
||||
static void*
|
||||
mallocstack(void)
|
||||
{
|
||||
Stack *p;
|
||||
|
||||
lock(&stacklock);
|
||||
top:
|
||||
p = freestacks;
|
||||
if(p)
|
||||
freestacks = p->fnext;
|
||||
else{
|
||||
if(stackmallocs++%1 == 0)
|
||||
gc();
|
||||
if(freestacks)
|
||||
goto top;
|
||||
p = malloc(fforkstacksize);
|
||||
p->next = allstacks;
|
||||
allstacks = p;
|
||||
}
|
||||
if(p)
|
||||
p->pid = 1;
|
||||
unlock(&stacklock);
|
||||
return p;
|
||||
}
|
||||
|
||||
static void
|
||||
gc(void)
|
||||
{
|
||||
Stack *p;
|
||||
|
||||
for(p=allstacks; p; p=p->next){
|
||||
if(p->pid > 1)
|
||||
if(kill(p->pid, 0) < 0 && errno == ESRCH){
|
||||
if(0) fprint(2, "reclaim stack from %d\n", p->pid);
|
||||
p->pid = 0;
|
||||
}
|
||||
if(p->pid == 0){
|
||||
p->fnext = freestacks;
|
||||
freestacks = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
freestack(void *v)
|
||||
{
|
||||
Stack *p;
|
||||
|
||||
p = v;
|
||||
if(p == nil)
|
||||
return;
|
||||
lock(&stacklock);
|
||||
p->fnext = freestacks;
|
||||
p->pid = 0;
|
||||
freestacks = p;
|
||||
unlock(&stacklock);
|
||||
return;
|
||||
}
|
||||
|
||||
static int
|
||||
tramp(void *v)
|
||||
{
|
||||
void (*fn)(void*), *arg;
|
||||
void **v2;
|
||||
void *p;
|
||||
|
||||
_p9uproc(0);
|
||||
v2 = v;
|
||||
fn = v2[0];
|
||||
arg = v2[1];
|
||||
p = v2[2];
|
||||
free(v2);
|
||||
fn(arg);
|
||||
_exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
trampnowait(void *v)
|
||||
{
|
||||
int pid;
|
||||
int cloneflag;
|
||||
void **v2;
|
||||
int *pidp;
|
||||
void *p;
|
||||
|
||||
v2 = v;
|
||||
cloneflag = (int)v2[4];
|
||||
pidp = v2[3];
|
||||
p = v2[2];
|
||||
pid = clone(tramp, p+fforkstacksize-512, cloneflag, v);
|
||||
*pidp = pid;
|
||||
_exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
ffork(int flags, void (*fn)(void*), void *arg)
|
||||
{
|
||||
void **v;
|
||||
char *p;
|
||||
int cloneflag, pid, thepid, status, nowait;
|
||||
|
||||
_p9uproc(0);
|
||||
p = mallocstack();
|
||||
v = malloc(sizeof(void*)*5);
|
||||
if(p==nil || v==nil){
|
||||
freestack(p);
|
||||
free(v);
|
||||
return -1;
|
||||
}
|
||||
cloneflag = 0;
|
||||
flags &= ~RFPROC;
|
||||
if(flags&RFMEM){
|
||||
cloneflag |= CLONE_VM;
|
||||
flags &= ~RFMEM;
|
||||
}
|
||||
if(!(flags&RFFDG))
|
||||
cloneflag |= CLONE_FILES;
|
||||
else
|
||||
flags &= ~RFFDG;
|
||||
nowait = flags&RFNOWAIT;
|
||||
if(!(flags&RFNOWAIT))
|
||||
cloneflag |= SIGCHLD;
|
||||
else
|
||||
flags &= ~RFNOWAIT;
|
||||
if(flags){
|
||||
fprint(2, "unknown rfork flags %x\n", flags);
|
||||
freestack(p);
|
||||
free(v);
|
||||
return -1;
|
||||
}
|
||||
v[0] = fn;
|
||||
v[1] = arg;
|
||||
v[2] = p;
|
||||
v[3] = &thepid;
|
||||
v[4] = (void*)cloneflag;
|
||||
thepid = -1;
|
||||
pid = clone(nowait ? trampnowait : tramp, p+fforkstacksize-16, cloneflag, v);
|
||||
if(pid > 0 && nowait){
|
||||
if(wait4(pid, &status, __WALL, 0) < 0)
|
||||
fprint(2, "ffork wait4: %r\n");
|
||||
}else
|
||||
thepid = pid;
|
||||
if(thepid == -1)
|
||||
freestack(p);
|
||||
else
|
||||
((Stack*)p)->pid = thepid;
|
||||
return thepid;
|
||||
}
|
||||
|
||||
int
|
||||
getfforkid(void)
|
||||
{
|
||||
return getpid();
|
||||
}
|
||||
|
|
@ -1,5 +0,0 @@
|
|||
#ifdef __Linux26__
|
||||
#include "ffork-pthread.c"
|
||||
#else
|
||||
#include "ffork-Linux-clone.c"
|
||||
#endif
|
|
@ -1 +0,0 @@
|
|||
#include "ffork-pthread.c"
|
|
@ -1 +0,0 @@
|
|||
#include "ffork-pthread.c"
|
|
@ -1,31 +0,0 @@
|
|||
#define NOPLAN9DEFINES
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <pthread.h>
|
||||
#include "9proc.h"
|
||||
|
||||
extern int __isthreaded;
|
||||
int
|
||||
ffork(int flags, void(*fn)(void*), void *arg)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
if(flags != (RFMEM|RFNOWAIT)){
|
||||
werrstr("ffork unsupported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_p9uproc(0);
|
||||
if(pthread_create(&tid, NULL, (void*(*)(void*))fn, arg) < 0)
|
||||
return -1;
|
||||
if((int)tid == 0)
|
||||
_p9uproc(0);
|
||||
return (int)tid;
|
||||
}
|
||||
|
||||
int
|
||||
getfforkid(void)
|
||||
{
|
||||
return (int)pthread_self();
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
#include "lock-pthread.c"
|
|
@ -1 +0,0 @@
|
|||
#include "lock-tas.c"
|
|
@ -1,5 +0,0 @@
|
|||
#ifdef __Linux26__
|
||||
#include "lock-pthread.c"
|
||||
#else
|
||||
#include "lock-tas.c"
|
||||
#endif
|
|
@ -1,55 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sched.h>
|
||||
#include <errno.h>
|
||||
#include <libc.h>
|
||||
|
||||
static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static void
|
||||
lockinit(Lock *lk)
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
pthread_mutex_lock(&initmutex);
|
||||
if(lk->init == 0){
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
|
||||
pthread_mutex_init(&lk->mutex, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
lk->init = 1;
|
||||
}
|
||||
pthread_mutex_unlock(&initmutex);
|
||||
}
|
||||
|
||||
void
|
||||
lock(Lock *lk)
|
||||
{
|
||||
if(!lk->init)
|
||||
lockinit(lk);
|
||||
if(pthread_mutex_lock(&lk->mutex) != 0)
|
||||
abort();
|
||||
}
|
||||
|
||||
int
|
||||
canlock(Lock *lk)
|
||||
{
|
||||
int r;
|
||||
|
||||
if(!lk->init)
|
||||
lockinit(lk);
|
||||
r = pthread_mutex_trylock(&lk->mutex);
|
||||
if(r == 0)
|
||||
return 1;
|
||||
if(r == EBUSY)
|
||||
return 0;
|
||||
abort();
|
||||
}
|
||||
|
||||
void
|
||||
unlock(Lock *lk)
|
||||
{
|
||||
if(pthread_mutex_unlock(&lk->mutex) != 0)
|
||||
abort();
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sched.h>
|
||||
#include <libc.h>
|
||||
|
||||
int _ntas;
|
||||
static int
|
||||
_xtas(void *v)
|
||||
{
|
||||
int x;
|
||||
|
||||
_ntas++;
|
||||
x = _tas(v);
|
||||
if(x != 0 && x != 0xcafebabe){
|
||||
print("bad tas value %d\n", x);
|
||||
abort();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
int
|
||||
canlock(Lock *l)
|
||||
{
|
||||
return !_xtas(&l->val);
|
||||
}
|
||||
|
||||
void
|
||||
unlock(Lock *l)
|
||||
{
|
||||
l->val = 0;
|
||||
}
|
||||
|
||||
void
|
||||
lock(Lock *lk)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* once fast */
|
||||
if(!_xtas(&lk->val))
|
||||
return;
|
||||
/* a thousand times pretty fast */
|
||||
for(i=0; i<1000; i++){
|
||||
if(!_xtas(&lk->val))
|
||||
return;
|
||||
sched_yield();
|
||||
}
|
||||
/* now nice and slow */
|
||||
for(i=0; i<1000; i++){
|
||||
if(!_xtas(&lk->val))
|
||||
return;
|
||||
usleep(100*1000);
|
||||
}
|
||||
/* take your time */
|
||||
while(_xtas(&lk->val))
|
||||
usleep(1000*1000);
|
||||
}
|
|
@ -108,7 +108,6 @@ LIB9OFILES=\
|
|||
jmp.$O\
|
||||
lrand.$O\
|
||||
lnrand.$O\
|
||||
lock-$SYSNAME.$O\
|
||||
main.$O\
|
||||
malloc.$O\
|
||||
malloctag.$O\
|
||||
|
@ -129,7 +128,6 @@ LIB9OFILES=\
|
|||
quote.$O\
|
||||
read9pmsg.$O\
|
||||
readn.$O\
|
||||
rendez-$SYSNAME.$O\
|
||||
rfork.$O\
|
||||
seek.$O\
|
||||
sendfd.$O\
|
||||
|
@ -138,7 +136,6 @@ LIB9OFILES=\
|
|||
strecpy.$O\
|
||||
sysfatal.$O\
|
||||
sysname.$O\
|
||||
tas-$OBJTYPE.$O\
|
||||
time.$O\
|
||||
tokenize.$O\
|
||||
truerand.$O\
|
||||
|
@ -164,5 +161,3 @@ HFILES=\
|
|||
|
||||
%.$O: utf/%.c
|
||||
$CC $CFLAGS utf/$stem.c
|
||||
|
||||
rendez-Linux.$O: rendez-signal.c
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
* There is no equivalent note to Unix's SIGKILL, since
|
||||
* it's not a deliverable signal anyway.
|
||||
*
|
||||
* We do not handle SIGABRT or SIGSEGV, mainly so that
|
||||
* stack traces show the original source of the signal instead
|
||||
* of notifysigf.
|
||||
* We do not handle SIGABRT or SIGSEGV, mainly because
|
||||
* the thread library queues its notes for later, and we want
|
||||
* to dump core with the state at time of delivery.
|
||||
*
|
||||
* We have to add some extra entry points to provide the
|
||||
* ability to tweak which signals are deliverable and which
|
||||
|
@ -112,7 +112,6 @@ static void (*notifyf)(void*, char*); /* Plan 9 handler */
|
|||
static void
|
||||
signotify(int sig)
|
||||
{
|
||||
int v;
|
||||
char tmp[64];
|
||||
Jmp *j;
|
||||
|
||||
|
@ -150,7 +149,6 @@ noted(int v)
|
|||
int
|
||||
notify(void (*f)(void*, char*))
|
||||
{
|
||||
int i;
|
||||
static int init;
|
||||
|
||||
notifyf = f;
|
||||
|
@ -164,7 +162,8 @@ notify(void (*f)(void*, char*))
|
|||
/*
|
||||
* Nonsense about enabling and disabling signals.
|
||||
*/
|
||||
static void(*)(int)
|
||||
typedef void Sighandler(int);
|
||||
static Sighandler*
|
||||
handler(int s)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
@ -174,7 +173,7 @@ handler(int s)
|
|||
}
|
||||
|
||||
static void
|
||||
notifysetenable(int sig, int enabled)
|
||||
notesetenable(int sig, int enabled)
|
||||
{
|
||||
sigset_t mask;
|
||||
|
||||
|
@ -187,15 +186,15 @@ notifysetenable(int sig, int enabled)
|
|||
}
|
||||
|
||||
void
|
||||
notifyenable(char *msg)
|
||||
noteenable(char *msg)
|
||||
{
|
||||
notifyenablex(_p9strsig(msg), 1);
|
||||
notesetenable(_p9strsig(msg), 1);
|
||||
}
|
||||
|
||||
void
|
||||
notifydisable(char *msg)
|
||||
notedisable(char *msg)
|
||||
{
|
||||
notifyenablex(_p9strsig(msg), 0);
|
||||
notesetenable(_p9strsig(msg), 0);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -207,7 +206,8 @@ notifyseton(int s, int on)
|
|||
sig = findsig(s);
|
||||
if(sig == nil)
|
||||
return;
|
||||
notifyenable(msg);
|
||||
if(on)
|
||||
notesetenable(s, 1);
|
||||
memset(&sa, 0, sizeof sa);
|
||||
sa.sa_handler = on ? signotify : signonotify;
|
||||
if(sig->restart)
|
||||
|
@ -234,7 +234,7 @@ notifyon(char *msg)
|
|||
void
|
||||
notifyoff(char *msg)
|
||||
{
|
||||
notifysetoff(_p9strsig(msg), 0);
|
||||
notifyseton(_p9strsig(msg), 0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -252,6 +252,7 @@ noteinit(void)
|
|||
* If someone has already installed a handler,
|
||||
* It's probably some ld preload nonsense,
|
||||
* like pct (a SIGVTALRM-based profiler).
|
||||
* Or maybe someone has already called notifyon/notifyoff.
|
||||
* Leave it alone.
|
||||
*/
|
||||
if(handler(sig->sig) != SIG_DFL)
|
||||
|
@ -261,7 +262,7 @@ noteinit(void)
|
|||
* (I.e. if parent has disabled for us, should we still enable?)
|
||||
* Right now we always initialize to the state we want.
|
||||
*/
|
||||
notifysetenable(sig->sig, sig->enabled);
|
||||
notesetenable(sig->sig, sig->enabled);
|
||||
notifyseton(sig->sig, sig->notified);
|
||||
}
|
||||
}
|
||||
|
|
428
src/lib9/qlock.c
428
src/lib9/qlock.c
|
@ -1,379 +1,167 @@
|
|||
#include <lib9.h>
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static struct {
|
||||
QLp *p;
|
||||
QLp x[1024];
|
||||
} ql = {
|
||||
ql.x
|
||||
};
|
||||
/*
|
||||
* The function pointers are supplied by the thread
|
||||
* library during its initialization. If there is no thread
|
||||
* library, there is no multithreading.
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
Queuing,
|
||||
QueuingR,
|
||||
QueuingW,
|
||||
Sleeping,
|
||||
Waking,
|
||||
};
|
||||
|
||||
static void (*procsleep)(_Procrend*) = _procsleep;
|
||||
static void (*procwakeup)(_Procrend*) = _procwakeup;
|
||||
#define _procsleep donotcall_procsleep
|
||||
#define _procwakeup donotcall_procwakeup
|
||||
|
||||
/* this gets called by the thread library ONLY to get us to use its rendezvous */
|
||||
void
|
||||
_qlockinit(void (*sleep)(_Procrend*), void (*wakeup)(_Procrend*))
|
||||
{
|
||||
procsleep = sleep;
|
||||
procwakeup = wakeup;
|
||||
}
|
||||
|
||||
/* find a free shared memory location to queue ourselves in */
|
||||
static QLp*
|
||||
getqlp(void)
|
||||
{
|
||||
QLp *p, *op;
|
||||
|
||||
op = ql.p;
|
||||
for(p = op+1; ; p++){
|
||||
if(p == &ql.x[nelem(ql.x)])
|
||||
p = ql.x;
|
||||
if(p == op){
|
||||
fprint(2, "qlock: out of qlp\n");
|
||||
abort();
|
||||
}
|
||||
if(canlock(&p->inuse)){
|
||||
ql.p = p;
|
||||
p->next = nil;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
int (*_lock)(Lock*, int, ulong);
|
||||
void (*_unlock)(Lock*, ulong);
|
||||
int (*_qlock)(QLock*, int, ulong); /* do not use */
|
||||
void (*_qunlock)(QLock*, ulong);
|
||||
void (*_rsleep)(Rendez*, ulong); /* do not use */
|
||||
int (*_rwakeup)(Rendez*, int, ulong);
|
||||
int (*_rlock)(RWLock*, int, ulong); /* do not use */
|
||||
int (*_wlock)(RWLock*, int, ulong);
|
||||
void (*_runlock)(RWLock*, ulong);
|
||||
void (*_wunlock)(RWLock*, ulong);
|
||||
|
||||
void
|
||||
qlock(QLock *q)
|
||||
lock(Lock *l)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
|
||||
lock(&q->lock);
|
||||
if(!q->locked){
|
||||
q->locked = 1;
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* chain into waiting list */
|
||||
mp = getqlp();
|
||||
p = q->tail;
|
||||
if(p == nil)
|
||||
q->head = mp;
|
||||
if(_lock)
|
||||
(*_lock)(l, 1, getcallerpc(&l));
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->state = Queuing;
|
||||
mp->rend.l = &q->lock;
|
||||
procsleep(&mp->rend);
|
||||
unlock(&q->lock);
|
||||
assert(mp->state == Waking);
|
||||
unlock(&mp->inuse);
|
||||
}
|
||||
|
||||
void
|
||||
qunlock(QLock *q)
|
||||
{
|
||||
QLp *p;
|
||||
|
||||
lock(&q->lock);
|
||||
p = q->head;
|
||||
if(p != nil){
|
||||
/* wakeup head waiting process */
|
||||
q->head = p->next;
|
||||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
p->state = Waking;
|
||||
procwakeup(&p->rend);
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
q->locked = 0;
|
||||
unlock(&q->lock);
|
||||
l->held = 1;
|
||||
}
|
||||
|
||||
int
|
||||
canqlock(QLock *q)
|
||||
canlock(Lock *l)
|
||||
{
|
||||
if(!canlock(&q->lock))
|
||||
return 0;
|
||||
if(!q->locked){
|
||||
q->locked = 1;
|
||||
unlock(&q->lock);
|
||||
if(_lock)
|
||||
return (*_lock)(l, 0, getcallerpc(&l));
|
||||
else{
|
||||
if(l->held)
|
||||
return 0;
|
||||
l->held = 1;
|
||||
return 1;
|
||||
}
|
||||
unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
rlock(RWLock *q)
|
||||
unlock(Lock *l)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
|
||||
lock(&q->lock);
|
||||
if(q->writer == 0 && q->head == nil){
|
||||
/* no writer, go for it */
|
||||
q->readers++;
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
mp = getqlp();
|
||||
p = q->tail;
|
||||
if(p == 0)
|
||||
q->head = mp;
|
||||
if(_unlock)
|
||||
(*_unlock)(l, getcallerpc(&l));
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->next = nil;
|
||||
mp->state = QueuingR;
|
||||
mp->rend.l = &q->lock;
|
||||
procsleep(&mp->rend);
|
||||
unlock(&q->lock);
|
||||
assert(mp->state == Waking);
|
||||
unlock(&mp->inuse);
|
||||
l->held = 0;
|
||||
}
|
||||
|
||||
void
|
||||
qlock(QLock *l)
|
||||
{
|
||||
if(_qlock)
|
||||
(*_qlock)(l, 1, getcallerpc(&l));
|
||||
else
|
||||
l->l.held = 1;
|
||||
}
|
||||
|
||||
int
|
||||
canrlock(RWLock *q)
|
||||
canqlock(QLock *l)
|
||||
{
|
||||
lock(&q->lock);
|
||||
if (q->writer == 0 && q->head == nil) {
|
||||
/* no writer; go for it */
|
||||
q->readers++;
|
||||
unlock(&q->lock);
|
||||
if(_qlock)
|
||||
return (*_qlock)(l, 0, getcallerpc(&l));
|
||||
else{
|
||||
if(l->l.held)
|
||||
return 0;
|
||||
l->l.held = 1;
|
||||
return 1;
|
||||
}
|
||||
unlock(&q->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
runlock(RWLock *q)
|
||||
qunlock(QLock *l)
|
||||
{
|
||||
QLp *p;
|
||||
|
||||
lock(&q->lock);
|
||||
if(q->readers <= 0)
|
||||
abort();
|
||||
p = q->head;
|
||||
if(--(q->readers) > 0 || p == nil){
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* start waiting writer */
|
||||
if(p->state != QueuingW)
|
||||
abort();
|
||||
q->head = p->next;
|
||||
if(q->head == 0)
|
||||
q->tail = 0;
|
||||
q->writer = 1;
|
||||
|
||||
/* wakeup waiter */
|
||||
p->state = Waking;
|
||||
procwakeup(&p->rend);
|
||||
unlock(&q->lock);
|
||||
}
|
||||
|
||||
void
|
||||
wlock(RWLock *q)
|
||||
{
|
||||
QLp *p, *mp;
|
||||
|
||||
lock(&q->lock);
|
||||
if(q->readers == 0 && q->writer == 0){
|
||||
/* noone waiting, go for it */
|
||||
q->writer = 1;
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* wait */
|
||||
p = q->tail;
|
||||
mp = getqlp();
|
||||
if(p == nil)
|
||||
q->head = mp;
|
||||
if(_qunlock)
|
||||
(*_qunlock)(l, getcallerpc(&l));
|
||||
else
|
||||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->next = nil;
|
||||
mp->state = QueuingW;
|
||||
l->l.held = 0;
|
||||
}
|
||||
|
||||
/* wait in kernel */
|
||||
mp->rend.l = &q->lock;
|
||||
procsleep(&mp->rend);
|
||||
unlock(&q->lock);
|
||||
assert(mp->state == Waking);
|
||||
unlock(&mp->inuse);
|
||||
void
|
||||
rlock(RWLock *l)
|
||||
{
|
||||
if(_rlock)
|
||||
(*_rlock)(l, 1, getcallerpc(&l));
|
||||
else
|
||||
l->readers++;
|
||||
}
|
||||
|
||||
int
|
||||
canwlock(RWLock *q)
|
||||
canrlock(RWLock *l)
|
||||
{
|
||||
lock(&q->lock);
|
||||
if (q->readers == 0 && q->writer == 0) {
|
||||
/* no one waiting; go for it */
|
||||
q->writer = 1;
|
||||
unlock(&q->lock);
|
||||
if(_rlock)
|
||||
return (*_rlock)(l, 0, getcallerpc(&l));
|
||||
else{
|
||||
if(l->writer)
|
||||
return 0;
|
||||
l->readers++;
|
||||
return 1;
|
||||
}
|
||||
unlock(&q->lock);
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
wunlock(RWLock *q)
|
||||
runlock(RWLock *l)
|
||||
{
|
||||
QLp *p;
|
||||
if(_runlock)
|
||||
(*_runlock)(l, getcallerpc(&l));
|
||||
else
|
||||
l->readers--;
|
||||
}
|
||||
|
||||
lock(&q->lock);
|
||||
if(q->writer == 0){
|
||||
fprint(2, "wunlock: not holding lock\n");
|
||||
abort();
|
||||
}
|
||||
p = q->head;
|
||||
if(p == nil){
|
||||
q->writer = 0;
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
if(p->state == QueuingW){
|
||||
/* start waiting writer */
|
||||
q->head = p->next;
|
||||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
p->state = Waking;
|
||||
procwakeup(&p->rend);
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
void
|
||||
wlock(RWLock *l)
|
||||
{
|
||||
if(_wlock)
|
||||
(*_wlock)(l, 1, getcallerpc(&l));
|
||||
else
|
||||
l->writer = (void*)1;
|
||||
}
|
||||
|
||||
if(p->state != QueuingR){
|
||||
fprint(2, "wunlock: bad state\n");
|
||||
abort();
|
||||
int
|
||||
canwlock(RWLock *l)
|
||||
{
|
||||
if(_wlock)
|
||||
return (*_wlock)(l, 0, getcallerpc(&l));
|
||||
else{
|
||||
if(l->writer || l->readers)
|
||||
return 0;
|
||||
l->writer = (void*)1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* wake waiting readers */
|
||||
while(q->head != nil && q->head->state == QueuingR){
|
||||
p = q->head;
|
||||
q->head = p->next;
|
||||
q->readers++;
|
||||
p->state = Waking;
|
||||
procwakeup(&p->rend);
|
||||
}
|
||||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
q->writer = 0;
|
||||
unlock(&q->lock);
|
||||
void
|
||||
wunlock(RWLock *l)
|
||||
{
|
||||
if(_wunlock)
|
||||
(*_wunlock)(l, getcallerpc(&l));
|
||||
else
|
||||
l->writer = nil;
|
||||
}
|
||||
|
||||
void
|
||||
rsleep(Rendez *r)
|
||||
{
|
||||
QLp *t, *me;
|
||||
|
||||
if(!r->l){
|
||||
fprint(2, "rsleep: no lock\n");
|
||||
abort();
|
||||
}
|
||||
lock(&r->l->lock);
|
||||
/* we should hold the qlock */
|
||||
if(!r->l->locked){
|
||||
fprint(2, "rsleep: not locked\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
/* add ourselves to the wait list */
|
||||
me = getqlp();
|
||||
me->state = Sleeping;
|
||||
if(r->head == nil)
|
||||
r->head = me;
|
||||
else
|
||||
r->tail->next = me;
|
||||
me->next = nil;
|
||||
r->tail = me;
|
||||
|
||||
/* pass the qlock to the next guy */
|
||||
t = r->l->head;
|
||||
if(t){
|
||||
r->l->head = t->next;
|
||||
if(r->l->head == nil)
|
||||
r->l->tail = nil;
|
||||
t->state = Waking;
|
||||
procwakeup(&t->rend);
|
||||
}else
|
||||
r->l->locked = 0;
|
||||
|
||||
/* wait for a wakeup */
|
||||
me->rend.l = &r->l->lock;
|
||||
procsleep(&me->rend);
|
||||
assert(me->state == Waking);
|
||||
unlock(&me->inuse);
|
||||
if(!r->l->locked){
|
||||
fprint(2, "rsleep: not locked after wakeup\n");
|
||||
abort();
|
||||
}
|
||||
unlock(&r->l->lock);
|
||||
if(_rsleep)
|
||||
(*_rsleep)(r, getcallerpc(&r));
|
||||
}
|
||||
|
||||
int
|
||||
rwakeup(Rendez *r)
|
||||
{
|
||||
QLp *t;
|
||||
|
||||
/*
|
||||
* take off wait and put on front of queue
|
||||
* put on front so guys that have been waiting will not get starved
|
||||
*/
|
||||
|
||||
if(!r->l){
|
||||
fprint(2, "rwakeup: no lock\n");
|
||||
abort();
|
||||
}
|
||||
lock(&r->l->lock);
|
||||
if(!r->l->locked){
|
||||
fprint(2, "rwakeup: not locked\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
t = r->head;
|
||||
if(t == nil){
|
||||
unlock(&r->l->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r->head = t->next;
|
||||
if(r->head == nil)
|
||||
r->tail = nil;
|
||||
|
||||
t->next = r->l->head;
|
||||
r->l->head = t;
|
||||
if(r->l->tail == nil)
|
||||
r->l->tail = t;
|
||||
|
||||
t->state = Queuing;
|
||||
unlock(&r->l->lock);
|
||||
return 1;
|
||||
if(_rwakeup)
|
||||
return (*_rwakeup)(r, 0, getcallerpc(&r));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
rwakeupall(Rendez *r)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i=0; rwakeup(r); i++)
|
||||
;
|
||||
return i;
|
||||
if(_rwakeup)
|
||||
return (*_rwakeup)(r, 1, getcallerpc(&r));
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
#include "rendez-pthread.c"
|
||||
|
|
@ -1 +0,0 @@
|
|||
#include "rendez-signal.c"
|
|
@ -1,5 +0,0 @@
|
|||
#ifdef __Linux26__
|
||||
#include "rendez-pthread.c"
|
||||
#else
|
||||
#include "rendez-signal.c"
|
||||
#endif
|
|
@ -1 +0,0 @@
|
|||
#include "rendez-signal.c"
|
|
@ -1 +0,0 @@
|
|||
#include "rendez-pthread.c"
|
|
@ -1,23 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <pthread.h>
|
||||
#include <libc.h>
|
||||
|
||||
void
|
||||
_procsleep(_Procrend *rend)
|
||||
{
|
||||
//print("sleep %p %d\n", rend, getpid());
|
||||
pthread_cond_init(&rend->cond, 0);
|
||||
rend->asleep = 1;
|
||||
while(rend->asleep)
|
||||
pthread_cond_wait(&rend->cond, &rend->l->mutex);
|
||||
pthread_cond_destroy(&rend->cond);
|
||||
}
|
||||
|
||||
void
|
||||
_procwakeup(_Procrend *rend)
|
||||
{
|
||||
//print("wakeup %p\n", rend);
|
||||
rend->asleep = 0;
|
||||
pthread_cond_signal(&rend->cond);
|
||||
}
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <signal.h>
|
||||
#include <libc.h>
|
||||
|
||||
#define DBG 0
|
||||
|
||||
static void
|
||||
ign(int x)
|
||||
{
|
||||
USED(x);
|
||||
}
|
||||
|
||||
void /*__attribute__((constructor))*/
|
||||
ignusr1(int restart)
|
||||
{
|
||||
struct sigaction sa;
|
||||
|
||||
memset(&sa, 0, sizeof sa);
|
||||
sa.sa_handler = ign;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaddset(&sa.sa_mask, SIGUSR1);
|
||||
if(restart)
|
||||
sa.sa_flags = SA_RESTART;
|
||||
sigaction(SIGUSR1, &sa, nil);
|
||||
}
|
||||
|
||||
void
|
||||
_procsleep(_Procrend *r)
|
||||
{
|
||||
sigset_t mask;
|
||||
|
||||
/*
|
||||
* Go to sleep.
|
||||
*
|
||||
* Block USR1, set the handler to interrupt system calls,
|
||||
* unlock the vouslock so our waker can wake us,
|
||||
* and then suspend.
|
||||
*/
|
||||
r->asleep = 1;
|
||||
r->pid = getpid();
|
||||
|
||||
sigprocmask(SIG_SETMASK, nil, &mask);
|
||||
sigaddset(&mask, SIGUSR1);
|
||||
sigprocmask(SIG_SETMASK, &mask, nil);
|
||||
ignusr1(0);
|
||||
unlock(r->l);
|
||||
sigdelset(&mask, SIGUSR1);
|
||||
sigsuspend(&mask);
|
||||
|
||||
/*
|
||||
* We're awake. Make USR1 not interrupt system calls.
|
||||
*/
|
||||
ignusr1(1);
|
||||
assert(r->asleep == 0);
|
||||
lock(r->l);
|
||||
}
|
||||
|
||||
void
|
||||
_procwakeup(_Procrend *r)
|
||||
{
|
||||
r->asleep = 0;
|
||||
assert(r->pid >= 1);
|
||||
kill(r->pid, SIGUSR1);
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "9proc.h"
|
||||
|
||||
static Lock rendlock;
|
||||
static Uproc *rendhash[RENDHASH];
|
||||
|
||||
ulong
|
||||
rendezvous(ulong tag, ulong val)
|
||||
{
|
||||
char c;
|
||||
ulong ret;
|
||||
Uproc *t, *self, **l;
|
||||
|
||||
self = _p9uproc(0);
|
||||
lock(&rendlock);
|
||||
l = &rendhash[tag%RENDHASH];
|
||||
for(t=*l; t; l=&t->rendhash, t=*l){
|
||||
if(t->rendtag==tag){
|
||||
*l = t->rendhash;
|
||||
ret = t->rendval;
|
||||
t->rendval = val;
|
||||
t->rendtag++;
|
||||
c = 0;
|
||||
unlock(&rendlock);
|
||||
write(t->pipe[1], &c, 1);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Going to sleep here. */
|
||||
t = self;
|
||||
t->rendtag = tag;
|
||||
t->rendval = val;
|
||||
t->rendhash = *l;
|
||||
*l = t;
|
||||
unlock(&rendlock);
|
||||
do
|
||||
read(t->pipe[0], &c, 1);
|
||||
while(t->rendtag == tag);
|
||||
return t->rendval;
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
.globl _tas
|
||||
_tas:
|
||||
movl $0xCAFEBABE, %eax
|
||||
movl 4(%esp), %ecx
|
||||
xchgl %eax, 0(%ecx)
|
||||
ret
|
|
@ -1,42 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "libc.h"
|
||||
|
||||
/*
|
||||
* first argument (l) is in r3 at entry.
|
||||
* r3 contains return value upon return.
|
||||
*/
|
||||
int
|
||||
_tas(int *x)
|
||||
{
|
||||
int v;
|
||||
/*
|
||||
* this __asm__ works with gcc 2.95.2 (mac os x 10.1).
|
||||
* this assembly language destroys r0 (0), some other register (v),
|
||||
* r4 (x) and r5 (temp).
|
||||
*/
|
||||
__asm__("\n sync\n"
|
||||
" li r0,0\n"
|
||||
" mr r4,%1 /* &l->val */\n"
|
||||
" lis r5,0xdead /* assemble constant 0xdeaddead */\n"
|
||||
" ori r5,r5,0xdead /* \" */\n"
|
||||
"tas1:\n"
|
||||
" dcbf r4,r0 /* cache flush; \"fix for 603x bug\" */\n"
|
||||
" lwarx %0,r4,r0 /* v = l->val with reservation */\n"
|
||||
" cmp cr0,0,%0,r0 /* v == 0 */\n"
|
||||
" bne tas0\n"
|
||||
" stwcx. r5,r4,r0 /* if (l->val same) l->val = 0xdeaddead */\n"
|
||||
" bne tas1\n"
|
||||
"tas0:\n"
|
||||
" sync\n"
|
||||
" isync\n"
|
||||
: "=r" (v)
|
||||
: "r" (x)
|
||||
: "cc", "memory", "r0", "r4", "r5"
|
||||
);
|
||||
switch(v) {
|
||||
case 0: return 0;
|
||||
case 0xdeaddead: return 1;
|
||||
default: fprint(2, "tas: corrupted 0x%lux\n", v);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
#include "u.h"
|
||||
#include "libc.h"
|
||||
|
||||
/*
|
||||
* first argument (l) is in r3 at entry.
|
||||
* r3 contains return value upon return.
|
||||
*/
|
||||
int
|
||||
_tas(int *x)
|
||||
{
|
||||
int v;
|
||||
int tmp, tmp2, tmp3;
|
||||
|
||||
/*
|
||||
* this __asm__ works with gcc on linux
|
||||
*/
|
||||
__asm__("\n sync\n"
|
||||
" li %1,0\n"
|
||||
" mr %2,%4 /* &x->val */\n"
|
||||
" lis %3,0xdead /* assemble constant 0xdeaddead */\n"
|
||||
" ori %3,%3,0xdead /* \" */\n"
|
||||
"tas1:\n"
|
||||
" dcbf %2,%1 /* cache flush; \"fix for 603x bug\" */\n"
|
||||
" lwarx %0,%2,%1 /* v = x->val with reservation */\n"
|
||||
" cmp cr0,0,%0,%1 /* v == 0 */\n"
|
||||
" bne tas0\n"
|
||||
" stwcx. %3,%2,%1 /* if (x->val same) x->val = 0xdeaddead */\n"
|
||||
" bne tas1\n"
|
||||
"tas0:\n"
|
||||
" sync\n"
|
||||
" isync\n"
|
||||
: "=r" (v), "=&r" (tmp), "=&r"(tmp2), "=&r"(tmp3)
|
||||
: "r" (x)
|
||||
: "cr0", "memory"
|
||||
);
|
||||
switch(v) {
|
||||
case 0: return 0;
|
||||
case 0xdeaddead: return 1;
|
||||
default: fprint(2, "tas: corrupted 0x%lux\n", v);
|
||||
}
|
||||
return 0;
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
.globl _tas
|
||||
_tas:
|
||||
retl
|
||||
ldstub [%o0], %o0
|
Loading…
Reference in a new issue