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