Blob
1 #include <u.h>2 #include <signal.h>3 #include <errno.h>4 #include "threadimpl.h"6 static Thread *runthread(Proc*);8 static char *_psstate[] = {9 "Dead",10 "Running",11 "Ready",12 "Rendezvous",13 };15 static char*16 psstate(int s)17 {18 if(s < 0 || s >= nelem(_psstate))19 return "unknown";20 return _psstate[s];21 }23 void24 needstack(int howmuch)25 {26 Proc *p;27 Thread *t;29 p = _threadgetproc();30 if(p == nil || (t=p->thread) == nil)31 return;32 if((ulong)&howmuch < (ulong)t->stk+howmuch){ /* stack overflow waiting to happen */33 fprint(2, "stack overflow: stack at 0x%lux, limit at 0x%lux, need 0x%lux\n", (ulong)&p, (ulong)t->stk, howmuch);34 abort();35 }36 }38 void39 _scheduler(void *arg)40 {41 Proc *p;42 Thread *t;44 p = arg;45 lock(&p->lock);46 p->pid = _threadgetpid();47 _threadsetproc(p);49 for(;;){50 t = runthread(p);51 if(t == nil){52 _threaddebug(DBGSCHED, "all threads gone; exiting");53 _threaddelproc();54 _schedexit(p);55 }56 _threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id);57 p->thread = t;58 if(t->moribund){59 _threaddebug(DBGSCHED, "%d.%d marked to die");60 goto Moribund;61 }62 t->state = Running;63 t->nextstate = Ready;64 unlock(&p->lock);66 _swaplabel(&p->sched, &t->sched);68 lock(&p->lock);69 p->thread = nil;70 if(t->moribund){71 Moribund:72 if(t->moribund != 1)73 fprint(2, "moribund %d\n", t->moribund);74 assert(t->moribund == 1);75 t->state = Dead;76 if(t->prevt)77 t->prevt->nextt = t->nextt;78 else79 p->threads.head = t->nextt;80 if(t->nextt)81 t->nextt->prevt = t->prevt;82 else83 p->threads.tail = t->prevt;84 unlock(&p->lock);85 if(t->inrendez){86 abort();87 // _threadflagrendez(t);88 // _threadbreakrendez();89 }90 _stackfree(t->stk);91 free(t->cmdname);92 free(t); /* XXX how do we know there are no references? */93 p->nthreads--;94 t = nil;95 lock(&p->lock);96 continue;97 }98 /*99 if(p->needexec){100 t->ret = _schedexec(&p->exec);101 p->needexec = 0;102 }103 */104 if(p->newproc){105 t->ret = _schedfork(p->newproc);106 if(t->ret < 0){107 //fprint(2, "_schedfork: %r\n");108 abort();109 }110 p->newproc = nil;111 }112 t->state = t->nextstate;113 if(t->state == Ready)114 _threadready(t);115 unlock(&p->lock);116 }117 }119 int120 _sched(void)121 {122 Proc *p;123 Thread *t;125 p = _threadgetproc();126 t = p->thread;127 assert(t != nil);128 _swaplabel(&t->sched, &p->sched);129 return p->nsched++;130 }132 static Thread*133 runthread(Proc *p)134 {135 Channel *c;136 Thread *t;137 Tqueue *q;138 Waitmsg *w;139 int e, sent;141 if(p->nthreads==0 || (p->nthreads==1 && p->idle))142 return nil;143 q = &p->ready;144 relock:145 lock(&p->readylock);146 if(p->nsched%128 == 0){147 /* clean up children */148 e = errno;149 if((c = _threadwaitchan) != nil){150 if(c->n <= c->s){151 sent = 0;152 for(;;){153 if((w = p->waitmsg) != nil)154 p->waitmsg = nil;155 else156 w = waitnohang();157 if(w == nil)158 break;159 if(sent == 0){160 unlock(&p->readylock);161 sent = 1;162 }163 if(nbsendp(c, w) != 1)164 break;165 }166 p->waitmsg = w;167 if(sent)168 goto relock;169 }170 }else{171 while((w = waitnohang()) != nil)172 free(w);173 }174 errno = e;175 }176 if(q->head == nil){177 if(p->idle){178 if(p->idle->state != Ready){179 fprint(2, "everyone is asleep\n");180 exits("everyone is asleep");181 }182 unlock(&p->readylock);183 _threaddebug(DBGSCHED, "running idle thread", p->nthreads);184 return p->idle;185 }187 _threaddebug(DBGSCHED, "sleeping for more work (%d threads)", p->nthreads);188 q->asleep = 1;189 p->rend.l = &p->readylock;190 _procsleep(&p->rend);191 if(_threadexitsallstatus)192 _exits(_threadexitsallstatus);193 }194 t = q->head;195 q->head = t->next;196 unlock(&p->readylock);197 return t;198 }200 long201 threadstack(void)202 {203 Proc *p;204 Thread *t;206 p = _threadgetproc();207 t = p->thread;208 return (ulong)&p - (ulong)t->stk;209 }211 void212 _threadready(Thread *t)213 {214 Tqueue *q;216 if(t == t->proc->idle){217 _threaddebug(DBGSCHED, "idle thread is ready");218 return;219 }221 assert(t->state == Ready);222 _threaddebug(DBGSCHED, "readying %d.%d", t->proc->pid, t->id);223 q = &t->proc->ready;224 lock(&t->proc->readylock);225 t->next = nil;226 if(q->head==nil)227 q->head = t;228 else229 q->tail->next = t;230 q->tail = t;231 if(q->asleep){232 assert(q->asleep == 1);233 q->asleep = 0;234 /* lock passes to runthread */235 _procwakeup(&t->proc->rend);236 }237 unlock(&t->proc->readylock);238 if(_threadexitsallstatus)239 _exits(_threadexitsallstatus);240 }242 void243 _threadidle(void)244 {245 Tqueue *q;246 Thread *t, *idle;247 Proc *p;249 p = _threadgetproc();250 q = &p->ready;251 lock(&p->readylock);252 assert(q->tail);253 idle = q->tail;254 if(q->head == idle){255 q->head = nil;256 q->tail = nil;257 }else{258 for(t=q->head; t->next!=q->tail; t=t->next)259 ;260 t->next = nil;261 q->tail = t;262 }263 p->idle = idle;264 _threaddebug(DBGSCHED, "p->idle is %d\n", idle->id);265 unlock(&p->readylock);266 }268 int269 yield(void)270 {271 Proc *p;272 int nsched;274 p = _threadgetproc();275 nsched = p->nsched;276 return _sched() - nsched;277 }279 void280 threadstatus(void)281 {282 Proc *p;283 Thread *t;285 p = _threadgetproc();286 for(t=p->threads.head; t; t=t->nextt)287 fprint(2, "[%3d] %s userpc=%lux\n",288 t->id, psstate(t->state), t->userpc);289 }