xref: /plan9-contrib/sys/src/libthread/sched.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier #include <u.h>
2*9a747e4fSDavid du Colombier #include <libc.h>
3*9a747e4fSDavid du Colombier #include <thread.h>
4*9a747e4fSDavid du Colombier #include "threadimpl.h"
5*9a747e4fSDavid du Colombier 
6*9a747e4fSDavid du Colombier static Thread	*runthread(Proc*);
7*9a747e4fSDavid du Colombier 
8*9a747e4fSDavid du Colombier static char *_psstate[] = {
9*9a747e4fSDavid du Colombier 	"Moribund",
10*9a747e4fSDavid du Colombier 	"Dead",
11*9a747e4fSDavid du Colombier 	"Exec",
12*9a747e4fSDavid du Colombier 	"Fork",
13*9a747e4fSDavid du Colombier 	"Running",
14*9a747e4fSDavid du Colombier 	"Ready",
15*9a747e4fSDavid du Colombier 	"Rendezvous",
16*9a747e4fSDavid du Colombier };
17*9a747e4fSDavid du Colombier 
18*9a747e4fSDavid du Colombier char*
19*9a747e4fSDavid du Colombier psstate(int s)
20*9a747e4fSDavid du Colombier {
21*9a747e4fSDavid du Colombier 	if(s < 0 || s >= nelem(_psstate))
22*9a747e4fSDavid du Colombier 		return "unknown";
23*9a747e4fSDavid du Colombier 	return _psstate[s];
24*9a747e4fSDavid du Colombier }
25*9a747e4fSDavid du Colombier 
26*9a747e4fSDavid du Colombier void
27*9a747e4fSDavid du Colombier _schedinit(void *arg)
28*9a747e4fSDavid du Colombier {
29*9a747e4fSDavid du Colombier 	Proc *p;
30*9a747e4fSDavid du Colombier 	Thread *t, **l;
31*9a747e4fSDavid du Colombier 
32*9a747e4fSDavid du Colombier 	p = arg;
33*9a747e4fSDavid du Colombier 	_threadsetproc(p);
34*9a747e4fSDavid du Colombier 	p->pid = getpid();
35*9a747e4fSDavid du Colombier 	while(setjmp(p->sched))
36*9a747e4fSDavid du Colombier 		;
37*9a747e4fSDavid du Colombier 	_threaddebug(DBGSCHED, "top of schedinit, _threadexitsallstatus=%p", _threadexitsallstatus);
38*9a747e4fSDavid du Colombier 	if(_threadexitsallstatus)
39*9a747e4fSDavid du Colombier 		exits(_threadexitsallstatus);
40*9a747e4fSDavid du Colombier 	lock(&p->lock);
41*9a747e4fSDavid du Colombier 	if((t=p->thread) != nil){
42*9a747e4fSDavid du Colombier 		p->thread = nil;
43*9a747e4fSDavid du Colombier 		if(t->moribund){
44*9a747e4fSDavid du Colombier 			t->state = Dead;
45*9a747e4fSDavid du Colombier 			for(l=&p->threads.head; *l; l=&(*l)->nextt)
46*9a747e4fSDavid du Colombier 				if(*l == t){
47*9a747e4fSDavid du Colombier 					*l = t->nextt;
48*9a747e4fSDavid du Colombier 					if(*l==nil)
49*9a747e4fSDavid du Colombier 						p->threads.tail = l;
50*9a747e4fSDavid du Colombier 					p->nthreads--;
51*9a747e4fSDavid du Colombier 					break;
52*9a747e4fSDavid du Colombier 				}
53*9a747e4fSDavid du Colombier 			unlock(&p->lock);
54*9a747e4fSDavid du Colombier 			if(t->inrendez){
55*9a747e4fSDavid du Colombier 				_threadflagrendez(t);
56*9a747e4fSDavid du Colombier 				_threadbreakrendez();
57*9a747e4fSDavid du Colombier 			}
58*9a747e4fSDavid du Colombier 			free(t->stk);
59*9a747e4fSDavid du Colombier 			free(t->cmdname);
60*9a747e4fSDavid du Colombier 			free(t);	/* XXX how do we know there are no references? */
61*9a747e4fSDavid du Colombier 			t = nil;
62*9a747e4fSDavid du Colombier 			_sched();
63*9a747e4fSDavid du Colombier 		}
64*9a747e4fSDavid du Colombier 		if(p->needexec){
65*9a747e4fSDavid du Colombier 			t->ret = _schedexec(&p->exec);
66*9a747e4fSDavid du Colombier 			p->needexec = 0;
67*9a747e4fSDavid du Colombier 		}
68*9a747e4fSDavid du Colombier 		if(p->newproc){
69*9a747e4fSDavid du Colombier 			t->ret = _schedfork(p->newproc);
70*9a747e4fSDavid du Colombier 			p->newproc = nil;
71*9a747e4fSDavid du Colombier 		}
72*9a747e4fSDavid du Colombier 		t->state = t->nextstate;
73*9a747e4fSDavid du Colombier 		if(t->state == Ready)
74*9a747e4fSDavid du Colombier 			_threadready(t);
75*9a747e4fSDavid du Colombier 	}
76*9a747e4fSDavid du Colombier 	unlock(&p->lock);
77*9a747e4fSDavid du Colombier 	_sched();
78*9a747e4fSDavid du Colombier }
79*9a747e4fSDavid du Colombier 
80*9a747e4fSDavid du Colombier void
81*9a747e4fSDavid du Colombier _sched(void)
82*9a747e4fSDavid du Colombier {
83*9a747e4fSDavid du Colombier 	Proc *p;
84*9a747e4fSDavid du Colombier 	Thread *t;
85*9a747e4fSDavid du Colombier 
86*9a747e4fSDavid du Colombier Resched:
87*9a747e4fSDavid du Colombier 	p = _threadgetproc();
88*9a747e4fSDavid du Colombier 	if((t = p->thread) != nil){
89*9a747e4fSDavid du Colombier 		if((ulong)&p < (ulong)t->stk)	/* stack overflow */
90*9a747e4fSDavid du Colombier 			abort();
91*9a747e4fSDavid du Colombier 		_threaddebug(DBGSCHED, "pausing, state=%s", psstate(t->state));
92*9a747e4fSDavid du Colombier 		if(setjmp(t->sched)==0)
93*9a747e4fSDavid du Colombier 			longjmp(p->sched, 1);
94*9a747e4fSDavid du Colombier 		return;
95*9a747e4fSDavid du Colombier 	}else{
96*9a747e4fSDavid du Colombier 		t = runthread(p);
97*9a747e4fSDavid du Colombier 		if(t == nil){
98*9a747e4fSDavid du Colombier 			_threaddebug(DBGSCHED, "all threads gone; exiting");
99*9a747e4fSDavid du Colombier 			_schedexit(p);
100*9a747e4fSDavid du Colombier 		}
101*9a747e4fSDavid du Colombier 		_threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id);
102*9a747e4fSDavid du Colombier 		p->thread = t;
103*9a747e4fSDavid du Colombier 		if(t->moribund){
104*9a747e4fSDavid du Colombier 			_threaddebug(DBGSCHED, "%d.%d marked to die");
105*9a747e4fSDavid du Colombier 			goto Resched;
106*9a747e4fSDavid du Colombier 		}
107*9a747e4fSDavid du Colombier 		t->state = Running;
108*9a747e4fSDavid du Colombier 		t->nextstate = Ready;
109*9a747e4fSDavid du Colombier 		longjmp(t->sched, 1);
110*9a747e4fSDavid du Colombier 	}
111*9a747e4fSDavid du Colombier }
112*9a747e4fSDavid du Colombier 
113*9a747e4fSDavid du Colombier static Thread*
114*9a747e4fSDavid du Colombier runthread(Proc *p)
115*9a747e4fSDavid du Colombier {
116*9a747e4fSDavid du Colombier 	Thread *t;
117*9a747e4fSDavid du Colombier 	Tqueue *q;
118*9a747e4fSDavid du Colombier 
119*9a747e4fSDavid du Colombier 	if(p->nthreads==0)
120*9a747e4fSDavid du Colombier 		return nil;
121*9a747e4fSDavid du Colombier 	q = &p->ready;
122*9a747e4fSDavid du Colombier 	lock(&p->readylock);
123*9a747e4fSDavid du Colombier 	if(q->head == nil){
124*9a747e4fSDavid du Colombier 		q->asleep = 1;
125*9a747e4fSDavid du Colombier 		_threaddebug(DBGSCHED, "sleeping for more work");
126*9a747e4fSDavid du Colombier 		unlock(&p->readylock);
127*9a747e4fSDavid du Colombier 		while(rendezvous((ulong)q, 0) == ~0){
128*9a747e4fSDavid du Colombier 			if(_threadexitsallstatus)
129*9a747e4fSDavid du Colombier 				exits(_threadexitsallstatus);
130*9a747e4fSDavid du Colombier 		}
131*9a747e4fSDavid du Colombier 		/* lock picked up from _threadready */
132*9a747e4fSDavid du Colombier 	}
133*9a747e4fSDavid du Colombier 	t = q->head;
134*9a747e4fSDavid du Colombier 	q->head = t->next;
135*9a747e4fSDavid du Colombier 	unlock(&p->readylock);
136*9a747e4fSDavid du Colombier 	return t;
137*9a747e4fSDavid du Colombier }
138*9a747e4fSDavid du Colombier 
139*9a747e4fSDavid du Colombier void
140*9a747e4fSDavid du Colombier _threadready(Thread *t)
141*9a747e4fSDavid du Colombier {
142*9a747e4fSDavid du Colombier 	Tqueue *q;
143*9a747e4fSDavid du Colombier 
144*9a747e4fSDavid du Colombier 	assert(t->state == Ready);
145*9a747e4fSDavid du Colombier 	_threaddebug(DBGSCHED, "readying %d.%d", t->proc->pid, t->id);
146*9a747e4fSDavid du Colombier 	q = &t->proc->ready;
147*9a747e4fSDavid du Colombier 	lock(&t->proc->readylock);
148*9a747e4fSDavid du Colombier 	t->next = nil;
149*9a747e4fSDavid du Colombier 	if(q->head==nil)
150*9a747e4fSDavid du Colombier 		q->head = t;
151*9a747e4fSDavid du Colombier 	else
152*9a747e4fSDavid du Colombier 		*q->tail = t;
153*9a747e4fSDavid du Colombier 	q->tail = &t->next;
154*9a747e4fSDavid du Colombier 	if(q->asleep){
155*9a747e4fSDavid du Colombier 		q->asleep = 0;
156*9a747e4fSDavid du Colombier 		/* lock passes to runthread */
157*9a747e4fSDavid du Colombier 		_threaddebug(DBGSCHED, "waking process %d", t->proc->pid);
158*9a747e4fSDavid du Colombier 		while(rendezvous((ulong)q, 0) == ~0){
159*9a747e4fSDavid du Colombier 			if(_threadexitsallstatus)
160*9a747e4fSDavid du Colombier 				exits(_threadexitsallstatus);
161*9a747e4fSDavid du Colombier 		}
162*9a747e4fSDavid du Colombier 	}else
163*9a747e4fSDavid du Colombier 		unlock(&t->proc->readylock);
164*9a747e4fSDavid du Colombier }
165*9a747e4fSDavid du Colombier 
166*9a747e4fSDavid du Colombier void
167*9a747e4fSDavid du Colombier yield(void)
168*9a747e4fSDavid du Colombier {
169*9a747e4fSDavid du Colombier 	_sched();
170*9a747e4fSDavid du Colombier }
171*9a747e4fSDavid du Colombier 
172