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