1 #include "u.h" 2 #include "../port/lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "../port/error.h" 7 #include <interp.h> 8 9 Ref pidalloc; 10 11 struct 12 { 13 Lock; 14 Proc* arena; 15 Proc* free; 16 }procalloc; 17 18 typedef struct 19 { 20 Lock; 21 Proc* head; 22 Proc* tail; 23 }Schedq; 24 25 static Schedq runq[Nrq]; 26 static ulong occupied; 27 int nrdy; 28 29 char *statename[] = 30 { /* BUG: generate automatically */ 31 "Dead", 32 "Moribund", 33 "Ready", 34 "Scheding", 35 "Running", 36 "Queueing", 37 "Wakeme", 38 "Broken", 39 "Stopped", 40 "Rendez", 41 }; 42 43 /* 44 * Always splhi()'ed. 45 */ 46 void 47 schedinit(void) /* never returns */ 48 { 49 setlabel(&m->sched); 50 if(up) { 51 /* 52 if((e = up->edf) && (e->flags & Admitted)) 53 edfrecord(up); 54 */ 55 m->proc = nil; 56 switch(up->state) { 57 case Running: 58 ready(up); 59 break; 60 case Moribund: 61 up->state = Dead; 62 /* 63 edfstop(up); 64 if(up->edf){ 65 free(up->edf); 66 up->edf = nil; 67 } 68 */ 69 /* 70 * Holding locks from pexit: 71 * procalloc 72 */ 73 up->qnext = procalloc.free; 74 procalloc.free = up; 75 unlock(&procalloc); 76 break; 77 } 78 up->mach = nil; 79 up = nil; 80 } 81 sched(); 82 } 83 84 void 85 sched(void) 86 { 87 if(up) { 88 splhi(); 89 procsave(up); 90 if(setlabel(&up->sched)) { 91 /* procrestore(up); */ 92 spllo(); 93 return; 94 } 95 gotolabel(&m->sched); 96 } 97 up = runproc(); 98 up->state = Running; 99 up->mach = MACHP(m->machno); /* m might be a fixed address; use MACHP */ 100 m->proc = up; 101 gotolabel(&up->sched); 102 } 103 104 void 105 ready(Proc *p) 106 { 107 int s; 108 Schedq *rq; 109 110 s = splhi(); 111 /* 112 if(edfready(p)){ 113 splx(s); 114 return; 115 } 116 */ 117 rq = &runq[p->pri]; 118 lock(runq); 119 p->rnext = 0; 120 if(rq->tail) 121 rq->tail->rnext = p; 122 else 123 rq->head = p; 124 rq->tail = p; 125 126 nrdy++; 127 occupied |= 1<<p->pri; 128 p->state = Ready; 129 unlock(runq); 130 splx(s); 131 } 132 133 int 134 anyready(void) 135 { 136 /* same priority only */ 137 return occupied & (1<<up->pri); 138 } 139 140 int 141 anyhigher(void) 142 { 143 return occupied & ((1<<up->pri)-1); 144 } 145 146 int 147 preemption(int tick) 148 { 149 if(up != nil && up->state == Running && !up->preempted && 150 (anyhigher() || tick && anyready())){ 151 up->preempted = 1; 152 sched(); 153 splhi(); 154 up->preempted = 0; 155 return 1; 156 } 157 return 0; 158 } 159 160 Proc* 161 runproc(void) 162 { 163 Proc *p, *l; 164 Schedq *rq, *erq; 165 166 erq = runq + Nrq - 1; 167 loop: 168 splhi(); 169 for(rq = runq; rq->head == 0; rq++) 170 if(rq >= erq) { 171 idlehands(); 172 spllo(); 173 goto loop; 174 } 175 176 if(!canlock(runq)) 177 goto loop; 178 /* choose first one we last ran on this processor at this level or hasn't moved recently */ 179 l = nil; 180 for(p = rq->head; p != nil; p = p->rnext) 181 if(p->mp == nil || p->mp == MACHP(m->machno) || p->movetime < MACHP(0)->ticks) 182 break; 183 if(p == nil) 184 p = rq->head; 185 /* p->mach==0 only when process state is saved */ 186 if(p == 0 || p->mach) { 187 unlock(runq); 188 goto loop; 189 } 190 if(p->rnext == nil) 191 rq->tail = l; 192 if(l) 193 l->rnext = p->rnext; 194 else 195 rq->head = p->rnext; 196 if(rq->head == nil){ 197 rq->tail = nil; 198 occupied &= ~(1<<p->pri); 199 } 200 nrdy--; 201 if(p->dbgstop){ 202 p->state = Stopped; 203 unlock(runq); 204 goto loop; 205 } 206 if(p->state != Ready) 207 print("runproc %s %lud %s\n", p->text, p->pid, statename[p->state]); 208 unlock(runq); 209 p->state = Scheding; 210 if(p->mp != MACHP(m->machno)) 211 p->movetime = MACHP(0)->ticks + HZ/10; 212 p->mp = MACHP(m->machno); 213 214 /* 215 if(edflock(p)){ 216 edfrun(p, rq == &runq[PriEdf]); // start deadline timer and do admin 217 edfunlock(); 218 } 219 */ 220 return p; 221 } 222 223 int 224 setpri(int pri) 225 { 226 int p; 227 228 /* called by up so not on run queue */ 229 p = up->pri; 230 up->pri = pri; 231 if(up->state == Running && anyhigher()) 232 sched(); 233 return p; 234 } 235 236 Proc* 237 newproc(void) 238 { 239 Proc *p; 240 241 lock(&procalloc); 242 for(;;) { 243 if(p = procalloc.free) 244 break; 245 246 unlock(&procalloc); 247 resrcwait("no procs"); 248 lock(&procalloc); 249 } 250 procalloc.free = p->qnext; 251 unlock(&procalloc); 252 253 p->type = Unknown; 254 p->state = Scheding; 255 p->pri = PriNormal; 256 p->psstate = "New"; 257 p->mach = 0; 258 p->qnext = 0; 259 p->fpstate = FPINIT; 260 p->kp = 0; 261 p->killed = 0; 262 p->swipend = 0; 263 p->mp = 0; 264 p->movetime = 0; 265 p->delaysched = 0; 266 p->edf = nil; 267 memset(&p->defenv, 0, sizeof(p->defenv)); 268 p->env = &p->defenv; 269 p->dbgreg = 0; 270 kstrdup(&p->env->user, "*nouser"); 271 p->env->errstr = p->env->errbuf0; 272 p->env->syserrstr = p->env->errbuf1; 273 274 p->pid = incref(&pidalloc); 275 if(p->pid == 0) 276 panic("pidalloc"); 277 if(p->kstack == 0) 278 p->kstack = smalloc(KSTACK); 279 addprog(p); 280 281 return p; 282 } 283 284 void 285 procinit(void) 286 { 287 Proc *p; 288 int i; 289 290 procalloc.free = xalloc(conf.nproc*sizeof(Proc)); 291 procalloc.arena = procalloc.free; 292 293 p = procalloc.free; 294 for(i=0; i<conf.nproc-1; i++,p++) 295 p->qnext = p+1; 296 p->qnext = 0; 297 298 debugkey('p', "processes", procdump, 0); 299 } 300 301 void 302 sleep(Rendez *r, int (*f)(void*), void *arg) 303 { 304 int s; 305 306 if(up == nil) 307 panic("sleep() not in process (%lux)", getcallerpc(&r)); 308 /* 309 * spl is to allow lock to be called 310 * at interrupt time. lock is mutual exclusion 311 */ 312 s = splhi(); 313 314 lock(&up->rlock); 315 lock(r); 316 317 /* 318 * if killed or condition happened, never mind 319 */ 320 if(up->killed || f(arg)){ 321 unlock(r); 322 }else{ 323 324 /* 325 * now we are committed to 326 * change state and call scheduler 327 */ 328 if(r->p != nil) { 329 print("double sleep pc=0x%lux %lud %lud r=0x%lux\n", getcallerpc(&r), r->p->pid, up->pid, r); 330 dumpstack(); 331 panic("sleep"); 332 } 333 up->state = Wakeme; 334 r->p = up; 335 unlock(r); 336 up->swipend = 0; 337 up->r = r; /* for swiproc */ 338 unlock(&up->rlock); 339 340 sched(); 341 splhi(); /* sched does spllo */ 342 343 lock(&up->rlock); 344 up->r = nil; 345 } 346 347 if(up->killed || up->swipend) { 348 up->killed = 0; 349 up->swipend = 0; 350 unlock(&up->rlock); 351 splx(s); 352 error(Eintr); 353 } 354 unlock(&up->rlock); 355 splx(s); 356 } 357 358 int 359 tfn(void *arg) 360 { 361 return MACHP(0)->ticks >= up->twhen || (*up->tfn)(arg); 362 } 363 364 void 365 tsleep(Rendez *r, int (*fn)(void*), void *arg, int ms) 366 { 367 ulong when; 368 Proc *f, **l; 369 370 if(up == nil) 371 panic("tsleep() not in process (0x%lux)", getcallerpc(&r)); 372 373 when = MS2TK(ms)+MACHP(0)->ticks; 374 lock(&talarm); 375 /* take out of list if checkalarm didn't */ 376 if(up->trend) { 377 l = &talarm.list; 378 for(f = *l; f; f = f->tlink) { 379 if(f == up) { 380 *l = up->tlink; 381 break; 382 } 383 l = &f->tlink; 384 } 385 } 386 /* insert in increasing time order */ 387 l = &talarm.list; 388 for(f = *l; f; f = f->tlink) { 389 if(f->twhen >= when) 390 break; 391 l = &f->tlink; 392 } 393 up->trend = r; 394 up->twhen = when; 395 up->tfn = fn; 396 up->tlink = *l; 397 *l = up; 398 unlock(&talarm); 399 400 if(waserror()){ 401 up->twhen = 0; 402 nexterror(); 403 } 404 sleep(r, tfn, arg); 405 up->twhen = 0; 406 poperror(); 407 } 408 409 int 410 wakeup(Rendez *r) 411 { 412 Proc *p; 413 int s; 414 415 s = splhi(); 416 lock(r); 417 p = r->p; 418 if(p){ 419 r->p = nil; 420 if(p->state != Wakeme) 421 panic("wakeup: state"); 422 ready(p); 423 } 424 unlock(r); 425 splx(s); 426 return p != nil; 427 } 428 429 void 430 swiproc(Proc *p, int interp) 431 { 432 ulong s; 433 Rendez *r; 434 435 if(p == nil) 436 return; 437 438 s = splhi(); 439 lock(&p->rlock); 440 if(!interp) 441 p->killed = 1; 442 r = p->r; 443 if(r != nil) { 444 lock(r); 445 if(r->p == p){ 446 p->swipend = 1; 447 r->p = nil; 448 ready(p); 449 } 450 unlock(r); 451 } 452 unlock(&p->rlock); 453 splx(s); 454 } 455 456 void 457 notkilled(void) 458 { 459 lock(&up->rlock); 460 up->killed = 0; 461 unlock(&up->rlock); 462 } 463 464 void 465 pexit(char*, int) 466 { 467 Osenv *o; 468 469 up->alarm = 0; 470 471 o = up->env; 472 if(o != nil){ 473 closefgrp(o->fgrp); 474 closepgrp(o->pgrp); 475 closeegrp(o->egrp); 476 closesigs(o->sigs); 477 } 478 479 /* Sched must not loop for this lock */ 480 lock(&procalloc); 481 482 /* 483 edfstop(up); 484 */ 485 up->state = Moribund; 486 sched(); 487 panic("pexit"); 488 } 489 490 Proc* 491 proctab(int i) 492 { 493 return &procalloc.arena[i]; 494 } 495 496 void 497 procdump(void) 498 { 499 int i; 500 char *s; 501 Proc *p; 502 char tmp[14]; 503 504 for(i=0; i<conf.nproc; i++) { 505 p = &procalloc.arena[i]; 506 if(p->state == Dead) 507 continue; 508 509 s = p->psstate; 510 if(s == nil) 511 s = "kproc"; 512 if(p->state == Wakeme) 513 snprint(tmp, sizeof(tmp), " /%.8lux", p->r); 514 else 515 *tmp = '\0'; 516 print("%lux:%3lud:%14s pc %.8lux %s/%s qpc %.8lux pri %d%s\n", 517 p, p->pid, p->text, p->pc, s, statename[p->state], p->qpc, p->pri, tmp); 518 } 519 } 520 521 void 522 kproc(char *name, void (*func)(void *), void *arg, int flags) 523 { 524 Proc *p; 525 Pgrp *pg; 526 Fgrp *fg; 527 Egrp *eg; 528 529 p = newproc(); 530 p->psstate = 0; 531 p->kp = 1; 532 533 p->fpsave = up->fpsave; 534 p->scallnr = up->scallnr; 535 p->nerrlab = 0; 536 537 kstrdup(&p->env->user, up->env->user); 538 if(flags & KPDUPPG) { 539 pg = up->env->pgrp; 540 incref(pg); 541 p->env->pgrp = pg; 542 } 543 if(flags & KPDUPFDG) { 544 fg = up->env->fgrp; 545 incref(fg); 546 p->env->fgrp = fg; 547 } 548 if(flags & KPDUPENVG) { 549 eg = up->env->egrp; 550 if(eg != nil) 551 incref(eg); 552 p->env->egrp = eg; 553 } 554 555 kprocchild(p, func, arg); 556 557 strcpy(p->text, name); 558 559 ready(p); 560 } 561 562 void 563 errorf(char *fmt, ...) 564 { 565 va_list arg; 566 char buf[PRINTSIZE]; 567 568 va_start(arg, fmt); 569 vseprint(buf, buf+sizeof(buf), fmt, arg); 570 va_end(arg); 571 error(buf); 572 } 573 574 void 575 error(char *err) 576 { 577 if(up == nil) 578 panic("error(%s) not in a process", err); 579 spllo(); 580 if(up->nerrlab > NERR) 581 panic("error stack too deep"); 582 if(err != up->env->errstr) 583 kstrcpy(up->env->errstr, err, ERRMAX); 584 setlabel(&up->errlab[NERR-1]); 585 nexterror(); 586 } 587 588 #include "errstr.h" 589 590 /* Set kernel error string */ 591 void 592 kerrstr(char *err, uint size) 593 { 594 595 char tmp[ERRMAX]; 596 597 kstrcpy(tmp, up->env->errstr, sizeof(tmp)); 598 kstrcpy(up->env->errstr, err, ERRMAX); 599 kstrcpy(err, tmp, size); 600 } 601 602 /* Get kernel error string */ 603 void 604 kgerrstr(char *err, uint size) 605 { 606 char tmp[ERRMAX]; 607 608 kstrcpy(tmp, up->env->errstr, sizeof(tmp)); 609 kstrcpy(up->env->errstr, err, ERRMAX); 610 kstrcpy(err, tmp, size); 611 } 612 613 /* Set kernel error string, using formatted print */ 614 void 615 kwerrstr(char *fmt, ...) 616 { 617 va_list arg; 618 char buf[ERRMAX]; 619 620 va_start(arg, fmt); 621 vseprint(buf, buf+sizeof(buf), fmt, arg); 622 va_end(arg); 623 kstrcpy(up->env->errstr, buf, ERRMAX); 624 } 625 626 void 627 werrstr(char *fmt, ...) 628 { 629 va_list arg; 630 char buf[ERRMAX]; 631 632 va_start(arg, fmt); 633 vseprint(buf, buf+sizeof(buf), fmt, arg); 634 va_end(arg); 635 kstrcpy(up->env->errstr, buf, ERRMAX); 636 } 637 638 void 639 nexterror(void) 640 { 641 gotolabel(&up->errlab[--up->nerrlab]); 642 } 643 644 /* for dynamic modules - functions not macros */ 645 646 void* 647 waserr(void) 648 { 649 up->nerrlab++; 650 return &up->errlab[up->nerrlab-1]; 651 } 652 653 void 654 poperr(void) 655 { 656 up->nerrlab--; 657 } 658 659 char* 660 enverror(void) 661 { 662 return up->env->errstr; 663 } 664 665 void 666 exhausted(char *resource) 667 { 668 char buf[64]; 669 670 snprint(buf, sizeof(buf), "no free %s", resource); 671 iprint("%s\n", buf); 672 error(buf); 673 } 674 675 /* 676 * change ownership to 'new' of all processes owned by 'old'. Used when 677 * eve changes. 678 */ 679 void 680 renameuser(char *old, char *new) 681 { 682 Proc *p, *ep; 683 Osenv *o; 684 685 ep = procalloc.arena+conf.nproc; 686 for(p = procalloc.arena; p < ep; p++) { 687 o = &p->defenv; 688 if(o->user != nil && strcmp(o->user, old) == 0) 689 kstrdup(&o->user, new); 690 } 691 } 692 693 int 694 return0(void*) 695 { 696 return 0; 697 } 698 699 void 700 setid(char *name, int owner) 701 { 702 if(!owner || iseve()) 703 kstrdup(&up->env->user, name); 704 } 705 706 void 707 rptwakeup(void *o, void *ar) 708 { 709 Rept *r; 710 711 r = ar; 712 if(r == nil) 713 return; 714 lock(&r->l); 715 r->o = o; 716 unlock(&r->l); 717 wakeup(&r->r); 718 } 719 720 static int 721 rptactive(void *a) 722 { 723 Rept *r = a; 724 int i; 725 lock(&r->l); 726 i = r->active(r->o); 727 unlock(&r->l); 728 return i; 729 } 730 731 static void 732 rproc(void *a) 733 { 734 long now, then; 735 ulong t; 736 int i; 737 void *o; 738 Rept *r; 739 740 r = a; 741 t = r->t; 742 743 Wait: 744 sleep(&r->r, rptactive, r); 745 lock(&r->l); 746 o = r->o; 747 unlock(&r->l); 748 then = TK2MS(MACHP(0)->ticks); 749 for(;;){ 750 tsleep(&up->sleep, return0, nil, t); 751 now = TK2MS(MACHP(0)->ticks); 752 if(waserror()) 753 break; 754 i = r->ck(o, now-then); 755 poperror(); 756 if(i == -1) 757 goto Wait; 758 if(i == 0) 759 continue; 760 then = now; 761 acquire(); 762 if(waserror()) { 763 release(); 764 break; 765 } 766 r->f(o); 767 poperror(); 768 release(); 769 } 770 pexit("", 0); 771 } 772 773 void* 774 rptproc(char *s, int t, void *o, int (*active)(void*), int (*ck)(void*, int), void (*f)(void*)) 775 { 776 Rept *r; 777 778 r = mallocz(sizeof(Rept), 1); 779 if(r == nil) 780 return nil; 781 r->t = t; 782 r->active = active; 783 r->ck = ck; 784 r->f = f; 785 r->o = o; 786 kproc(s, rproc, r, KPDUP); 787 return r; 788 } 789