]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libthread/sched.c
merge
[plan9front.git] / sys / src / libthread / sched.c
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*
20 psstate(int s)
21 {
22         if(s < 0 || s >= nelem(_psstate))
23                 return "unknown";
24         return _psstate[s];
25 }
26
27 void
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
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
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*
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
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
185 yield(void)
186 {
187         _sched();
188 }
189