libthread: deal with _schedfork() and _schedexec() returning -1
The current behaviour of the kernel to deadlock itself instead of returning an error on fork. This might change in the future, so prepare libthread to handle this case. For _schedfork(), we'r going to just retry forking on every switch, while for _schedexec(), the exec will fail and send ~0 down the pid channel.
This commit is contained in:
parent
24bd67f990
commit
07608c768f
6 changed files with 72 additions and 63 deletions
|
@ -97,7 +97,8 @@ procrfork(void (*f)(void *), void *arg, uint stacksize, int rforkflag)
|
|||
int id;
|
||||
|
||||
p = _threadgetproc();
|
||||
assert(p->newproc == nil);
|
||||
while(p->newproc)
|
||||
_sched();
|
||||
p->newproc = _newproc(f, arg, stacksize, nil, p->thread->grp, rforkflag);
|
||||
id = p->newproc->threads.head->id;
|
||||
_sched();
|
||||
|
|
|
@ -45,8 +45,10 @@ procexec(Channel *pidc, char *prog, char *args[])
|
|||
close(p->exec.fd[1]);
|
||||
p->exec.fd[1] = n;
|
||||
|
||||
while(p->needexec || p->newproc)
|
||||
_sched();
|
||||
|
||||
/* exec in parallel via the scheduler */
|
||||
assert(p->needexec==0);
|
||||
p->exec.prog = prog;
|
||||
p->exec.args = args;
|
||||
p->needexec = 1;
|
||||
|
@ -61,6 +63,8 @@ procexec(Channel *pidc, char *prog, char *args[])
|
|||
}
|
||||
close(p->exec.fd[0]);
|
||||
|
||||
if(t->ret == -1)
|
||||
goto Bad;
|
||||
if(pidc)
|
||||
sendul(pidc, t->ret);
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "threadimpl.h"
|
||||
#include <tos.h>
|
||||
|
||||
char *_threadexitsallstatus;
|
||||
Channel *_threadwaitchan;
|
||||
|
@ -33,7 +32,7 @@ threadexitsall(char *exitstr)
|
|||
exitstr = "";
|
||||
_threadexitsallstatus = exitstr;
|
||||
_threaddebug(DBGSCHED, "_threadexitsallstatus set to %p", _threadexitsallstatus);
|
||||
mypid = _tos->pid; //getpid();
|
||||
mypid = getpid();
|
||||
|
||||
/*
|
||||
* signal others.
|
||||
|
@ -47,7 +46,7 @@ threadexitsall(char *exitstr)
|
|||
lock(&_threadpq.lock);
|
||||
npid = 0;
|
||||
for(p = _threadpq.head; p && npid < nelem(pid); p=p->next){
|
||||
if(p->threadint == 0 && p->pid != mypid){
|
||||
if(p->threadint == 0 && p->pid != mypid && p->pid != -1){
|
||||
pid[npid++] = p->pid;
|
||||
p->threadint = 1;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "threadimpl.h"
|
||||
#include <tos.h>
|
||||
|
||||
int
|
||||
threadid(void)
|
||||
|
|
|
@ -28,8 +28,6 @@ main(int argc, char **argv)
|
|||
|
||||
rfork(RFREND);
|
||||
mainp = &p;
|
||||
if(setjmp(_mainjmp))
|
||||
_schedinit(p);
|
||||
|
||||
//_threaddebuglevel = (DBGSCHED|DBGCHAN|DBGREND)^~0;
|
||||
_systhreadinit();
|
||||
|
@ -45,6 +43,7 @@ main(int argc, char **argv)
|
|||
a->argv = argv;
|
||||
|
||||
p = _newproc(mainlauncher, a, mainstacksize, "threadmain", 0, 0);
|
||||
setjmp(_mainjmp);
|
||||
_schedinit(p);
|
||||
abort(); /* not reached */
|
||||
}
|
||||
|
@ -117,18 +116,6 @@ void
|
|||
_schedexit(Proc *p)
|
||||
{
|
||||
char ex[ERRMAX];
|
||||
Proc **l;
|
||||
|
||||
lock(&_threadpq.lock);
|
||||
for(l=&_threadpq.head; *l; l=&(*l)->next){
|
||||
if(*l == p){
|
||||
*l = p->next;
|
||||
if(*l == nil)
|
||||
_threadpq.tail = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
unlock(&_threadpq.lock);
|
||||
|
||||
utfecpy(ex, ex+sizeof ex, p->exitstr);
|
||||
free(p);
|
||||
|
|
|
@ -2,15 +2,9 @@
|
|||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include "threadimpl.h"
|
||||
#include <tos.h>
|
||||
|
||||
static Thread *runthread(Proc*);
|
||||
|
||||
static char *_psstate[] = {
|
||||
"Moribund",
|
||||
"Dead",
|
||||
"Exec",
|
||||
"Fork",
|
||||
"Running",
|
||||
"Ready",
|
||||
"Rendezvous",
|
||||
|
@ -24,6 +18,23 @@ psstate(int s)
|
|||
return _psstate[s];
|
||||
}
|
||||
|
||||
static void
|
||||
unlinkproc(Proc *p)
|
||||
{
|
||||
Proc **l;
|
||||
|
||||
lock(&_threadpq.lock);
|
||||
for(l=&_threadpq.head; *l; l=&(*l)->next){
|
||||
if(*l == p){
|
||||
*l = p->next;
|
||||
if(*l == nil)
|
||||
_threadpq.tail = l;
|
||||
break;
|
||||
}
|
||||
}
|
||||
unlock(&_threadpq.lock);
|
||||
}
|
||||
|
||||
void
|
||||
_schedinit(void *arg)
|
||||
{
|
||||
|
@ -31,8 +42,8 @@ _schedinit(void *arg)
|
|||
Thread *t, **l;
|
||||
|
||||
p = arg;
|
||||
p->pid = getpid();
|
||||
_threadsetproc(p);
|
||||
p->pid = _tos->pid; //getpid();
|
||||
while(setjmp(p->sched))
|
||||
;
|
||||
_threaddebug(DBGSCHED, "top of schedinit, _threadexitsallstatus=%p", _threadexitsallstatus);
|
||||
|
@ -67,8 +78,15 @@ _schedinit(void *arg)
|
|||
p->needexec = 0;
|
||||
}
|
||||
if(p->newproc){
|
||||
t->ret = _schedfork(p->newproc);
|
||||
p->newproc = nil;
|
||||
Thread *x = p->newproc->threads.head;
|
||||
if(x->moribund){
|
||||
x->proc = p;
|
||||
_threadready(x);
|
||||
unlinkproc(p->newproc);
|
||||
free(p->newproc);
|
||||
p->newproc = nil;
|
||||
} else if(_schedfork(p->newproc) != -1)
|
||||
p->newproc = nil;
|
||||
}
|
||||
t->state = t->nextstate;
|
||||
if(t->state == Ready)
|
||||
|
@ -90,44 +108,12 @@ needstack(int n)
|
|||
|
||||
if((uchar*)&x - n < (uchar*)t->stk){
|
||||
fprint(2, "%s %lud: &x=%p n=%d t->stk=%p\n",
|
||||
argv0, _tos->pid, &x, n, t->stk);
|
||||
fprint(2, "%s %lud: stack overflow\n", argv0, _tos->pid);
|
||||
argv0, (ulong)p->pid, &x, n, t->stk);
|
||||
fprint(2, "%s %lud: stack overflow\n", argv0, (ulong)p->pid);
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_sched(void)
|
||||
{
|
||||
Proc *p;
|
||||
Thread *t;
|
||||
|
||||
Resched:
|
||||
p = _threadgetproc();
|
||||
if((t = p->thread) != nil){
|
||||
needstack(128);
|
||||
_threaddebug(DBGSCHED, "pausing, state=%s", psstate(t->state));
|
||||
if(setjmp(t->sched)==0)
|
||||
longjmp(p->sched, 1);
|
||||
return;
|
||||
}else{
|
||||
t = runthread(p);
|
||||
if(t == nil){
|
||||
_threaddebug(DBGSCHED, "all threads gone; exiting");
|
||||
_schedexit(p);
|
||||
}
|
||||
_threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id);
|
||||
p->thread = t;
|
||||
if(t->moribund){
|
||||
_threaddebug(DBGSCHED, "%d.%d marked to die");
|
||||
goto Resched;
|
||||
}
|
||||
t->state = Running;
|
||||
t->nextstate = Ready;
|
||||
longjmp(t->sched, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static Thread*
|
||||
runthread(Proc *p)
|
||||
{
|
||||
|
@ -154,6 +140,39 @@ runthread(Proc *p)
|
|||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
_sched(void)
|
||||
{
|
||||
Proc *p;
|
||||
Thread *t;
|
||||
|
||||
Resched:
|
||||
p = _threadgetproc();
|
||||
if((t = p->thread) != nil){
|
||||
needstack(128);
|
||||
_threaddebug(DBGSCHED, "pausing, state=%s", psstate(t->state));
|
||||
if(setjmp(t->sched)==0)
|
||||
longjmp(p->sched, 1);
|
||||
return;
|
||||
}else{
|
||||
t = runthread(p);
|
||||
if(t == nil){
|
||||
_threaddebug(DBGSCHED, "all threads gone; exiting");
|
||||
unlinkproc(p);
|
||||
_schedexit(p); /* frees proc */
|
||||
}
|
||||
_threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id);
|
||||
p->thread = t;
|
||||
if(t->moribund){
|
||||
_threaddebug(DBGSCHED, "%d.%d marked to die");
|
||||
goto Resched;
|
||||
}
|
||||
t->state = Running;
|
||||
t->nextstate = Ready;
|
||||
longjmp(t->sched, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_threadready(Thread *t)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue