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