commit cf4f3eafc6016ccdb57773215dcdd5ebac95c07d from: rsc date: Mon Nov 08 16:03:42 2004 UTC extra files commit - 195645536743aeb99eb336726823c38716cec02d commit + cf4f3eafc6016ccdb57773215dcdd5ebac95c07d blob - /dev/null blob + 4382be402347886592df25c8aafa044ed52a2f42 (mode 644) --- /dev/null +++ src/libthread/execproc.ch @@ -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) +{ +} + blob - /dev/null blob + e2580ac77e38f8460b3bc68cbed606a149076935 (mode 644) --- /dev/null +++ src/libthread/exit-getpid.ch @@ -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); +} blob - /dev/null blob + ccf81866cec7b4ab9ef08e695cc7a19b39c53331 (mode 644) --- /dev/null +++ src/libthread/procstack.ch @@ -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; +} + + blob - /dev/null blob + d51543f991482d954b167ec681c8ac0a24264a38 (mode 644) --- /dev/null +++ src/libthread/proctab.ch @@ -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; iprocid == 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; +}