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