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;
|
int id;
|
||||||
|
|
||||||
p = _threadgetproc();
|
p = _threadgetproc();
|
||||||
assert(p->newproc == nil);
|
while(p->newproc)
|
||||||
|
_sched();
|
||||||
p->newproc = _newproc(f, arg, stacksize, nil, p->thread->grp, rforkflag);
|
p->newproc = _newproc(f, arg, stacksize, nil, p->thread->grp, rforkflag);
|
||||||
id = p->newproc->threads.head->id;
|
id = p->newproc->threads.head->id;
|
||||||
_sched();
|
_sched();
|
||||||
|
|
|
@ -45,8 +45,10 @@ procexec(Channel *pidc, char *prog, char *args[])
|
||||||
close(p->exec.fd[1]);
|
close(p->exec.fd[1]);
|
||||||
p->exec.fd[1] = n;
|
p->exec.fd[1] = n;
|
||||||
|
|
||||||
|
while(p->needexec || p->newproc)
|
||||||
|
_sched();
|
||||||
|
|
||||||
/* exec in parallel via the scheduler */
|
/* exec in parallel via the scheduler */
|
||||||
assert(p->needexec==0);
|
|
||||||
p->exec.prog = prog;
|
p->exec.prog = prog;
|
||||||
p->exec.args = args;
|
p->exec.args = args;
|
||||||
p->needexec = 1;
|
p->needexec = 1;
|
||||||
|
@ -61,6 +63,8 @@ procexec(Channel *pidc, char *prog, char *args[])
|
||||||
}
|
}
|
||||||
close(p->exec.fd[0]);
|
close(p->exec.fd[0]);
|
||||||
|
|
||||||
|
if(t->ret == -1)
|
||||||
|
goto Bad;
|
||||||
if(pidc)
|
if(pidc)
|
||||||
sendul(pidc, t->ret);
|
sendul(pidc, t->ret);
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include "threadimpl.h"
|
#include "threadimpl.h"
|
||||||
#include <tos.h>
|
|
||||||
|
|
||||||
char *_threadexitsallstatus;
|
char *_threadexitsallstatus;
|
||||||
Channel *_threadwaitchan;
|
Channel *_threadwaitchan;
|
||||||
|
@ -33,7 +32,7 @@ threadexitsall(char *exitstr)
|
||||||
exitstr = "";
|
exitstr = "";
|
||||||
_threadexitsallstatus = exitstr;
|
_threadexitsallstatus = exitstr;
|
||||||
_threaddebug(DBGSCHED, "_threadexitsallstatus set to %p", _threadexitsallstatus);
|
_threaddebug(DBGSCHED, "_threadexitsallstatus set to %p", _threadexitsallstatus);
|
||||||
mypid = _tos->pid; //getpid();
|
mypid = getpid();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* signal others.
|
* signal others.
|
||||||
|
@ -47,7 +46,7 @@ threadexitsall(char *exitstr)
|
||||||
lock(&_threadpq.lock);
|
lock(&_threadpq.lock);
|
||||||
npid = 0;
|
npid = 0;
|
||||||
for(p = _threadpq.head; p && npid < nelem(pid); p=p->next){
|
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;
|
pid[npid++] = p->pid;
|
||||||
p->threadint = 1;
|
p->threadint = 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include "threadimpl.h"
|
#include "threadimpl.h"
|
||||||
#include <tos.h>
|
|
||||||
|
|
||||||
int
|
int
|
||||||
threadid(void)
|
threadid(void)
|
||||||
|
|
|
@ -28,8 +28,6 @@ main(int argc, char **argv)
|
||||||
|
|
||||||
rfork(RFREND);
|
rfork(RFREND);
|
||||||
mainp = &p;
|
mainp = &p;
|
||||||
if(setjmp(_mainjmp))
|
|
||||||
_schedinit(p);
|
|
||||||
|
|
||||||
//_threaddebuglevel = (DBGSCHED|DBGCHAN|DBGREND)^~0;
|
//_threaddebuglevel = (DBGSCHED|DBGCHAN|DBGREND)^~0;
|
||||||
_systhreadinit();
|
_systhreadinit();
|
||||||
|
@ -45,6 +43,7 @@ main(int argc, char **argv)
|
||||||
a->argv = argv;
|
a->argv = argv;
|
||||||
|
|
||||||
p = _newproc(mainlauncher, a, mainstacksize, "threadmain", 0, 0);
|
p = _newproc(mainlauncher, a, mainstacksize, "threadmain", 0, 0);
|
||||||
|
setjmp(_mainjmp);
|
||||||
_schedinit(p);
|
_schedinit(p);
|
||||||
abort(); /* not reached */
|
abort(); /* not reached */
|
||||||
}
|
}
|
||||||
|
@ -117,18 +116,6 @@ void
|
||||||
_schedexit(Proc *p)
|
_schedexit(Proc *p)
|
||||||
{
|
{
|
||||||
char ex[ERRMAX];
|
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);
|
utfecpy(ex, ex+sizeof ex, p->exitstr);
|
||||||
free(p);
|
free(p);
|
||||||
|
|
|
@ -2,15 +2,9 @@
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
#include <thread.h>
|
#include <thread.h>
|
||||||
#include "threadimpl.h"
|
#include "threadimpl.h"
|
||||||
#include <tos.h>
|
|
||||||
|
|
||||||
static Thread *runthread(Proc*);
|
|
||||||
|
|
||||||
static char *_psstate[] = {
|
static char *_psstate[] = {
|
||||||
"Moribund",
|
|
||||||
"Dead",
|
"Dead",
|
||||||
"Exec",
|
|
||||||
"Fork",
|
|
||||||
"Running",
|
"Running",
|
||||||
"Ready",
|
"Ready",
|
||||||
"Rendezvous",
|
"Rendezvous",
|
||||||
|
@ -24,6 +18,23 @@ psstate(int s)
|
||||||
return _psstate[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
|
void
|
||||||
_schedinit(void *arg)
|
_schedinit(void *arg)
|
||||||
{
|
{
|
||||||
|
@ -31,8 +42,8 @@ _schedinit(void *arg)
|
||||||
Thread *t, **l;
|
Thread *t, **l;
|
||||||
|
|
||||||
p = arg;
|
p = arg;
|
||||||
|
p->pid = getpid();
|
||||||
_threadsetproc(p);
|
_threadsetproc(p);
|
||||||
p->pid = _tos->pid; //getpid();
|
|
||||||
while(setjmp(p->sched))
|
while(setjmp(p->sched))
|
||||||
;
|
;
|
||||||
_threaddebug(DBGSCHED, "top of schedinit, _threadexitsallstatus=%p", _threadexitsallstatus);
|
_threaddebug(DBGSCHED, "top of schedinit, _threadexitsallstatus=%p", _threadexitsallstatus);
|
||||||
|
@ -67,8 +78,15 @@ _schedinit(void *arg)
|
||||||
p->needexec = 0;
|
p->needexec = 0;
|
||||||
}
|
}
|
||||||
if(p->newproc){
|
if(p->newproc){
|
||||||
t->ret = _schedfork(p->newproc);
|
Thread *x = p->newproc->threads.head;
|
||||||
p->newproc = nil;
|
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;
|
t->state = t->nextstate;
|
||||||
if(t->state == Ready)
|
if(t->state == Ready)
|
||||||
|
@ -90,44 +108,12 @@ needstack(int n)
|
||||||
|
|
||||||
if((uchar*)&x - n < (uchar*)t->stk){
|
if((uchar*)&x - n < (uchar*)t->stk){
|
||||||
fprint(2, "%s %lud: &x=%p n=%d t->stk=%p\n",
|
fprint(2, "%s %lud: &x=%p n=%d t->stk=%p\n",
|
||||||
argv0, _tos->pid, &x, n, t->stk);
|
argv0, (ulong)p->pid, &x, n, t->stk);
|
||||||
fprint(2, "%s %lud: stack overflow\n", argv0, _tos->pid);
|
fprint(2, "%s %lud: stack overflow\n", argv0, (ulong)p->pid);
|
||||||
abort();
|
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*
|
static Thread*
|
||||||
runthread(Proc *p)
|
runthread(Proc *p)
|
||||||
{
|
{
|
||||||
|
@ -154,6 +140,39 @@ runthread(Proc *p)
|
||||||
return t;
|
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
|
void
|
||||||
_threadready(Thread *t)
|
_threadready(Thread *t)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue