Rewrite to remove dependence on rendezvous and its bizarre
data structures. Makes it easier to use pthreads too. Still need to add code for non-pthreads systems. Just a checkpoint to switch work to another machine.
This commit is contained in:
parent
984e353160
commit
06bb4ed20d
15 changed files with 205 additions and 218 deletions
|
|
@ -1,3 +1,6 @@
|
|||
#include "ffork-pthread.c"
|
||||
|
||||
#ifdef OLD
|
||||
/*
|
||||
* Is nothing simple?
|
||||
*
|
||||
|
|
@ -191,3 +194,4 @@ getfforkid(void)
|
|||
return getpid();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -2,52 +2,54 @@
|
|||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sched.h>
|
||||
#include <errno.h>
|
||||
#include <libc.h>
|
||||
|
||||
int _ntas;
|
||||
static int
|
||||
_xtas(void *v)
|
||||
{
|
||||
int x;
|
||||
static pthread_mutex_t initmutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
_ntas++;
|
||||
x = _tas(v);
|
||||
return x;
|
||||
}
|
||||
|
||||
int
|
||||
canlock(Lock *l)
|
||||
static void
|
||||
lockinit(Lock *lk)
|
||||
{
|
||||
return !_xtas(&l->val);
|
||||
}
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
void
|
||||
unlock(Lock *l)
|
||||
{
|
||||
l->val = 0;
|
||||
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)
|
||||
{
|
||||
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);
|
||||
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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,13 +16,15 @@ enum
|
|||
Waking,
|
||||
};
|
||||
|
||||
static ulong (*_rendezvousp)(ulong, ulong) = rendezvous;
|
||||
static void (*procsleep)(_Procrend*) = _procsleep;
|
||||
static void (*procwakeup)(_Procrend*) = _procwakeup;
|
||||
|
||||
/* this gets called by the thread library ONLY to get us to use its rendezvous */
|
||||
void
|
||||
_qlockinit(ulong (*r)(ulong, ulong))
|
||||
_qlockinit(void (*sleep)(_Procrend*), void (*wakeup)(_Procrend*))
|
||||
{
|
||||
_rendezvousp = r;
|
||||
procsleep = sleep;
|
||||
procwakeup = wakeup;
|
||||
}
|
||||
|
||||
/* find a free shared memory location to queue ourselves in */
|
||||
|
|
@ -39,7 +41,7 @@ getqlp(void)
|
|||
fprint(2, "qlock: out of qlp\n");
|
||||
abort();
|
||||
}
|
||||
if(_tas(&(p->inuse)) == 0){
|
||||
if(canlock(&p->inuse)){
|
||||
ql.p = p;
|
||||
p->next = nil;
|
||||
break;
|
||||
|
|
@ -70,13 +72,11 @@ qlock(QLock *q)
|
|||
p->next = mp;
|
||||
q->tail = mp;
|
||||
mp->state = Queuing;
|
||||
mp->rend.l = &q->lock;
|
||||
_procsleep(&mp->rend);
|
||||
unlock(&q->lock);
|
||||
|
||||
/* wait */
|
||||
while((*_rendezvousp)((ulong)mp, 1) == ~0)
|
||||
;
|
||||
assert(mp->state == Waking);
|
||||
mp->inuse = 0;
|
||||
unlock(&mp->inuse);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -91,10 +91,9 @@ qunlock(QLock *q)
|
|||
q->head = p->next;
|
||||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
unlock(&q->lock);
|
||||
p->state = Waking;
|
||||
while((*_rendezvousp)((ulong)p, 0x12345) == ~0)
|
||||
;
|
||||
_procwakeup(&p->rend);
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
q->locked = 0;
|
||||
|
|
@ -137,13 +136,11 @@ rlock(RWLock *q)
|
|||
q->tail = mp;
|
||||
mp->next = nil;
|
||||
mp->state = QueuingR;
|
||||
mp->rend.l = &q->lock;
|
||||
_procsleep(&mp->rend);
|
||||
unlock(&q->lock);
|
||||
|
||||
/* wait in kernel */
|
||||
while((*_rendezvousp)((ulong)mp, 1) == ~0)
|
||||
;
|
||||
assert(mp->state == Waking);
|
||||
mp->inuse = 0;
|
||||
unlock(&mp->inuse);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -181,12 +178,11 @@ runlock(RWLock *q)
|
|||
if(q->head == 0)
|
||||
q->tail = 0;
|
||||
q->writer = 1;
|
||||
unlock(&q->lock);
|
||||
|
||||
/* wakeup waiter */
|
||||
p->state = Waking;
|
||||
while((*_rendezvousp)((ulong)p, 0) == ~0)
|
||||
;
|
||||
_procwakeup(&p->rend);
|
||||
unlock(&q->lock);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -212,13 +208,13 @@ wlock(RWLock *q)
|
|||
q->tail = mp;
|
||||
mp->next = nil;
|
||||
mp->state = QueuingW;
|
||||
unlock(&q->lock);
|
||||
|
||||
/* wait in kernel */
|
||||
while((*_rendezvousp)((ulong)mp, 1) == ~0)
|
||||
;
|
||||
mp->rend.l = &q->lock;
|
||||
_procsleep(&mp->rend);
|
||||
unlock(&q->lock);
|
||||
assert(mp->state == Waking);
|
||||
mp->inuse = 0;
|
||||
unlock(&mp->inuse);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
@ -256,10 +252,9 @@ wunlock(RWLock *q)
|
|||
q->head = p->next;
|
||||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
unlock(&q->lock);
|
||||
p->state = Waking;
|
||||
while((*_rendezvousp)((ulong)p, 0) == ~0)
|
||||
;
|
||||
_procwakeup(&p->rend);
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -274,8 +269,7 @@ wunlock(RWLock *q)
|
|||
q->head = p->next;
|
||||
q->readers++;
|
||||
p->state = Waking;
|
||||
while((*_rendezvousp)((ulong)p, 0) == ~0)
|
||||
;
|
||||
_procwakeup(&p->rend);
|
||||
}
|
||||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
|
|
@ -315,20 +309,17 @@ rsleep(Rendez *r)
|
|||
r->l->head = t->next;
|
||||
if(r->l->head == nil)
|
||||
r->l->tail = nil;
|
||||
unlock(&r->l->lock);
|
||||
t->state = Waking;
|
||||
while((*_rendezvousp)((ulong)t, 0x12345) == ~0)
|
||||
;
|
||||
}else{
|
||||
_procwakeup(&t->rend);
|
||||
}else
|
||||
r->l->locked = 0;
|
||||
unlock(&r->l->lock);
|
||||
}
|
||||
|
||||
/* wait for a wakeup */
|
||||
while((*_rendezvousp)((ulong)me, 0x23456) == ~0)
|
||||
;
|
||||
me->rend.l = &r->l->lock;
|
||||
_procsleep(&me->rend);
|
||||
|
||||
assert(me->state == Waking);
|
||||
me->inuse = 0;
|
||||
unlock(&me->inuse);
|
||||
if(!r->l->locked){
|
||||
fprint(2, "rsleep: not locked after wakeup\n");
|
||||
abort();
|
||||
|
|
@ -384,3 +375,23 @@ rwakeupall(Rendez *r)
|
|||
;
|
||||
return i;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue