shithub: riscv

Download patch

ref: 07608c768faadfe960872d492d960be3112b7999
parent: 24bd67f990fde5f25783293f57f651c93ce19125
author: cinap_lenrek <cinap_lenrek@felloff.net>
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