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:
cinap_lenrek 2021-10-12 00:49:12 +00:00
parent 24bd67f990
commit 07608c768f
6 changed files with 72 additions and 63 deletions

View file

@ -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();

View file

@ -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);

View file

@ -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;
}

View file

@ -2,7 +2,6 @@
#include <libc.h>
#include <thread.h>
#include "threadimpl.h"
#include <tos.h>
int
threadid(void)

View file

@ -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);

View file

@ -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)
{