extra files

This commit is contained in:
rsc 2004-11-08 16:03:42 +00:00
parent 1956455367
commit cf4f3eafc6
4 changed files with 380 additions and 0 deletions

183
src/libthread/execproc.ch Normal file
View file

@ -0,0 +1,183 @@
/*
* Set up a dedicated proc to handle calls to exec.
* The proc also waits for child messages.
* This way, each proc scheduler need not worry
* about calling wait in its main loop.
*
* To be included from other files (e.g., Linux-clone.c).
*/
typedef struct Xarg Xarg;
struct Xarg
{
Channel *pidc;
int fd[3];
char *prog;
char **args;
int freeargs;
Channel *ret;
int errn;
char errstr[ERRMAX];
};
static Proc *_threadexecproc;
static Channel *_threadexecchan;
static Lock threadexeclock;
/*
* Called to poll for any kids of this pthread.
* We have a separate proc responsible for exec,
* so this is a no-op.
*/
void
_threadwaitkids(Proc *p)
{
}
#define WAITSIG SIGCHLD
/*
* Separate process to wait for child messages.
* Also runs signal handlers and runs all execs.
*/
static void
nop(int sig)
{
USED(sig);
}
static void
_threadwaitproc(void *v)
{
Channel *c;
Waitmsg *w;
sigset_t mask;
int ret, nkids;
Xarg *xa;
nkids = 0;
sigemptyset(&mask);
siginterrupt(WAITSIG, 1);
signal(WAITSIG, nop);
sigaddset(&mask, WAITSIG);
sigprocmask(SIG_BLOCK, &mask, nil);
USED(v);
for(;;){
while((nkids > 0 ? nbrecv : recv)(_threadexecchan, &xa) == 1){
ret = _threadexec(xa->pidc, xa->fd, xa->prog, xa->args, xa->freeargs);
if(ret > 0)
nkids++;
else{
rerrstr(xa->errstr, sizeof xa->errstr);
xa->errn = errno;
}
sendul(xa->ret, ret);
}
if(nkids > 0){
sigprocmask(SIG_UNBLOCK, &mask, nil);
w = wait();
sigprocmask(SIG_BLOCK, &mask, nil);
if(w == nil && errno == ECHILD){
fprint(2, "wait returned ECHILD but nkids=%d; reset\n", nkids);
nkids = 0;
}
if(w){
nkids--;
if((c = _threadwaitchan) != nil)
sendp(c, w);
else
free(w);
}
}
}
}
static void _kickexecproc(void);
int
_callthreadexec(Channel *pidc, int fd[3], char *prog, char *args[], int freeargs)
{
int ret;
Xarg xa;
if(_threadexecchan == nil){
lock(&threadexeclock);
if(_threadexecchan == nil)
_threadfirstexec();
unlock(&threadexeclock);
}
xa.pidc = pidc;
xa.fd[0] = fd[0];
xa.fd[1] = fd[1];
xa.fd[2] = fd[2];
xa.prog = prog;
xa.args = args;
xa.freeargs = freeargs;
xa.ret = chancreate(sizeof(ulong), 1);
sendp(_threadexecchan, &xa);
_kickexecproc();
ret = recvul(xa.ret);
if(ret < 0){
werrstr("%s", xa.errstr);
errno = xa.errn;
}
chanfree(xa.ret);
return ret;
}
/*
* Called before the first exec.
*/
void
_threadfirstexec(void)
{
int id;
Proc *p;
_threadexecchan = chancreate(sizeof(Xarg*), 1);
id = proccreate(_threadwaitproc, nil, 32*1024);
/*
* Sleazy: decrement threadnprocs so that
* the existence of the _threadwaitproc proc
* doesn't keep us from exiting.
*/
lock(&_threadpq.lock);
--_threadnprocs;
for(p=_threadpq.head; p; p=p->next)
if(p->threads.head && p->threads.head->id == id)
break;
if(p == nil)
sysfatal("cannot find exec proc");
unlock(&_threadpq.lock);
_threadexecproc = p;
}
/*
* Called after the thread t has been rescheduled.
* Kick the exec proc in case it is in the middle of a wait.
*/
static void
_kickexecproc(void)
{
kill(_threadexecproc->pid, WAITSIG);
}
/*
* Called before exec.
*/
void
_threadbeforeexec(void)
{
}
/*
* Called after exec.
*/
void
_threadafterexec(void)
{
}

View file

@ -0,0 +1,25 @@
/*
* Implement threadexitsall by sending a signal to every proc.
*
* To be included from another C file (e.g., Linux-clone.c).
*/
void
_threadexitallproc(char *exitstr)
{
Proc *p;
int mypid;
mypid = getpid();
lock(&_threadpq.lock);
for(p=_threadpq.head; p; p=p->next)
if(p->pid > 1 && p->pid != mypid)
kill(p->pid, SIGUSR2);
exits(exitstr);
}
void
_threadexitproc(char *exitstr)
{
_exits(exitstr);
}

View file

@ -0,0 +1,75 @@
static 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 && procexited(p->pid)){
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;
}

97
src/libthread/proctab.ch Normal file
View file

@ -0,0 +1,97 @@
/*
* Proc structure hash table indexed by proctabid() (usually getpid()).
* No lock is necessary for lookups (important when called from signal
* handlers).
*
* To be included from other files (e.g., Linux-clone.c).
*/
#define T ((void*)-1)
enum
{
PTABHASH = 1031,
};
static Lock ptablock;
static Proc *proctab[PTABHASH];
static Proc *theproc;
static int multi;
void
_threadmultiproc(void)
{
if(multi == 0){
multi = 1;
_threadsetproc(theproc);
}
}
void
_threadsetproc(Proc *p)
{
int i, h;
Proc **t;
if(!multi){
theproc = p;
return;
}
lock(&ptablock);
p->procid = procid();
h = p->procid%PTABHASH;
for(i=0; i<PTABHASH; i++){
t = &proctab[(h+i)%PTABHASH];
if(*t==nil || *t==T){
*t = p;
break;
}
}
unlock(&ptablock);
if(i == PTABHASH)
sysfatal("too many procs - proctab is full");
}
static Proc**
_threadfindproc(int id)
{
int i, h;
Proc **t;
if(!multi)
return &theproc;
h = id%PTABHASH;
for(i=0; i<PTABHASH; i++){
t = &proctab[(h+i)%PTABHASH];
if(*t != nil && *t != T && (*t)->procid == id){
unlock(&ptablock);
return t;
}
}
return nil;
}
Proc*
_threadgetproc(void)
{
Proc **t;
t = _threadfindproc(procid());
if(t == nil)
return nil;
return *t;
}
Proc*
_threaddelproc(void)
{
Proc **t, *p;
t = _threadfindproc(procid());
if(t == nil)
return nil;
p = *t;
*t = T;
return p;
}