No more malloc or lock inside signal handlers.

This commit is contained in:
rsc 2004-04-21 04:48:25 +00:00
parent ac0e2db600
commit 175b8a534a
6 changed files with 78 additions and 55 deletions

View file

@ -2,15 +2,12 @@ enum
{ {
NPRIV = 16, NPRIV = 16,
RENDHASH = 33, RENDHASH = 33,
PIDHASH = 33,
}; };
typedef struct Uproc Uproc; typedef struct Uproc Uproc;
struct Uproc struct Uproc
{ {
Uproc *next;
int pid; int pid;
int pipe[2];
int state; int state;
void *priv[NPRIV]; void *priv[NPRIV];
ulong rendval; ulong rendval;
@ -19,5 +16,5 @@ struct Uproc
p9jmp_buf notejb; p9jmp_buf notejb;
}; };
extern Uproc *_p9uproc(void); extern Uproc *_p9uproc(int);
extern void _p9uprocdie(void); extern void _p9uprocdie(void);

View file

@ -1,73 +1,95 @@
/*
* 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 <u.h>
#include <libc.h> #include <libc.h>
#include "9proc.h" #include "9proc.h"
enum { PIDHASH = 1021 };
#define T ((void*)-1)
static Uproc *alluproc[PIDHASH];
static int allupid[PIDHASH];
static Lock uproclock; static Lock uproclock;
static Uproc *phash[PIDHASH];
Uproc* Uproc*
_p9uproc(void) _p9uproc(int inhandler)
{ {
/* for now, assume getpid is fast or cached */ int i, h, pid;
int pid;
Uproc *up; Uproc *up;
/* for now, assume getpid is fast or cached */
pid = getpid(); pid = getpid();
again:
if(0)print("find %d\n", pid); /*
lock(&uproclock); * this part - the lookup - needs to run without locks
for(up=phash[pid%PIDHASH]; up; up=up->next){ * so that it can safely be called from within the notify handler.
if(up->pid == pid){ * notify calls _p9uproc, and fork and rfork call _p9uproc
if(0)print("found %d\n", pid); * in both parent and child, so if we're in a signal handler,
unlock(&uproclock); * 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; return up;
if(++h == PIDHASH)
h = 0;
} }
}
if(inhandler)
sysfatal("did not find uproc in signal handler");
/* need to allocate */
while((up = mallocz(sizeof(Uproc), 1)) == nil)
sleep(1000);
up = mallocz(sizeof(Uproc), 1); up = mallocz(sizeof(Uproc), 1);
if(up == nil){ lock(&uproclock);
if(0)print("again %d\n", pid); h = pid%PIDHASH;
unlock(&uproclock); for(i=0; i<PIDHASH; i++){
sleep(1000); if(alluproc[h]==T || alluproc[h]==nil){
goto again; alluproc[h] = up;
} allupid[h] = pid;
againpipe:
if(pipe(up->pipe) < 0){
if(0)print("againpipe %d\n", pid);
sleep(1000);
goto againpipe;
}
up->pid = pid;
up->next = phash[pid%PIDHASH];
phash[pid%PIDHASH] = up;
if(0)print("link %d\n", pid);
unlock(&uproclock);
return up; return up;
} }
if(++h == PIDHASH)
h = 0;
}
unlock(&uproclock);
/* out of pids! */
sysfatal("too many processes in uproc table");
return nil;
}
void void
_p9uprocdie(void) _p9uprocdie(void)
{ {
Uproc **l, *up; Uproc *up;
int pid; int pid, i, h;
pid = getpid(); pid = getpid();
if(0)print("die %d\n", pid); h = pid%PIDHASH;
lock(&uproclock); for(i=0; i<PIDHASH; i++){
for(l=&phash[pid%33]; *l; l=&(*l)->next){ up = alluproc[h];
if((*l)->pid == pid){ if(up == nil)
up = *l; break;
*l = up->next; if(up == T)
if(0)print("died %d\n", pid); continue;
unlock(&uproclock); if(allupid[h] == pid){
close(up->pipe[0]); up = alluproc[h];
close(up->pipe[1]); alluproc[h] = T;
free(up); free(up);
return; allupid[h] = 0;
} }
} }
if(0)print("not started %d\n", pid);
unlock(&uproclock);
} }

View file

@ -49,7 +49,7 @@ notifysigf(int sig)
char tmp[64]; char tmp[64];
Uproc *up; Uproc *up;
up = _p9uproc(); up = _p9uproc(1);
v = p9setjmp(up->notejb); v = p9setjmp(up->notejb);
if(v == 0 && notifyf) if(v == 0 && notifyf)
(*notifyf)(nil, _p9sigstr(sig, tmp)); (*notifyf)(nil, _p9sigstr(sig, tmp));
@ -68,6 +68,7 @@ notify(void (*f)(void*, char*))
int i; int i;
struct sigaction sa; struct sigaction sa;
_p9uproc(0);
memset(&sa, 0, sizeof sa); memset(&sa, 0, sizeof sa);
if(f == 0) if(f == 0)
sa.sa_handler = SIG_DFL; sa.sa_handler = SIG_DFL;
@ -90,7 +91,7 @@ noted(int v)
{ {
Uproc *up; Uproc *up;
up = _p9uproc(); up = _p9uproc(1);
p9longjmp(up->notejb, v==NCONT ? 2 : 1); p9longjmp(up->notejb, v==NCONT ? 2 : 1);
abort(); abort();
return 0; return 0;

View file

@ -26,7 +26,7 @@ privmem(int i)
{ {
Uproc *up; Uproc *up;
up = _p9uproc(); up = _p9uproc(0);
return &up->priv[i]; return &up->priv[i];
} }

View file

@ -12,7 +12,7 @@ rendezvous(ulong tag, ulong val)
ulong ret; ulong ret;
Uproc *t, *self, **l; Uproc *t, *self, **l;
self = _p9uproc(); self = _p9uproc(0);
lock(&rendlock); lock(&rendlock);
l = &rendhash[tag%RENDHASH]; l = &rendhash[tag%RENDHASH];
for(t=*l; t; l=&t->rendhash, t=*l){ for(t=*l; t; l=&t->rendhash, t=*l){

View file

@ -1,5 +1,7 @@
#define NOPLAN9DEFINES #include <u.h>
#include <lib9.h> #include <libc.h>
#include "9proc.h"
#undef rfork
int int
p9rfork(int flags) p9rfork(int flags)
@ -14,6 +16,7 @@ p9rfork(int flags)
return -1; return -1;
} }
pid = fork(); pid = fork();
_p9uproc(0);
if(pid != 0) if(pid != 0)
return pid; return pid;
} }