19a747e4fSDavid du Colombier #include <u.h> 29a747e4fSDavid du Colombier #include <libc.h> 39a747e4fSDavid du Colombier #include <thread.h> 49a747e4fSDavid du Colombier #include "threadimpl.h" 59a747e4fSDavid du Colombier 69a747e4fSDavid du Colombier static Thread *runthread(Proc*); 79a747e4fSDavid du Colombier 89a747e4fSDavid du Colombier static char *_psstate[] = { 99a747e4fSDavid du Colombier "Moribund", 109a747e4fSDavid du Colombier "Dead", 119a747e4fSDavid du Colombier "Exec", 129a747e4fSDavid du Colombier "Fork", 139a747e4fSDavid du Colombier "Running", 149a747e4fSDavid du Colombier "Ready", 159a747e4fSDavid du Colombier "Rendezvous", 169a747e4fSDavid du Colombier }; 179a747e4fSDavid du Colombier 18*3ff48bf5SDavid du Colombier static char* 199a747e4fSDavid du Colombier psstate(int s) 209a747e4fSDavid du Colombier { 219a747e4fSDavid du Colombier if(s < 0 || s >= nelem(_psstate)) 229a747e4fSDavid du Colombier return "unknown"; 239a747e4fSDavid du Colombier return _psstate[s]; 249a747e4fSDavid du Colombier } 259a747e4fSDavid du Colombier 269a747e4fSDavid du Colombier void 279a747e4fSDavid du Colombier _schedinit(void *arg) 289a747e4fSDavid du Colombier { 299a747e4fSDavid du Colombier Proc *p; 309a747e4fSDavid du Colombier Thread *t, **l; 319a747e4fSDavid du Colombier 329a747e4fSDavid du Colombier p = arg; 339a747e4fSDavid du Colombier _threadsetproc(p); 349a747e4fSDavid du Colombier p->pid = getpid(); 359a747e4fSDavid du Colombier while(setjmp(p->sched)) 369a747e4fSDavid du Colombier ; 379a747e4fSDavid du Colombier _threaddebug(DBGSCHED, "top of schedinit, _threadexitsallstatus=%p", _threadexitsallstatus); 389a747e4fSDavid du Colombier if(_threadexitsallstatus) 399a747e4fSDavid du Colombier exits(_threadexitsallstatus); 409a747e4fSDavid du Colombier lock(&p->lock); 419a747e4fSDavid du Colombier if((t=p->thread) != nil){ 429a747e4fSDavid du Colombier p->thread = nil; 439a747e4fSDavid du Colombier if(t->moribund){ 449a747e4fSDavid du Colombier t->state = Dead; 459a747e4fSDavid du Colombier for(l=&p->threads.head; *l; l=&(*l)->nextt) 469a747e4fSDavid du Colombier if(*l == t){ 479a747e4fSDavid du Colombier *l = t->nextt; 489a747e4fSDavid du Colombier if(*l==nil) 499a747e4fSDavid du Colombier p->threads.tail = l; 509a747e4fSDavid du Colombier p->nthreads--; 519a747e4fSDavid du Colombier break; 529a747e4fSDavid du Colombier } 539a747e4fSDavid du Colombier unlock(&p->lock); 549a747e4fSDavid du Colombier if(t->inrendez){ 559a747e4fSDavid du Colombier _threadflagrendez(t); 569a747e4fSDavid du Colombier _threadbreakrendez(); 579a747e4fSDavid du Colombier } 589a747e4fSDavid du Colombier free(t->stk); 599a747e4fSDavid du Colombier free(t->cmdname); 609a747e4fSDavid du Colombier free(t); /* XXX how do we know there are no references? */ 619a747e4fSDavid du Colombier t = nil; 629a747e4fSDavid du Colombier _sched(); 639a747e4fSDavid du Colombier } 649a747e4fSDavid du Colombier if(p->needexec){ 659a747e4fSDavid du Colombier t->ret = _schedexec(&p->exec); 669a747e4fSDavid du Colombier p->needexec = 0; 679a747e4fSDavid du Colombier } 689a747e4fSDavid du Colombier if(p->newproc){ 699a747e4fSDavid du Colombier t->ret = _schedfork(p->newproc); 709a747e4fSDavid du Colombier p->newproc = nil; 719a747e4fSDavid du Colombier } 729a747e4fSDavid du Colombier t->state = t->nextstate; 739a747e4fSDavid du Colombier if(t->state == Ready) 749a747e4fSDavid du Colombier _threadready(t); 759a747e4fSDavid du Colombier } 769a747e4fSDavid du Colombier unlock(&p->lock); 779a747e4fSDavid du Colombier _sched(); 789a747e4fSDavid du Colombier } 799a747e4fSDavid du Colombier 809a747e4fSDavid du Colombier void 819a747e4fSDavid du Colombier _sched(void) 829a747e4fSDavid du Colombier { 839a747e4fSDavid du Colombier Proc *p; 849a747e4fSDavid du Colombier Thread *t; 859a747e4fSDavid du Colombier 869a747e4fSDavid du Colombier Resched: 879a747e4fSDavid du Colombier p = _threadgetproc(); 889a747e4fSDavid du Colombier if((t = p->thread) != nil){ 899a747e4fSDavid du Colombier if((ulong)&p < (ulong)t->stk) /* stack overflow */ 909a747e4fSDavid du Colombier abort(); 919a747e4fSDavid du Colombier _threaddebug(DBGSCHED, "pausing, state=%s", psstate(t->state)); 929a747e4fSDavid du Colombier if(setjmp(t->sched)==0) 939a747e4fSDavid du Colombier longjmp(p->sched, 1); 949a747e4fSDavid du Colombier return; 959a747e4fSDavid du Colombier }else{ 969a747e4fSDavid du Colombier t = runthread(p); 979a747e4fSDavid du Colombier if(t == nil){ 989a747e4fSDavid du Colombier _threaddebug(DBGSCHED, "all threads gone; exiting"); 999a747e4fSDavid du Colombier _schedexit(p); 1009a747e4fSDavid du Colombier } 1019a747e4fSDavid du Colombier _threaddebug(DBGSCHED, "running %d.%d", t->proc->pid, t->id); 1029a747e4fSDavid du Colombier p->thread = t; 1039a747e4fSDavid du Colombier if(t->moribund){ 1049a747e4fSDavid du Colombier _threaddebug(DBGSCHED, "%d.%d marked to die"); 1059a747e4fSDavid du Colombier goto Resched; 1069a747e4fSDavid du Colombier } 1079a747e4fSDavid du Colombier t->state = Running; 1089a747e4fSDavid du Colombier t->nextstate = Ready; 1099a747e4fSDavid du Colombier longjmp(t->sched, 1); 1109a747e4fSDavid du Colombier } 1119a747e4fSDavid du Colombier } 1129a747e4fSDavid du Colombier 1139a747e4fSDavid du Colombier static Thread* 1149a747e4fSDavid du Colombier runthread(Proc *p) 1159a747e4fSDavid du Colombier { 1169a747e4fSDavid du Colombier Thread *t; 1179a747e4fSDavid du Colombier Tqueue *q; 1189a747e4fSDavid du Colombier 1199a747e4fSDavid du Colombier if(p->nthreads==0) 1209a747e4fSDavid du Colombier return nil; 1219a747e4fSDavid du Colombier q = &p->ready; 1229a747e4fSDavid du Colombier lock(&p->readylock); 1239a747e4fSDavid du Colombier if(q->head == nil){ 1249a747e4fSDavid du Colombier q->asleep = 1; 1259a747e4fSDavid du Colombier _threaddebug(DBGSCHED, "sleeping for more work"); 1269a747e4fSDavid du Colombier unlock(&p->readylock); 1279a747e4fSDavid du Colombier while(rendezvous((ulong)q, 0) == ~0){ 1289a747e4fSDavid du Colombier if(_threadexitsallstatus) 1299a747e4fSDavid du Colombier exits(_threadexitsallstatus); 1309a747e4fSDavid du Colombier } 1319a747e4fSDavid du Colombier /* lock picked up from _threadready */ 1329a747e4fSDavid du Colombier } 1339a747e4fSDavid du Colombier t = q->head; 1349a747e4fSDavid du Colombier q->head = t->next; 1359a747e4fSDavid du Colombier unlock(&p->readylock); 1369a747e4fSDavid du Colombier return t; 1379a747e4fSDavid du Colombier } 1389a747e4fSDavid du Colombier 1399a747e4fSDavid du Colombier void 1409a747e4fSDavid du Colombier _threadready(Thread *t) 1419a747e4fSDavid du Colombier { 1429a747e4fSDavid du Colombier Tqueue *q; 1439a747e4fSDavid du Colombier 1449a747e4fSDavid du Colombier assert(t->state == Ready); 1459a747e4fSDavid du Colombier _threaddebug(DBGSCHED, "readying %d.%d", t->proc->pid, t->id); 1469a747e4fSDavid du Colombier q = &t->proc->ready; 1479a747e4fSDavid du Colombier lock(&t->proc->readylock); 1489a747e4fSDavid du Colombier t->next = nil; 1499a747e4fSDavid du Colombier if(q->head==nil) 1509a747e4fSDavid du Colombier q->head = t; 1519a747e4fSDavid du Colombier else 1529a747e4fSDavid du Colombier *q->tail = t; 1539a747e4fSDavid du Colombier q->tail = &t->next; 1549a747e4fSDavid du Colombier if(q->asleep){ 1559a747e4fSDavid du Colombier q->asleep = 0; 1569a747e4fSDavid du Colombier /* lock passes to runthread */ 1579a747e4fSDavid du Colombier _threaddebug(DBGSCHED, "waking process %d", t->proc->pid); 1589a747e4fSDavid du Colombier while(rendezvous((ulong)q, 0) == ~0){ 1599a747e4fSDavid du Colombier if(_threadexitsallstatus) 1609a747e4fSDavid du Colombier exits(_threadexitsallstatus); 1619a747e4fSDavid du Colombier } 1629a747e4fSDavid du Colombier }else 1639a747e4fSDavid du Colombier unlock(&t->proc->readylock); 1649a747e4fSDavid du Colombier } 1659a747e4fSDavid du Colombier 1669a747e4fSDavid du Colombier void 1679a747e4fSDavid du Colombier yield(void) 1689a747e4fSDavid du Colombier { 1699a747e4fSDavid du Colombier _sched(); 1709a747e4fSDavid du Colombier } 1719a747e4fSDavid du Colombier 172