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 190