Blob


1 #include "threadimpl.h"
2 #include <signal.h>
4 //static Thread *runthread(Proc*);
6 static char *_psstate[] = {
7 "Dead",
8 "Running",
9 "Ready",
10 "Rendezvous",
11 };
13 static char*
14 psstate(int s)
15 {
16 if(s < 0 || s >= nelem(_psstate))
17 return "unknown";
18 return _psstate[s];
19 }
21 void
22 _schedinit(void *arg)
23 {
24 Proc *p;
25 Thread *t;
26 extern void ignusr1(void), _threaddie(int);
27 ignusr1();
28 signal(SIGTERM, _threaddie);
32 p = arg;
33 p->pid = _threadgetpid();
34 _threadsetproc(p);
35 while(_setlabel(&p->sched))
36 ;
37 _threaddebug(DBGSCHED, "top of schedinit, _threadexitsallstatus=%p", _threadexitsallstatus);
38 if(_threadexitsallstatus)
39 exits(_threadexitsallstatus);
40 lock(&p->lock);
41 if((t=p->thread) != nil){
42 p->thread = nil;
43 if(t->moribund){
44 assert(t->moribund == 1);
45 t->state = Dead;
46 if(t->prevt)
47 t->prevt->nextt = t->nextt;
48 else
49 p->threads.head = t->nextt;
50 if(t->nextt)
51 t->nextt->prevt = t->prevt;
52 else
53 p->threads.tail = t->prevt;
54 unlock(&p->lock);
55 if(t->inrendez){
56 _threadflagrendez(t);
57 _threadbreakrendez();
58 }
59 _stackfree(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 if(t->ret < 0){
72 //fprint(2, "_schedfork: %r\n");
73 abort();
74 }
75 p->newproc = nil;
76 }
77 t->state = t->nextstate;
78 if(t->state == Ready)
79 _threadready(t);
80 }
81 unlock(&p->lock);
82 _sched();
83 }
85 static inline Thread*
86 runthread(Proc *p)
87 {
88 Thread *t;
89 Tqueue *q;
91 if(p->nthreads==0)
92 return nil;
93 q = &p->ready;
94 lock(&p->readylock);
95 if(q->head == nil){
96 q->asleep = 1;
97 _threaddebug(DBGSCHED, "sleeping for more work");
98 unlock(&p->readylock);
99 while(rendezvous((ulong)q, 0) == ~0){
100 if(_threadexitsallstatus)
101 exits(_threadexitsallstatus);
103 /* lock picked up from _threadready */
105 t = q->head;
106 q->head = t->next;
107 unlock(&p->readylock);
108 return t;
111 void
112 _sched(void)
114 Proc *p;
115 Thread *t;
117 Resched:
118 p = _threadgetproc();
119 //fprint(2, "p %p\n", p);
120 if((t = p->thread) != nil){
121 if((ulong)&p < (ulong)t->stk){ /* stack overflow */
122 fprint(2, "stack overflow %lux %lux\n", (ulong)&p, (ulong)t->stk);
123 abort();
125 // _threaddebug(DBGSCHED, "pausing, state=%s set %p goto %p",
126 // psstate(t->state), &t->sched, &p->sched);
127 if(_setlabel(&t->sched)==0)
128 _gotolabel(&p->sched);
129 return;
130 }else{
131 t = runthread(p);
132 if(t == nil){
133 _threaddebug(DBGSCHED, "all threads gone; exiting");
134 _threaddelproc();
135 _schedexit(p);
137 // _threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id);
138 p->thread = t;
139 if(t->moribund){
140 _threaddebug(DBGSCHED, "%d.%d marked to die");
141 goto Resched;
143 t->state = Running;
144 t->nextstate = Ready;
145 _gotolabel(&t->sched);
149 long
150 threadstack(void)
152 Proc *p;
153 Thread *t;
155 p = _threadgetproc();
156 t = p->thread;
157 return (ulong)&p - (ulong)t->stk;
160 void
161 _threadready(Thread *t)
163 Tqueue *q;
165 assert(t->state == Ready);
166 _threaddebug(DBGSCHED, "readying %d.%d", t->proc->pid, t->id);
167 q = &t->proc->ready;
168 lock(&t->proc->readylock);
169 t->next = nil;
170 if(q->head==nil)
171 q->head = t;
172 else
173 q->tail->next = t;
174 q->tail = t;
175 if(q->asleep){
176 q->asleep = 0;
177 /* lock passes to runthread */
178 _threaddebug(DBGSCHED, "waking process %d", t->proc->pid);
179 while(rendezvous((ulong)q, 0) == ~0){
180 if(_threadexitsallstatus)
181 exits(_threadexitsallstatus);
183 }else
184 unlock(&t->proc->readylock);
187 void
188 yield(void)
190 _sched();