Continue the pthreads torture.
This commit is contained in:
parent
3d5e34e146
commit
c6687d4591
25 changed files with 440 additions and 124 deletions
|
|
@ -13,9 +13,6 @@ struct Uproc
|
|||
int pid;
|
||||
int state;
|
||||
void *priv[NPRIV];
|
||||
ulong rendval;
|
||||
ulong rendtag;
|
||||
Uproc *rendhash;
|
||||
p9jmp_buf notejb;
|
||||
};
|
||||
|
||||
|
|
|
|||
5
src/lib9/_p9proc-Linux.c
Normal file
5
src/lib9/_p9proc-Linux.c
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#ifdef __Linux26__
|
||||
#include "_p9proc-pthread.c"
|
||||
#else
|
||||
#include "_p9proc-getpid.c"
|
||||
#endif
|
||||
113
src/lib9/_p9proc-getpid.c
Normal file
113
src/lib9/_p9proc-getpid.c
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
* This needs to be callable from a signal handler, so it has been
|
||||
* written to avoid locks. The only lock is the one used to acquire
|
||||
* an entry in the table, and we make sure that acquiring is done
|
||||
* when not in a handler. Lookup and delete do not need locks.
|
||||
* It's a scan-forward hash table. To avoid breaking chains,
|
||||
* T ((void*)-1) is used as a non-breaking nil.
|
||||
*/
|
||||
|
||||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include "9proc.h"
|
||||
|
||||
enum { PIDHASH = 1021 };
|
||||
|
||||
#define T ((void*)-1)
|
||||
static Uproc *alluproc[PIDHASH];
|
||||
static int allupid[PIDHASH];
|
||||
static Lock uproclock;
|
||||
|
||||
void
|
||||
_clearuproc(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
/* called right after fork - no locking needed */
|
||||
for(i=0; i<PIDHASH; i++)
|
||||
if(alluproc[i] != T && alluproc[i] != 0)
|
||||
free(alluproc[i]);
|
||||
memset(alluproc, 0, sizeof alluproc);
|
||||
memset(allupid, 0, sizeof allupid);
|
||||
}
|
||||
|
||||
Uproc*
|
||||
_p9uproc(int inhandler)
|
||||
{
|
||||
int i, h, pid;
|
||||
Uproc *up;
|
||||
|
||||
/* for now, assume getpid is fast or cached */
|
||||
pid = getpid();
|
||||
|
||||
/*
|
||||
* this part - the lookup - needs to run without locks
|
||||
* so that it can safely be called from within the notify handler.
|
||||
* notify calls _p9uproc, and fork and rfork call _p9uproc
|
||||
* in both parent and child, so if we're in a signal handler,
|
||||
* we should find something in the table.
|
||||
*/
|
||||
h = pid%PIDHASH;
|
||||
for(i=0; i<PIDHASH; i++){
|
||||
up = alluproc[h];
|
||||
if(up == nil)
|
||||
break;
|
||||
if(allupid[h] == pid)
|
||||
return up;
|
||||
if(++h == PIDHASH)
|
||||
h = 0;
|
||||
}
|
||||
|
||||
if(inhandler){
|
||||
fprint(2, "%s: did not find uproc for pid %d in signal handler\n", argv0, pid);
|
||||
abort();
|
||||
}
|
||||
|
||||
/* need to allocate */
|
||||
while((up = mallocz(sizeof(Uproc), 1)) == nil)
|
||||
sleep(1000);
|
||||
|
||||
/* fprint(2, "alloc uproc for pid %d\n", pid); */
|
||||
up->pid = pid;
|
||||
lock(&uproclock);
|
||||
h = pid%PIDHASH;
|
||||
for(i=0; i<PIDHASH; i++){
|
||||
if(alluproc[h]==T || alluproc[h]==nil){
|
||||
alluproc[h] = up;
|
||||
allupid[h] = pid;
|
||||
unlock(&uproclock);
|
||||
return up;
|
||||
}
|
||||
if(++h == PIDHASH)
|
||||
h = 0;
|
||||
}
|
||||
unlock(&uproclock);
|
||||
|
||||
/* out of pids! */
|
||||
sysfatal("too many processes in uproc table");
|
||||
return nil;
|
||||
}
|
||||
|
||||
void
|
||||
_p9uprocdie(void)
|
||||
{
|
||||
Uproc *up;
|
||||
int pid, i, h;
|
||||
|
||||
pid = getpid();
|
||||
/* fprint(2, "reap uproc for pid %d\n", pid); */
|
||||
h = pid%PIDHASH;
|
||||
for(i=0; i<PIDHASH; i++){
|
||||
up = alluproc[h];
|
||||
if(up == nil)
|
||||
break;
|
||||
if(up == T)
|
||||
continue;
|
||||
if(allupid[h] == pid){
|
||||
up = alluproc[h];
|
||||
alluproc[h] = T;
|
||||
free(up);
|
||||
allupid[h] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
#include <u.h>
|
||||
#include <signal.h>
|
||||
#include <libc.h>
|
||||
#include "9proc.h"
|
||||
#undef fork
|
||||
|
|
@ -7,9 +8,15 @@ int
|
|||
p9fork(void)
|
||||
{
|
||||
int pid;
|
||||
sigset_t all, old;
|
||||
|
||||
sigfillset(&all);
|
||||
sigprocmask(SIG_SETMASK, &all, &old);
|
||||
pid = fork();
|
||||
_clearuproc();
|
||||
_p9uproc(0);
|
||||
if(pid == 0){
|
||||
_clearuproc();
|
||||
_p9uproc(0);
|
||||
}
|
||||
sigprocmask(SIG_SETMASK, &old, nil);
|
||||
return pid;
|
||||
}
|
||||
|
|
|
|||
1
src/lib9/lock-Darwin.c
Normal file
1
src/lib9/lock-Darwin.c
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include "lock-pthread.c"
|
||||
1
src/lib9/lock-FreeBSD.c
Normal file
1
src/lib9/lock-FreeBSD.c
Normal file
|
|
@ -0,0 +1 @@
|
|||
#include "lock-tas.c"
|
||||
5
src/lib9/lock-Linux.c
Normal file
5
src/lib9/lock-Linux.c
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
#ifdef __Linux26__
|
||||
#include "lock-pthread.c"
|
||||
#else
|
||||
#include "lock-tas.c"
|
||||
#endif
|
||||
54
src/lib9/lock-pthread.c
Normal file
54
src/lib9/lock-pthread.c
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
#include <u.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <sched.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();
|
||||
}
|
||||
57
src/lib9/lock-tas.c
Normal file
57
src/lib9/lock-tas.c
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
#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);
|
||||
}
|
||||
|
|
@ -67,7 +67,7 @@ LIB9OFILES=\
|
|||
_exits.$O\
|
||||
_p9dialparse.$O\
|
||||
_p9dir.$O\
|
||||
_p9proc.$O\
|
||||
_p9proc-$SYSNAME.$O\
|
||||
announce.$O\
|
||||
argv0.$O\
|
||||
atexit.$O\
|
||||
|
|
@ -111,7 +111,7 @@ LIB9OFILES=\
|
|||
jmp.$O\
|
||||
lrand.$O\
|
||||
lnrand.$O\
|
||||
lock.$O\
|
||||
lock-$SYSNAME.$O\
|
||||
main.$O\
|
||||
malloc.$O\
|
||||
malloctag.$O\
|
||||
|
|
@ -141,6 +141,7 @@ LIB9OFILES=\
|
|||
strecpy.$O\
|
||||
sysfatal.$O\
|
||||
sysname.$O\
|
||||
tas-$OBJTYPE.$O\
|
||||
time.$O\
|
||||
tokenize.$O\
|
||||
truerand.$O\
|
||||
|
|
|
|||
|
|
@ -18,6 +18,8 @@ enum
|
|||
|
||||
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
|
||||
|
|
@ -73,7 +75,7 @@ qlock(QLock *q)
|
|||
q->tail = mp;
|
||||
mp->state = Queuing;
|
||||
mp->rend.l = &q->lock;
|
||||
_procsleep(&mp->rend);
|
||||
procsleep(&mp->rend);
|
||||
unlock(&q->lock);
|
||||
assert(mp->state == Waking);
|
||||
unlock(&mp->inuse);
|
||||
|
|
@ -92,7 +94,7 @@ qunlock(QLock *q)
|
|||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
p->state = Waking;
|
||||
_procwakeup(&p->rend);
|
||||
procwakeup(&p->rend);
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
|
@ -137,7 +139,7 @@ rlock(RWLock *q)
|
|||
mp->next = nil;
|
||||
mp->state = QueuingR;
|
||||
mp->rend.l = &q->lock;
|
||||
_procsleep(&mp->rend);
|
||||
procsleep(&mp->rend);
|
||||
unlock(&q->lock);
|
||||
assert(mp->state == Waking);
|
||||
unlock(&mp->inuse);
|
||||
|
|
@ -181,7 +183,7 @@ runlock(RWLock *q)
|
|||
|
||||
/* wakeup waiter */
|
||||
p->state = Waking;
|
||||
_procwakeup(&p->rend);
|
||||
procwakeup(&p->rend);
|
||||
unlock(&q->lock);
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +213,7 @@ wlock(RWLock *q)
|
|||
|
||||
/* wait in kernel */
|
||||
mp->rend.l = &q->lock;
|
||||
_procsleep(&mp->rend);
|
||||
procsleep(&mp->rend);
|
||||
unlock(&q->lock);
|
||||
assert(mp->state == Waking);
|
||||
unlock(&mp->inuse);
|
||||
|
|
@ -253,7 +255,7 @@ wunlock(RWLock *q)
|
|||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
p->state = Waking;
|
||||
_procwakeup(&p->rend);
|
||||
procwakeup(&p->rend);
|
||||
unlock(&q->lock);
|
||||
return;
|
||||
}
|
||||
|
|
@ -269,7 +271,7 @@ wunlock(RWLock *q)
|
|||
q->head = p->next;
|
||||
q->readers++;
|
||||
p->state = Waking;
|
||||
_procwakeup(&p->rend);
|
||||
procwakeup(&p->rend);
|
||||
}
|
||||
if(q->head == nil)
|
||||
q->tail = nil;
|
||||
|
|
@ -310,20 +312,20 @@ rsleep(Rendez *r)
|
|||
if(r->l->head == nil)
|
||||
r->l->tail = nil;
|
||||
t->state = Waking;
|
||||
_procwakeup(&t->rend);
|
||||
procwakeup(&t->rend);
|
||||
}else
|
||||
r->l->locked = 0;
|
||||
|
||||
/* wait for a wakeup */
|
||||
me->rend.l = &r->l->lock;
|
||||
_procsleep(&me->rend);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ _procsleep(_Procrend *r)
|
|||
*/
|
||||
ignusr1(1);
|
||||
assert(r->asleep == 0);
|
||||
lock(r->l);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue