extra files
This commit is contained in:
parent
1956455367
commit
cf4f3eafc6
4 changed files with 380 additions and 0 deletions
183
src/libthread/execproc.ch
Normal file
183
src/libthread/execproc.ch
Normal 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)
|
||||
{
|
||||
}
|
||||
|
||||
25
src/libthread/exit-getpid.ch
Normal file
25
src/libthread/exit-getpid.ch
Normal 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);
|
||||
}
|
||||
75
src/libthread/procstack.ch
Normal file
75
src/libthread/procstack.ch
Normal 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
97
src/libthread/proctab.ch
Normal 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue