ref: 07608c768faadfe960872d492d960be3112b7999
parent: 24bd67f990fde5f25783293f57f651c93ce19125
author: cinap_lenrek <[email protected]>
date: Mon Oct 11 20:49:12 EDT 2021
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.
--- a/sys/src/libthread/create.c
+++ b/sys/src/libthread/create.c
@@ -97,7 +97,8 @@
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();
--- a/sys/src/libthread/exec.c
+++ b/sys/src/libthread/exec.c
@@ -45,8 +45,10 @@
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 @@
}
close(p->exec.fd[0]);
+ if(t->ret == -1)
+ goto Bad;
if(pidc)
sendul(pidc, t->ret);
--- a/sys/src/libthread/exit.c
+++ b/sys/src/libthread/exit.c
@@ -2,7 +2,6 @@
#include <libc.h>
#include <thread.h>
#include "threadimpl.h"
-#include <tos.h>
char *_threadexitsallstatus;
Channel *_threadwaitchan;
@@ -33,7 +32,7 @@
exitstr = "";
_threadexitsallstatus = exitstr;
_threaddebug(DBGSCHED, "_threadexitsallstatus set to %p", _threadexitsallstatus);
- mypid = _tos->pid; //getpid();
+ mypid = getpid();
/*
* signal others.
@@ -47,7 +46,7 @@
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;
}
--- a/sys/src/libthread/id.c
+++ b/sys/src/libthread/id.c
@@ -2,7 +2,6 @@
#include <libc.h>
#include <thread.h>
#include "threadimpl.h"
-#include <tos.h>
int
threadid(void)
--- a/sys/src/libthread/main.c
+++ b/sys/src/libthread/main.c
@@ -28,8 +28,6 @@
rfork(RFREND);
mainp = &p;
- if(setjmp(_mainjmp))
- _schedinit(p);
//_threaddebuglevel = (DBGSCHED|DBGCHAN|DBGREND)^~0;
_systhreadinit();
@@ -45,6 +43,7 @@
a->argv = argv;
p = _newproc(mainlauncher, a, mainstacksize, "threadmain", 0, 0);
+ setjmp(_mainjmp);
_schedinit(p);
abort(); /* not reached */
}
@@ -117,18 +116,6 @@
_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);
--- a/sys/src/libthread/sched.c
+++ b/sys/src/libthread/sched.c
@@ -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 @@
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 @@
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 @@
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,12 +108,38 @@
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();
}
}
+static Thread*
+runthread(Proc *p)
+{
+ Thread *t;
+ Tqueue *q;
+
+ if(p->nthreads==0)
+ return nil;
+ q = &p->ready;
+ lock(&p->readylock);
+ if(q->head == nil){
+ q->asleep = 1;
+ _threaddebug(DBGSCHED, "sleeping for more work");
+ unlock(&p->readylock);
+ while(rendezvous(q, 0) == (void*)~0){
+ if(_threadexitsallstatus)
+ exits(_threadexitsallstatus);
+ }
+ /* lock picked up from _threadready */
+ }
+ t = q->head;
+ q->head = t->next;
+ unlock(&p->readylock);
+ return t;
+}
+
void
_sched(void)
{
@@ -114,7 +158,8 @@
t = runthread(p);
if(t == nil){
_threaddebug(DBGSCHED, "all threads gone; exiting");
- _schedexit(p);
+ unlinkproc(p);
+ _schedexit(p); /* frees proc */
}
_threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id);
p->thread = t;
@@ -126,32 +171,6 @@
t->nextstate = Ready;
longjmp(t->sched, 1);
}
-}
-
-static Thread*
-runthread(Proc *p)
-{
- Thread *t;
- Tqueue *q;
-
- if(p->nthreads==0)
- return nil;
- q = &p->ready;
- lock(&p->readylock);
- if(q->head == nil){
- q->asleep = 1;
- _threaddebug(DBGSCHED, "sleeping for more work");
- unlock(&p->readylock);
- while(rendezvous(q, 0) == (void*)~0){
- if(_threadexitsallstatus)
- exits(_threadexitsallstatus);
- }
- /* lock picked up from _threadready */
- }
- t = q->head;
- q->head = t->next;
- unlock(&p->readylock);
- return t;
}
void