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