xref: /plan9/sys/src/libthread/sched.c (revision d1be6b086622eecc0da76db1fbd64349a5e85293)
19a747e4fSDavid du Colombier #include <u.h>
29a747e4fSDavid du Colombier #include <libc.h>
39a747e4fSDavid du Colombier #include <thread.h>
49a747e4fSDavid du Colombier #include "threadimpl.h"
5*d1be6b08SDavid du Colombier #include <tos.h>
69a747e4fSDavid du Colombier 
79a747e4fSDavid du Colombier static Thread	*runthread(Proc*);
89a747e4fSDavid du Colombier 
99a747e4fSDavid du Colombier static char *_psstate[] = {
109a747e4fSDavid du Colombier 	"Moribund",
119a747e4fSDavid du Colombier 	"Dead",
129a747e4fSDavid du Colombier 	"Exec",
139a747e4fSDavid du Colombier 	"Fork",
149a747e4fSDavid du Colombier 	"Running",
159a747e4fSDavid du Colombier 	"Ready",
169a747e4fSDavid du Colombier 	"Rendezvous",
179a747e4fSDavid du Colombier };
189a747e4fSDavid du Colombier 
193ff48bf5SDavid du Colombier static char*
psstate(int s)209a747e4fSDavid du Colombier psstate(int s)
219a747e4fSDavid du Colombier {
229a747e4fSDavid du Colombier 	if(s < 0 || s >= nelem(_psstate))
239a747e4fSDavid du Colombier 		return "unknown";
249a747e4fSDavid du Colombier 	return _psstate[s];
259a747e4fSDavid du Colombier }
269a747e4fSDavid du Colombier 
279a747e4fSDavid du Colombier void
_schedinit(void * arg)289a747e4fSDavid du Colombier _schedinit(void *arg)
299a747e4fSDavid du Colombier {
309a747e4fSDavid du Colombier 	Proc *p;
319a747e4fSDavid du Colombier 	Thread *t, **l;
329a747e4fSDavid du Colombier 
339a747e4fSDavid du Colombier 	p = arg;
349a747e4fSDavid du Colombier 	_threadsetproc(p);
35*d1be6b08SDavid du Colombier 	p->pid = _tos->pid; //getpid();
369a747e4fSDavid du Colombier 	while(setjmp(p->sched))
379a747e4fSDavid du Colombier 		;
389a747e4fSDavid du Colombier 	_threaddebug(DBGSCHED, "top of schedinit, _threadexitsallstatus=%p", _threadexitsallstatus);
399a747e4fSDavid du Colombier 	if(_threadexitsallstatus)
409a747e4fSDavid du Colombier 		exits(_threadexitsallstatus);
419a747e4fSDavid du Colombier 	lock(&p->lock);
429a747e4fSDavid du Colombier 	if((t=p->thread) != nil){
439a747e4fSDavid du Colombier 		p->thread = nil;
449a747e4fSDavid du Colombier 		if(t->moribund){
459a747e4fSDavid du Colombier 			t->state = Dead;
469a747e4fSDavid du Colombier 			for(l=&p->threads.head; *l; l=&(*l)->nextt)
479a747e4fSDavid du Colombier 				if(*l == t){
489a747e4fSDavid du Colombier 					*l = t->nextt;
499a747e4fSDavid du Colombier 					if(*l==nil)
509a747e4fSDavid du Colombier 						p->threads.tail = l;
519a747e4fSDavid du Colombier 					p->nthreads--;
529a747e4fSDavid du Colombier 					break;
539a747e4fSDavid du Colombier 				}
549a747e4fSDavid du Colombier 			unlock(&p->lock);
559a747e4fSDavid du Colombier 			if(t->inrendez){
569a747e4fSDavid du Colombier 				_threadflagrendez(t);
579a747e4fSDavid du Colombier 				_threadbreakrendez();
589a747e4fSDavid du Colombier 			}
599a747e4fSDavid du Colombier 			free(t->stk);
609a747e4fSDavid du Colombier 			free(t->cmdname);
619a747e4fSDavid du Colombier 			free(t);	/* XXX how do we know there are no references? */
629a747e4fSDavid du Colombier 			t = nil;
639a747e4fSDavid du Colombier 			_sched();
649a747e4fSDavid du Colombier 		}
659a747e4fSDavid du Colombier 		if(p->needexec){
669a747e4fSDavid du Colombier 			t->ret = _schedexec(&p->exec);
679a747e4fSDavid du Colombier 			p->needexec = 0;
689a747e4fSDavid du Colombier 		}
699a747e4fSDavid du Colombier 		if(p->newproc){
709a747e4fSDavid du Colombier 			t->ret = _schedfork(p->newproc);
719a747e4fSDavid du Colombier 			p->newproc = nil;
729a747e4fSDavid du Colombier 		}
739a747e4fSDavid du Colombier 		t->state = t->nextstate;
749a747e4fSDavid du Colombier 		if(t->state == Ready)
759a747e4fSDavid du Colombier 			_threadready(t);
769a747e4fSDavid du Colombier 	}
779a747e4fSDavid du Colombier 	unlock(&p->lock);
789a747e4fSDavid du Colombier 	_sched();
799a747e4fSDavid du Colombier }
809a747e4fSDavid du Colombier 
819a747e4fSDavid du Colombier void
needstack(int n)822cca75a1SDavid du Colombier needstack(int n)
832cca75a1SDavid du Colombier {
842cca75a1SDavid du Colombier 	int x;
852cca75a1SDavid du Colombier 	Proc *p;
862cca75a1SDavid du Colombier 	Thread *t;
872cca75a1SDavid du Colombier 
882cca75a1SDavid du Colombier 	p = _threadgetproc();
892cca75a1SDavid du Colombier 	t = p->thread;
902cca75a1SDavid du Colombier 
912cca75a1SDavid du Colombier 	if((uchar*)&x - n < (uchar*)t->stk){
92*d1be6b08SDavid du Colombier 		fprint(2, "%s %lud: &x=%p n=%d t->stk=%p\n",
93*d1be6b08SDavid du Colombier 			argv0, _tos->pid, &x, n, t->stk);
94*d1be6b08SDavid du Colombier 		fprint(2, "%s %lud: stack overflow\n", argv0, _tos->pid);
952cca75a1SDavid du Colombier 		abort();
962cca75a1SDavid du Colombier 	}
972cca75a1SDavid du Colombier }
982cca75a1SDavid du Colombier 
992cca75a1SDavid du Colombier void
_sched(void)1009a747e4fSDavid du Colombier _sched(void)
1019a747e4fSDavid du Colombier {
1029a747e4fSDavid du Colombier 	Proc *p;
1039a747e4fSDavid du Colombier 	Thread *t;
1049a747e4fSDavid du Colombier 
1059a747e4fSDavid du Colombier Resched:
1069a747e4fSDavid du Colombier 	p = _threadgetproc();
1079a747e4fSDavid du Colombier 	if((t = p->thread) != nil){
1082cca75a1SDavid du Colombier 		needstack(128);
1099a747e4fSDavid du Colombier 		_threaddebug(DBGSCHED, "pausing, state=%s", psstate(t->state));
1109a747e4fSDavid du Colombier 		if(setjmp(t->sched)==0)
1119a747e4fSDavid du Colombier 			longjmp(p->sched, 1);
1129a747e4fSDavid du Colombier 		return;
1139a747e4fSDavid du Colombier 	}else{
1149a747e4fSDavid du Colombier 		t = runthread(p);
1159a747e4fSDavid du Colombier 		if(t == nil){
1169a747e4fSDavid du Colombier 			_threaddebug(DBGSCHED, "all threads gone; exiting");
1179a747e4fSDavid du Colombier 			_schedexit(p);
1189a747e4fSDavid du Colombier 		}
1199a747e4fSDavid du Colombier 		_threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id);
1209a747e4fSDavid du Colombier 		p->thread = t;
1219a747e4fSDavid du Colombier 		if(t->moribund){
1229a747e4fSDavid du Colombier 			_threaddebug(DBGSCHED, "%d.%d marked to die");
1239a747e4fSDavid du Colombier 			goto Resched;
1249a747e4fSDavid du Colombier 		}
1259a747e4fSDavid du Colombier 		t->state = Running;
1269a747e4fSDavid du Colombier 		t->nextstate = Ready;
1279a747e4fSDavid du Colombier 		longjmp(t->sched, 1);
1289a747e4fSDavid du Colombier 	}
1299a747e4fSDavid du Colombier }
1309a747e4fSDavid du Colombier 
1319a747e4fSDavid du Colombier static Thread*
runthread(Proc * p)1329a747e4fSDavid du Colombier runthread(Proc *p)
1339a747e4fSDavid du Colombier {
1349a747e4fSDavid du Colombier 	Thread *t;
1359a747e4fSDavid du Colombier 	Tqueue *q;
1369a747e4fSDavid du Colombier 
1379a747e4fSDavid du Colombier 	if(p->nthreads==0)
1389a747e4fSDavid du Colombier 		return nil;
1399a747e4fSDavid du Colombier 	q = &p->ready;
1409a747e4fSDavid du Colombier 	lock(&p->readylock);
1419a747e4fSDavid du Colombier 	if(q->head == nil){
1429a747e4fSDavid du Colombier 		q->asleep = 1;
1439a747e4fSDavid du Colombier 		_threaddebug(DBGSCHED, "sleeping for more work");
1449a747e4fSDavid du Colombier 		unlock(&p->readylock);
14574f16c81SDavid du Colombier 		while(rendezvous(q, 0) == (void*)~0){
1469a747e4fSDavid du Colombier 			if(_threadexitsallstatus)
1479a747e4fSDavid du Colombier 				exits(_threadexitsallstatus);
1489a747e4fSDavid du Colombier 		}
1499a747e4fSDavid du Colombier 		/* lock picked up from _threadready */
1509a747e4fSDavid du Colombier 	}
1519a747e4fSDavid du Colombier 	t = q->head;
1529a747e4fSDavid du Colombier 	q->head = t->next;
1539a747e4fSDavid du Colombier 	unlock(&p->readylock);
1549a747e4fSDavid du Colombier 	return t;
1559a747e4fSDavid du Colombier }
1569a747e4fSDavid du Colombier 
1579a747e4fSDavid du Colombier void
_threadready(Thread * t)1589a747e4fSDavid du Colombier _threadready(Thread *t)
1599a747e4fSDavid du Colombier {
1609a747e4fSDavid du Colombier 	Tqueue *q;
1619a747e4fSDavid du Colombier 
1629a747e4fSDavid du Colombier 	assert(t->state == Ready);
1639a747e4fSDavid du Colombier 	_threaddebug(DBGSCHED, "readying %d.%d", t->proc->pid, t->id);
1649a747e4fSDavid du Colombier 	q = &t->proc->ready;
1659a747e4fSDavid du Colombier 	lock(&t->proc->readylock);
1669a747e4fSDavid du Colombier 	t->next = nil;
1679a747e4fSDavid du Colombier 	if(q->head==nil)
1689a747e4fSDavid du Colombier 		q->head = t;
1699a747e4fSDavid du Colombier 	else
1709a747e4fSDavid du Colombier 		*q->tail = t;
1719a747e4fSDavid du Colombier 	q->tail = &t->next;
1729a747e4fSDavid du Colombier 	if(q->asleep){
1739a747e4fSDavid du Colombier 		q->asleep = 0;
1749a747e4fSDavid du Colombier 		/* lock passes to runthread */
1759a747e4fSDavid du Colombier 		_threaddebug(DBGSCHED, "waking process %d", t->proc->pid);
17674f16c81SDavid du Colombier 		while(rendezvous(q, 0) == (void*)~0){
1779a747e4fSDavid du Colombier 			if(_threadexitsallstatus)
1789a747e4fSDavid du Colombier 				exits(_threadexitsallstatus);
1799a747e4fSDavid du Colombier 		}
1809a747e4fSDavid du Colombier 	}else
1819a747e4fSDavid du Colombier 		unlock(&t->proc->readylock);
1829a747e4fSDavid du Colombier }
1839a747e4fSDavid du Colombier 
1849a747e4fSDavid du Colombier void
yield(void)1859a747e4fSDavid du Colombier yield(void)
1869a747e4fSDavid du Colombier {
1879a747e4fSDavid du Colombier 	_sched();
1889a747e4fSDavid du Colombier }
1899a747e4fSDavid du Colombier 
190