Blob


1 #include <signal.h>
2 #include <errno.h>
3 #include "threadimpl.h"
5 //static Thread *runthread(Proc*);
7 static char *_psstate[] = {
8 "Dead",
9 "Running",
10 "Ready",
11 "Rendezvous",
12 };
14 static char*
15 psstate(int s)
16 {
17 if(s < 0 || s >= nelem(_psstate))
18 return "unknown";
19 return _psstate[s];
20 }
22 void
23 _schedinit(void *arg)
24 {
25 Proc *p;
26 Thread *t;
27 extern void ignusr1(void), _threaddie(int);
28 ignusr1();
29 signal(SIGTERM, _threaddie);
31 p = arg;
32 lock(&p->lock);
33 p->pid = _threadgetpid();
34 _threadsetproc(p);
35 unlock(&p->lock);
36 while(_setlabel(&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 if(t->moribund != 1)
46 fprint(2, "moribund %d\n", t->moribund);
47 assert(t->moribund == 1);
48 t->state = Dead;
49 if(t->prevt)
50 t->prevt->nextt = t->nextt;
51 else
52 p->threads.head = t->nextt;
53 if(t->nextt)
54 t->nextt->prevt = t->prevt;
55 else
56 p->threads.tail = t->prevt;
57 unlock(&p->lock);
58 if(t->inrendez){
59 _threadflagrendez(t);
60 _threadbreakrendez();
61 }
62 _stackfree(t->stk);
63 free(t->cmdname);
64 free(t); /* XXX how do we know there are no references? */
65 p->nthreads--;
66 t = nil;
67 _sched();
68 }
69 /*
70 if(p->needexec){
71 t->ret = _schedexec(&p->exec);
72 p->needexec = 0;
73 }
74 */
75 if(p->newproc){
76 t->ret = _schedfork(p->newproc);
77 if(t->ret < 0){
78 //fprint(2, "_schedfork: %r\n");
79 abort();
80 }
81 p->newproc = nil;
82 }
83 t->state = t->nextstate;
84 if(t->state == Ready)
85 _threadready(t);
86 }
87 unlock(&p->lock);
88 _sched();
89 }
91 static Thread*
92 runthread(Proc *p)
93 {
94 Channel *c;
95 Thread *t;
96 Tqueue *q;
97 Waitmsg *w;
98 int e, sent;
100 if(p->nthreads==0 || (p->nthreads==1 && p->idle))
101 return nil;
102 q = &p->ready;
103 relock:
104 lock(&p->readylock);
105 if(q->head == nil){
106 e = errno;
107 if((c = _threadwaitchan) != nil){
108 if(c->n <= c->s){
109 sent = 0;
110 for(;;){
111 if((w = p->waitmsg) != nil)
112 p->waitmsg = nil;
113 else
114 w = waitnohang();
115 if(w == nil)
116 break;
117 if(sent == 0){
118 unlock(&p->readylock);
119 sent = 1;
121 if(nbsendp(c, w) != 1)
122 break;
124 p->waitmsg = w;
125 if(sent)
126 goto relock;
128 }else{
129 while((w = waitnohang()) != nil)
130 free(w);
132 errno = e;
133 if(p->idle){
134 if(p->idle->state != Ready){
135 fprint(2, "everyone is asleep\n");
136 exits("everyone is asleep");
138 unlock(&p->readylock);
139 _threaddebug(DBGSCHED, "running idle thread", p->nthreads);
140 return p->idle;
143 _threaddebug(DBGSCHED, "sleeping for more work (%d threads)", p->nthreads);
144 q->asleep = 1;
145 unlock(&p->readylock);
146 while(rendezvous((ulong)q, 0) == ~0){
147 if(_threadexitsallstatus)
148 exits(_threadexitsallstatus);
150 /* lock picked up from _threadready */
152 t = q->head;
153 q->head = t->next;
154 unlock(&p->readylock);
155 return t;
158 void
159 _sched(void)
161 Proc *p;
162 Thread *t;
164 Resched:
165 p = _threadgetproc();
166 //fprint(2, "p %p\n", p);
167 if((t = p->thread) != nil){
168 if((ulong)&p < (ulong)t->stk){ /* stack overflow */
169 fprint(2, "stack overflow %lux %lux\n", (ulong)&p, (ulong)t->stk);
170 abort();
172 // _threaddebug(DBGSCHED, "pausing, state=%s set %p goto %p",
173 // psstate(t->state), &t->sched, &p->sched);
174 if(_setlabel(&t->sched)==0)
175 _gotolabel(&p->sched);
176 return;
177 }else{
178 t = runthread(p);
179 if(t == nil){
180 _threaddebug(DBGSCHED, "all threads gone; exiting");
181 _threaddelproc();
182 _schedexit(p);
184 _threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id);
185 p->thread = t;
186 if(t->moribund){
187 _threaddebug(DBGSCHED, "%d.%d marked to die");
188 goto Resched;
190 t->state = Running;
191 t->nextstate = Ready;
192 _gotolabel(&t->sched);
196 long
197 threadstack(void)
199 Proc *p;
200 Thread *t;
202 p = _threadgetproc();
203 t = p->thread;
204 return (ulong)&p - (ulong)t->stk;
207 void
208 _threadready(Thread *t)
210 Tqueue *q;
212 if(t == t->proc->idle){
213 _threaddebug(DBGSCHED, "idle thread is ready");
214 return;
217 assert(t->state == Ready);
218 _threaddebug(DBGSCHED, "readying %d.%d", t->proc->pid, t->id);
219 q = &t->proc->ready;
220 lock(&t->proc->readylock);
221 t->next = nil;
222 if(q->head==nil)
223 q->head = t;
224 else
225 q->tail->next = t;
226 q->tail = t;
227 if(q->asleep){
228 assert(q->asleep == 1);
229 q->asleep = 0;
230 /* lock passes to runthread */
231 _threaddebug(DBGSCHED, "waking process %d", t->proc->pid);
232 while(rendezvous((ulong)q, 0) == ~0){
233 if(_threadexitsallstatus)
234 exits(_threadexitsallstatus);
236 }else
237 unlock(&t->proc->readylock);
240 void
241 _threadidle(void)
243 Tqueue *q;
244 Thread *t, *idle;
245 Proc *p;
247 p = _threadgetproc();
248 q = &p->ready;
249 lock(&p->readylock);
250 assert(q->tail);
251 idle = q->tail;
252 if(q->head == idle){
253 q->head = nil;
254 q->tail = nil;
255 }else{
256 for(t=q->head; t->next!=q->tail; t=t->next)
258 t->next = nil;
259 q->tail = t;
261 p->idle = idle;
262 _threaddebug(DBGSCHED, "p->idle is %d\n", idle->id);
263 unlock(&p->readylock);
266 void
267 yield(void)
269 _sched();
272 void
273 threadstatus(void)
275 Proc *p;
276 Thread *t;
278 p = _threadgetproc();
279 for(t=p->threads.head; t; t=t->nextt)
280 fprint(2, "[%3d] %s userpc=%lux\n",
281 t->id, psstate(t->state), t->userpc);