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 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 _sched(void) 82 { 83 Proc *p; 84 Thread *t; 85 86 Resched: 87 p = _threadgetproc(); 88 if((t = p->thread) != nil){ 89 if((ulong)&p < (ulong)t->stk) /* stack overflow */ 90 abort(); 91 _threaddebug(DBGSCHED, "pausing, state=%s", psstate(t->state)); 92 if(setjmp(t->sched)==0) 93 longjmp(p->sched, 1); 94 return; 95 }else{ 96 t = runthread(p); 97 if(t == nil){ 98 _threaddebug(DBGSCHED, "all threads gone; exiting"); 99 _schedexit(p); 100 } 101 _threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id); 102 p->thread = t; 103 if(t->moribund){ 104 _threaddebug(DBGSCHED, "%d.%d marked to die"); 105 goto Resched; 106 } 107 t->state = Running; 108 t->nextstate = Ready; 109 longjmp(t->sched, 1); 110 } 111 } 112 113 static Thread* 114 runthread(Proc *p) 115 { 116 Thread *t; 117 Tqueue *q; 118 119 if(p->nthreads==0) 120 return nil; 121 q = &p->ready; 122 lock(&p->readylock); 123 if(q->head == nil){ 124 q->asleep = 1; 125 _threaddebug(DBGSCHED, "sleeping for more work"); 126 unlock(&p->readylock); 127 while(rendezvous((ulong)q, 0) == ~0){ 128 if(_threadexitsallstatus) 129 exits(_threadexitsallstatus); 130 } 131 /* lock picked up from _threadready */ 132 } 133 t = q->head; 134 q->head = t->next; 135 unlock(&p->readylock); 136 return t; 137 } 138 139 void 140 _threadready(Thread *t) 141 { 142 Tqueue *q; 143 144 assert(t->state == Ready); 145 _threaddebug(DBGSCHED, "readying %d.%d", t->proc->pid, t->id); 146 q = &t->proc->ready; 147 lock(&t->proc->readylock); 148 t->next = nil; 149 if(q->head==nil) 150 q->head = t; 151 else 152 *q->tail = t; 153 q->tail = &t->next; 154 if(q->asleep){ 155 q->asleep = 0; 156 /* lock passes to runthread */ 157 _threaddebug(DBGSCHED, "waking process %d", t->proc->pid); 158 while(rendezvous((ulong)q, 0) == ~0){ 159 if(_threadexitsallstatus) 160 exits(_threadexitsallstatus); 161 } 162 }else 163 unlock(&t->proc->readylock); 164 } 165 166 void 167 yield(void) 168 { 169 _sched(); 170 } 171 172