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:
rsc 2004-12-26 21:51:15 +00:00
parent b2ff538258
commit 5f8fa94796
27 changed files with 123 additions and 968 deletions

View file

@ -1 +0,0 @@
#include "ffork-pthread.c"

View file

@ -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();
}

View file

@ -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();
}

View file

@ -1,5 +0,0 @@
#ifdef __Linux26__
#include "ffork-pthread.c"
#else
#include "ffork-Linux-clone.c"
#endif

View file

@ -1 +0,0 @@
#include "ffork-pthread.c"

View file

@ -1 +0,0 @@
#include "ffork-pthread.c"

View file

@ -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();
}

View file

@ -1 +0,0 @@
#include "lock-pthread.c"

View file

@ -1 +0,0 @@
#include "lock-tas.c"

View file

@ -1,5 +0,0 @@
#ifdef __Linux26__
#include "lock-pthread.c"
#else
#include "lock-tas.c"
#endif

View file

@ -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();
}

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -1,2 +0,0 @@
#include "rendez-pthread.c"

View file

@ -1 +0,0 @@
#include "rendez-signal.c"

View file

@ -1,5 +0,0 @@
#ifdef __Linux26__
#include "rendez-pthread.c"
#else
#include "rendez-signal.c"
#endif

View file

@ -1 +0,0 @@
#include "rendez-signal.c"

View file

@ -1 +0,0 @@
#include "rendez-pthread.c"

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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;
}

View file

@ -1,6 +0,0 @@
.globl _tas
_tas:
movl $0xCAFEBABE, %eax
movl 4(%esp), %ecx
xchgl %eax, 0(%ecx)
ret

View file

@ -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;
}

View file

@ -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;
}

View file

@ -1,4 +0,0 @@
.globl _tas
_tas:
retl
ldstub [%o0], %o0