1 #include <u.h> 2 #include <libc.h> 3 #include <thread.h> 4 #include "threadimpl.h" 5 6 static Thread *runthread(Proc*); 7 8 static char *_psstate[] = { 9 "Moribund", 10 "Dead", 11 "Exec", 12 "Fork", 13 "Running", 14 "Ready", 15 "Rendezvous", 16 }; 17 18 static char* 19 psstate(int s) 20 { 21 if(s < 0 || s >= nelem(_psstate)) 22 return "unknown"; 23 return _psstate[s]; 24 } 25 26 void 27 _schedinit(void *arg) 28 { 29 Proc *p; 30 Thread *t, **l; 31 32 p = arg; 33 _threadsetproc(p); 34 p->pid = getpid(); 35 while(setjmp(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 t->state = Dead; 45 for(l=&p->threads.head; *l; l=&(*l)->nextt) 46 if(*l == t){ 47 *l = t->nextt; 48 if(*l==nil) 49 p->threads.tail = l; 50 p->nthreads--; 51 break; 52 } 53 unlock(&p->lock); 54 if(t->inrendez){ 55 _threadflagrendez(t); 56 _threadbreakrendez(); 57 } 58 free(t->stk); 59 free(t->cmdname); 60 free(t); /* XXX how do we know there are no references? */ 61 t = nil; 62 _sched(); 63 } 64 if(p->needexec){ 65 t->ret = _schedexec(&p->exec); 66 p->needexec = 0; 67 } 68 if(p->newproc){ 69 t->ret = _schedfork(p->newproc); 70 p->newproc = nil; 71 } 72 t->state = t->nextstate; 73 if(t->state == Ready) 74 _threadready(t); 75 } 76 unlock(&p->lock); 77 _sched(); 78 } 79 80 void 81 needstack(int n) 82 { 83 int x; 84 Proc *p; 85 Thread *t; 86 87 p = _threadgetproc(); 88 t = p->thread; 89 90 if((uchar*)&x - n < (uchar*)t->stk){ 91 fprint(2, "%s %d: &x=%p n=%d t->stk=%p\n", 92 argv0, getpid(), &x, n, t->stk); 93 fprint(2, "%s %d: stack overflow\n", argv0, getpid()); 94 abort(); 95 } 96 } 97 98 void 99 _sched(void) 100 { 101 Proc *p; 102 Thread *t; 103 104 Resched: 105 p = _threadgetproc(); 106 if((t = p->thread) != nil){ 107 needstack(128); 108 _threaddebug(DBGSCHED, "pausing, state=%s", psstate(t->state)); 109 if(setjmp(t->sched)==0) 110 longjmp(p->sched, 1); 111 return; 112 }else{ 113 t = runthread(p); 114 if(t == nil){ 115 _threaddebug(DBGSCHED, "all threads gone; exiting"); 116 _schedexit(p); 117 } 118 _threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id); 119 p->thread = t; 120 if(t->moribund){ 121 _threaddebug(DBGSCHED, "%d.%d marked to die"); 122 goto Resched; 123 } 124 t->state = Running; 125 t->nextstate = Ready; 126 longjmp(t->sched, 1); 127 } 128 } 129 130 static Thread* 131 runthread(Proc *p) 132 { 133 Thread *t; 134 Tqueue *q; 135 136 if(p->nthreads==0) 137 return nil; 138 q = &p->ready; 139 lock(&p->readylock); 140 if(q->head == nil){ 141 q->asleep = 1; 142 _threaddebug(DBGSCHED, "sleeping for more work"); 143 unlock(&p->readylock); 144 while(rendezvous(q, 0) == (void*)~0){ 145 if(_threadexitsallstatus) 146 exits(_threadexitsallstatus); 147 } 148 /* lock picked up from _threadready */ 149 } 150 t = q->head; 151 q->head = t->next; 152 unlock(&p->readylock); 153 return t; 154 } 155 156 void 157 _threadready(Thread *t) 158 { 159 Tqueue *q; 160 161 assert(t->state == Ready); 162 _threaddebug(DBGSCHED, "readying %d.%d", t->proc->pid, t->id); 163 q = &t->proc->ready; 164 lock(&t->proc->readylock); 165 t->next = nil; 166 if(q->head==nil) 167 q->head = t; 168 else 169 *q->tail = t; 170 q->tail = &t->next; 171 if(q->asleep){ 172 q->asleep = 0; 173 /* lock passes to runthread */ 174 _threaddebug(DBGSCHED, "waking process %d", t->proc->pid); 175 while(rendezvous(q, 0) == (void*)~0){ 176 if(_threadexitsallstatus) 177 exits(_threadexitsallstatus); 178 } 179 }else 180 unlock(&t->proc->readylock); 181 } 182 183 void 184 yield(void) 185 { 186 _sched(); 187 } 188 189