| tthread.c - plan9port - [fork] Plan 9 from user space | |
| git clone git://src.adamsgaard.dk/plan9port | |
| Log | |
| Files | |
| Refs | |
| README | |
| LICENSE | |
| --- | |
| tthread.c (16472B) | |
| --- | |
| 1 #include "threadimpl.h" | |
| 2 | |
| 3 int _threaddebuglevel = 0; | |
| 4 | |
| 5 static uint threadnproc; | |
| 6 static uint threadnsysproc; | |
| 7 static Lock threadnproclock; | |
| 8 static Ref threadidref; | |
| 9 static Proc *threadmainproc; | |
| 10 | |
| 11 static void addproc(Proc*); | |
| 12 static void delproc(Proc*); | |
| 13 static void addthread(_Threadlist*, _Thread*); | |
| 14 static void delthread(_Threadlist*, _Thread*); | |
| 15 static int onlist(_Threadlist*, _Thread*); | |
| 16 static void addthreadinproc(Proc*, _Thread*); | |
| 17 static void delthreadinproc(Proc*, _Thread*); | |
| 18 static void procmain(Proc*); | |
| 19 static int threadinfo(void*, char*); | |
| 20 static void pthreadscheduler(Proc *p); | |
| 21 static void pthreadsleepschedlocked(Proc *p, _Thre… | |
| 22 static void pthreadwakeupschedlocked(Proc *p, _Thr… | |
| 23 static _Thread* procnext(Proc*, _Thread*); | |
| 24 | |
| 25 static void | |
| 26 _threaddebug(_Thread *t, char *fmt, ...) | |
| 27 { | |
| 28 va_list arg; | |
| 29 char buf[128]; | |
| 30 char *p; | |
| 31 static int fd = -1; | |
| 32 | |
| 33 if(_threaddebuglevel == 0) | |
| 34 return; | |
| 35 | |
| 36 if(fd < 0){ | |
| 37 p = strrchr(argv0, '/'); | |
| 38 if(p) | |
| 39 p++; | |
| 40 else | |
| 41 p = argv0; | |
| 42 snprint(buf, sizeof buf, "/tmp/%s.tlog", p); | |
| 43 if((fd = create(buf, OWRITE, 0666)) < 0) | |
| 44 fd = open("/dev/null", OWRITE); | |
| 45 if(fd >= 0 && fd != 2){ | |
| 46 dup(fd, 2); | |
| 47 close(fd); | |
| 48 fd = 2; | |
| 49 } | |
| 50 } | |
| 51 | |
| 52 va_start(arg, fmt); | |
| 53 vsnprint(buf, sizeof buf, fmt, arg); | |
| 54 va_end(arg); | |
| 55 if(t == nil) | |
| 56 t = proc()->thread; | |
| 57 if(t) | |
| 58 fprint(fd, "%p %d.%d: %s\n", proc(), getpid(), t->id, bu… | |
| 59 else | |
| 60 fprint(fd, "%p %d._: %s\n", proc(), getpid(), buf); | |
| 61 } | |
| 62 | |
| 63 static _Thread* | |
| 64 getthreadnow(void) | |
| 65 { | |
| 66 return proc()->thread; | |
| 67 } | |
| 68 _Thread *(*threadnow)(void) = getthreadnow; | |
| 69 | |
| 70 static Proc* | |
| 71 procalloc(void) | |
| 72 { | |
| 73 Proc *p; | |
| 74 | |
| 75 p = malloc(sizeof *p); | |
| 76 if(p == nil) | |
| 77 sysfatal("procalloc malloc: %r"); | |
| 78 memset(p, 0, sizeof *p); | |
| 79 addproc(p); | |
| 80 lock(&threadnproclock); | |
| 81 threadnproc++; | |
| 82 unlock(&threadnproclock); | |
| 83 return p; | |
| 84 } | |
| 85 | |
| 86 _Thread* | |
| 87 _threadcreate(Proc *p, void (*fn)(void*), void *arg, uint stack) | |
| 88 { | |
| 89 _Thread *t; | |
| 90 | |
| 91 USED(stack); | |
| 92 t = malloc(sizeof *t); | |
| 93 if(t == nil) | |
| 94 sysfatal("threadcreate malloc: %r"); | |
| 95 memset(t, 0, sizeof *t); | |
| 96 t->id = incref(&threadidref); | |
| 97 t->startfn = fn; | |
| 98 t->startarg = arg; | |
| 99 t->proc = p; | |
| 100 if(p->nthread != 0) | |
| 101 _threadpthreadstart(p, t); | |
| 102 else | |
| 103 t->mainthread = 1; | |
| 104 p->nthread++; | |
| 105 addthreadinproc(p, t); | |
| 106 _threadready(t); | |
| 107 return t; | |
| 108 } | |
| 109 | |
| 110 int | |
| 111 threadcreate(void (*fn)(void*), void *arg, uint stack) | |
| 112 { | |
| 113 _Thread *t; | |
| 114 | |
| 115 t = _threadcreate(proc(), fn, arg, stack); | |
| 116 _threaddebug(nil, "threadcreate %d", t->id); | |
| 117 return t->id; | |
| 118 } | |
| 119 | |
| 120 int | |
| 121 proccreate(void (*fn)(void*), void *arg, uint stack) | |
| 122 { | |
| 123 int id; | |
| 124 _Thread *t; | |
| 125 Proc *p; | |
| 126 | |
| 127 p = procalloc(); | |
| 128 t = _threadcreate(p, fn, arg, stack); | |
| 129 id = t->id; /* t might be freed after _procstart */ | |
| 130 _threaddebug(t, "proccreate %p", p); | |
| 131 _procstart(p, procmain); | |
| 132 return id; | |
| 133 } | |
| 134 | |
| 135 void | |
| 136 _threadswitch(void) | |
| 137 { | |
| 138 Proc *p; | |
| 139 | |
| 140 needstack(0); | |
| 141 p = proc(); | |
| 142 /*print("threadswtch %p\n", p); */ | |
| 143 pthreadscheduler(p); | |
| 144 } | |
| 145 | |
| 146 void | |
| 147 _threadready(_Thread *t) | |
| 148 { | |
| 149 Proc *p; | |
| 150 | |
| 151 p = t->proc; | |
| 152 lock(&p->lock); | |
| 153 p->runrend.l = &p->lock; | |
| 154 addthread(&p->runqueue, t); | |
| 155 /*print("%d wake for job %d->%d\n", time(0), getpid(), p->osprocid); */ | |
| 156 if(p != proc()) | |
| 157 _procwakeupandunlock(&p->runrend); | |
| 158 else | |
| 159 unlock(&p->lock); | |
| 160 } | |
| 161 | |
| 162 int | |
| 163 threadidle(void) | |
| 164 { | |
| 165 int n; | |
| 166 Proc *p; | |
| 167 | |
| 168 p = proc(); | |
| 169 n = p->nswitch; | |
| 170 lock(&p->lock); | |
| 171 p->runrend.l = &p->lock; | |
| 172 addthread(&p->idlequeue, p->thread); | |
| 173 unlock(&p->lock); | |
| 174 _threadswitch(); | |
| 175 return p->nswitch - n; | |
| 176 } | |
| 177 | |
| 178 int | |
| 179 threadyield(void) | |
| 180 { | |
| 181 int n; | |
| 182 Proc *p; | |
| 183 | |
| 184 p = proc(); | |
| 185 n = p->nswitch; | |
| 186 _threadready(p->thread); | |
| 187 _threadswitch(); | |
| 188 return p->nswitch - n; | |
| 189 } | |
| 190 | |
| 191 void | |
| 192 threadexits(char *msg) | |
| 193 { | |
| 194 Proc *p; | |
| 195 | |
| 196 p = proc(); | |
| 197 if(msg == nil) | |
| 198 msg = ""; | |
| 199 utfecpy(p->msg, p->msg+sizeof p->msg, msg); | |
| 200 proc()->thread->exiting = 1; | |
| 201 _threadswitch(); | |
| 202 } | |
| 203 | |
| 204 void | |
| 205 threadpin(void) | |
| 206 { | |
| 207 Proc *p; | |
| 208 | |
| 209 p = proc(); | |
| 210 if(p->pinthread){ | |
| 211 fprint(2, "already pinning a thread - %p %p\n", p->pinth… | |
| 212 assert(0); | |
| 213 } | |
| 214 p->pinthread = p->thread; | |
| 215 } | |
| 216 | |
| 217 void | |
| 218 threadunpin(void) | |
| 219 { | |
| 220 Proc *p; | |
| 221 | |
| 222 p = proc(); | |
| 223 if(p->pinthread != p->thread){ | |
| 224 fprint(2, "wrong pinthread - %p %p\n", p->pinthread, p->… | |
| 225 assert(0); | |
| 226 } | |
| 227 p->pinthread = nil; | |
| 228 } | |
| 229 | |
| 230 void | |
| 231 threadsysfatal(char *fmt, va_list arg) | |
| 232 { | |
| 233 char buf[256]; | |
| 234 | |
| 235 vseprint(buf, buf+sizeof(buf), fmt, arg); | |
| 236 __fixargv0(); | |
| 237 fprint(2, "%s: %s\n", argv0 ? argv0 : "<prog>", buf); | |
| 238 threadexitsall(buf); | |
| 239 } | |
| 240 | |
| 241 static void | |
| 242 procmain(Proc *p) | |
| 243 { | |
| 244 _Thread *t; | |
| 245 | |
| 246 _threadsetproc(p); | |
| 247 | |
| 248 /* take out first thread to run on system stack */ | |
| 249 t = p->runqueue.head; | |
| 250 delthread(&p->runqueue, t); | |
| 251 | |
| 252 /* run it */ | |
| 253 p->thread = t; | |
| 254 t->startfn(t->startarg); | |
| 255 if(p->nthread != 0) | |
| 256 threadexits(nil); | |
| 257 } | |
| 258 | |
| 259 void | |
| 260 _threadpthreadmain(Proc *p, _Thread *t) | |
| 261 { | |
| 262 _threadsetproc(p); | |
| 263 lock(&p->lock); | |
| 264 pthreadsleepschedlocked(p, t); | |
| 265 unlock(&p->lock); | |
| 266 _threaddebug(nil, "startfn"); | |
| 267 t->startfn(t->startarg); | |
| 268 threadexits(nil); | |
| 269 } | |
| 270 | |
| 271 static void | |
| 272 pthreadsleepschedlocked(Proc *p, _Thread *t) | |
| 273 { | |
| 274 _threaddebug(t, "pthreadsleepsched %p %d", p, t->id);; | |
| 275 t->schedrend.l = &p->lock; | |
| 276 while(p->schedthread != t) | |
| 277 _procsleep(&t->schedrend); | |
| 278 } | |
| 279 | |
| 280 static void | |
| 281 pthreadwakeupschedlocked(Proc *p, _Thread *self, _Thread *t) | |
| 282 { | |
| 283 _threaddebug(self, "pthreadwakeupschedlocked %p %d", p, t->id);; | |
| 284 t->schedrend.l = &p->lock; | |
| 285 p->schedthread = t; | |
| 286 _procwakeup(&t->schedrend); | |
| 287 } | |
| 288 | |
| 289 static void | |
| 290 pthreadscheduler(Proc *p) | |
| 291 { | |
| 292 _Thread *self, *t; | |
| 293 | |
| 294 _threaddebug(nil, "scheduler"); | |
| 295 lock(&p->lock); | |
| 296 self = p->thread; | |
| 297 p->thread = nil; | |
| 298 _threaddebug(self, "pausing"); | |
| 299 | |
| 300 if(self->exiting) { | |
| 301 _threaddebug(self, "exiting"); | |
| 302 delthreadinproc(p, self); | |
| 303 p->nthread--; | |
| 304 } | |
| 305 | |
| 306 t = procnext(p, self); | |
| 307 if(t != nil) { | |
| 308 pthreadwakeupschedlocked(p, self, t); | |
| 309 if(!self->exiting) { | |
| 310 pthreadsleepschedlocked(p, self); | |
| 311 _threaddebug(nil, "resume %d", self->id); | |
| 312 unlock(&p->lock); | |
| 313 return; | |
| 314 } | |
| 315 } | |
| 316 | |
| 317 if(t == nil) { | |
| 318 /* Tear down proc bookkeeping. Wait to free p. */ | |
| 319 delproc(p); | |
| 320 lock(&threadnproclock); | |
| 321 if(p->sysproc) | |
| 322 --threadnsysproc; | |
| 323 if(--threadnproc == threadnsysproc) | |
| 324 threadexitsall(p->msg); | |
| 325 unlock(&threadnproclock); | |
| 326 } | |
| 327 | |
| 328 /* Tear down pthread. */ | |
| 329 if(self->mainthread && p->mainproc) { | |
| 330 _threaddaemonize(); | |
| 331 _threaddebug(self, "sleeper"); | |
| 332 unlock(&p->lock); | |
| 333 /* | |
| 334 * Avoid bugs with main pthread exiting. | |
| 335 * When all procs are gone, threadexitsall above will ha… | |
| 336 */ | |
| 337 for(;;) | |
| 338 sleep(60*60*1000); | |
| 339 } | |
| 340 _threadsetproc(nil); | |
| 341 free(self); | |
| 342 unlock(&p->lock); | |
| 343 if(t == nil) | |
| 344 free(p); | |
| 345 _threadpexit(); | |
| 346 } | |
| 347 | |
| 348 static _Thread* | |
| 349 procnext(Proc *p, _Thread *self) | |
| 350 { | |
| 351 _Thread *t; | |
| 352 | |
| 353 if((t = p->pinthread) != nil){ | |
| 354 while(!onlist(&p->runqueue, t)){ | |
| 355 p->runrend.l = &p->lock; | |
| 356 _threaddebug(self, "scheduler sleep (pin)"); | |
| 357 _procsleep(&p->runrend); | |
| 358 _threaddebug(self, "scheduler wake (pin)"); | |
| 359 } | |
| 360 } else | |
| 361 while((t = p->runqueue.head) == nil){ | |
| 362 if(p->nthread == 0) | |
| 363 return nil; | |
| 364 if((t = p->idlequeue.head) != nil){ | |
| 365 /* | |
| 366 * Run all the idling threads once. | |
| 367 */ | |
| 368 while((t = p->idlequeue.head) != nil){ | |
| 369 delthread(&p->idlequeue, t); | |
| 370 addthread(&p->runqueue, t); | |
| 371 } | |
| 372 continue; | |
| 373 } | |
| 374 p->runrend.l = &p->lock; | |
| 375 _threaddebug(self, "scheduler sleep"); | |
| 376 _procsleep(&p->runrend); | |
| 377 _threaddebug(self, "scheduler wake"); | |
| 378 } | |
| 379 | |
| 380 if(p->pinthread && p->pinthread != t) | |
| 381 fprint(2, "p->pinthread %p t %p\n", p->pinthread, t); | |
| 382 assert(p->pinthread == nil || p->pinthread == t); | |
| 383 delthread(&p->runqueue, t); | |
| 384 | |
| 385 p->thread = t; | |
| 386 p->nswitch++; | |
| 387 return t; | |
| 388 } | |
| 389 | |
| 390 void | |
| 391 _threadsetsysproc(void) | |
| 392 { | |
| 393 lock(&threadnproclock); | |
| 394 if(++threadnsysproc == threadnproc) | |
| 395 threadexitsall(nil); | |
| 396 unlock(&threadnproclock); | |
| 397 proc()->sysproc = 1; | |
| 398 } | |
| 399 | |
| 400 void** | |
| 401 procdata(void) | |
| 402 { | |
| 403 return &proc()->udata; | |
| 404 } | |
| 405 | |
| 406 void** | |
| 407 threaddata(void) | |
| 408 { | |
| 409 return &proc()->thread->udata; | |
| 410 } | |
| 411 | |
| 412 extern Jmp *(*_notejmpbuf)(void); | |
| 413 static Jmp* | |
| 414 threadnotejmp(void) | |
| 415 { | |
| 416 return &proc()->sigjmp; | |
| 417 } | |
| 418 | |
| 419 /* | |
| 420 * debugging | |
| 421 */ | |
| 422 void | |
| 423 threadsetname(char *fmt, ...) | |
| 424 { | |
| 425 va_list arg; | |
| 426 _Thread *t; | |
| 427 | |
| 428 t = proc()->thread; | |
| 429 va_start(arg, fmt); | |
| 430 vsnprint(t->name, sizeof t->name, fmt, arg); | |
| 431 va_end(arg); | |
| 432 } | |
| 433 | |
| 434 char* | |
| 435 threadgetname(void) | |
| 436 { | |
| 437 return proc()->thread->name; | |
| 438 } | |
| 439 | |
| 440 void | |
| 441 threadsetstate(char *fmt, ...) | |
| 442 { | |
| 443 va_list arg; | |
| 444 _Thread *t; | |
| 445 | |
| 446 t = proc()->thread; | |
| 447 va_start(arg, fmt); | |
| 448 vsnprint(t->state, sizeof t->name, fmt, arg); | |
| 449 va_end(arg); | |
| 450 } | |
| 451 | |
| 452 int | |
| 453 threadid(void) | |
| 454 { | |
| 455 _Thread *t; | |
| 456 | |
| 457 t = proc()->thread; | |
| 458 return t->id; | |
| 459 } | |
| 460 | |
| 461 void | |
| 462 needstack(int n) | |
| 463 { | |
| 464 _Thread *t; | |
| 465 | |
| 466 t = proc()->thread; | |
| 467 if(t->stk == nil) | |
| 468 return; | |
| 469 | |
| 470 if((char*)&t <= (char*)t->stk | |
| 471 || (char*)&t - (char*)t->stk < 256+n){ | |
| 472 fprint(2, "thread stack overflow: &t=%p tstk=%p n=%d\n",… | |
| 473 abort(); | |
| 474 } | |
| 475 } | |
| 476 | |
| 477 static int | |
| 478 singlethreaded(void) | |
| 479 { | |
| 480 return threadnproc == 1 && _threadprocs->nthread == 1; | |
| 481 } | |
| 482 | |
| 483 /* | |
| 484 * locking | |
| 485 */ | |
| 486 static int | |
| 487 threadqlock(QLock *l, int block, ulong pc) | |
| 488 { | |
| 489 /*print("threadqlock %p\n", l); */ | |
| 490 lock(&l->l); | |
| 491 if(l->owner == nil){ | |
| 492 l->owner = (*threadnow)(); | |
| 493 /*print("qlock %p @%#x by %p\n", l, pc, l->owner); */ | |
| 494 if(l->owner == nil) { | |
| 495 fprint(2, "%s: qlock uncontended owner=nil oops\… | |
| 496 abort(); | |
| 497 } | |
| 498 unlock(&l->l); | |
| 499 return 1; | |
| 500 } | |
| 501 if(!block){ | |
| 502 unlock(&l->l); | |
| 503 return 0; | |
| 504 } | |
| 505 | |
| 506 if(singlethreaded()){ | |
| 507 fprint(2, "qlock deadlock\n"); | |
| 508 abort(); | |
| 509 } | |
| 510 | |
| 511 /*print("qsleep %p @%#x by %p\n", l, pc, (*threadnow)()); */ | |
| 512 addthread(&l->waiting, (*threadnow)()); | |
| 513 unlock(&l->l); | |
| 514 | |
| 515 _threadswitch(); | |
| 516 | |
| 517 if(l->owner != (*threadnow)()){ | |
| 518 fprint(2, "%s: qlock pc=0x%lux owner=%p self=%p oops\n", | |
| 519 argv0, pc, l->owner, (*threadnow)()); | |
| 520 abort(); | |
| 521 } | |
| 522 if(l->owner == nil) { | |
| 523 fprint(2, "%s: qlock threadswitch owner=nil oops\n", arg… | |
| 524 abort(); | |
| 525 } | |
| 526 | |
| 527 /*print("qlock wakeup %p @%#x by %p\n", l, pc, (*threadnow)()); */ | |
| 528 return 1; | |
| 529 } | |
| 530 | |
| 531 static void | |
| 532 threadqunlock(QLock *l, ulong pc) | |
| 533 { | |
| 534 _Thread *ready; | |
| 535 | |
| 536 lock(&l->l); | |
| 537 /*print("qlock unlock %p @%#x by %p (owner %p)\n", l, pc, (*threadnow)()… | |
| 538 if(l->owner == 0){ | |
| 539 fprint(2, "%s: qunlock pc=0x%lux owner=%p self=%p oops\n… | |
| 540 argv0, pc, l->owner, (*threadnow)()); | |
| 541 abort(); | |
| 542 } | |
| 543 if((l->owner = ready = l->waiting.head) != nil) | |
| 544 delthread(&l->waiting, l->owner); | |
| 545 /* | |
| 546 * N.B. Cannot call _threadready() before unlocking l->l, | |
| 547 * because the thread we are readying might: | |
| 548 * - be in another proc | |
| 549 * - start running immediately | |
| 550 * - and free l before we get a chance to run again | |
| 551 */ | |
| 552 unlock(&l->l); | |
| 553 if(ready) | |
| 554 _threadready(l->owner); | |
| 555 } | |
| 556 | |
| 557 static int | |
| 558 threadrlock(RWLock *l, int block, ulong pc) | |
| 559 { | |
| 560 USED(pc); | |
| 561 | |
| 562 lock(&l->l); | |
| 563 if(l->writer == nil && l->wwaiting.head == nil){ | |
| 564 l->readers++; | |
| 565 unlock(&l->l); | |
| 566 return 1; | |
| 567 } | |
| 568 if(!block){ | |
| 569 unlock(&l->l); | |
| 570 return 0; | |
| 571 } | |
| 572 if(singlethreaded()){ | |
| 573 fprint(2, "rlock deadlock\n"); | |
| 574 abort(); | |
| 575 } | |
| 576 addthread(&l->rwaiting, (*threadnow)()); | |
| 577 unlock(&l->l); | |
| 578 _threadswitch(); | |
| 579 return 1; | |
| 580 } | |
| 581 | |
| 582 static int | |
| 583 threadwlock(RWLock *l, int block, ulong pc) | |
| 584 { | |
| 585 USED(pc); | |
| 586 | |
| 587 lock(&l->l); | |
| 588 if(l->writer == nil && l->readers == 0){ | |
| 589 l->writer = (*threadnow)(); | |
| 590 unlock(&l->l); | |
| 591 return 1; | |
| 592 } | |
| 593 if(!block){ | |
| 594 unlock(&l->l); | |
| 595 return 0; | |
| 596 } | |
| 597 if(singlethreaded()){ | |
| 598 fprint(2, "wlock deadlock\n"); | |
| 599 abort(); | |
| 600 } | |
| 601 addthread(&l->wwaiting, (*threadnow)()); | |
| 602 unlock(&l->l); | |
| 603 _threadswitch(); | |
| 604 return 1; | |
| 605 } | |
| 606 | |
| 607 static void | |
| 608 threadrunlock(RWLock *l, ulong pc) | |
| 609 { | |
| 610 _Thread *t; | |
| 611 | |
| 612 USED(pc); | |
| 613 t = nil; | |
| 614 lock(&l->l); | |
| 615 --l->readers; | |
| 616 if(l->readers == 0 && (t = l->wwaiting.head) != nil){ | |
| 617 delthread(&l->wwaiting, t); | |
| 618 l->writer = t; | |
| 619 } | |
| 620 unlock(&l->l); | |
| 621 if(t) | |
| 622 _threadready(t); | |
| 623 | |
| 624 } | |
| 625 | |
| 626 static void | |
| 627 threadwunlock(RWLock *l, ulong pc) | |
| 628 { | |
| 629 _Thread *t; | |
| 630 | |
| 631 USED(pc); | |
| 632 lock(&l->l); | |
| 633 l->writer = nil; | |
| 634 assert(l->readers == 0); | |
| 635 while((t = l->rwaiting.head) != nil){ | |
| 636 delthread(&l->rwaiting, t); | |
| 637 l->readers++; | |
| 638 _threadready(t); | |
| 639 } | |
| 640 t = nil; | |
| 641 if(l->readers == 0 && (t = l->wwaiting.head) != nil){ | |
| 642 delthread(&l->wwaiting, t); | |
| 643 l->writer = t; | |
| 644 } | |
| 645 unlock(&l->l); | |
| 646 if(t) | |
| 647 _threadready(t); | |
| 648 } | |
| 649 | |
| 650 /* | |
| 651 * sleep and wakeup | |
| 652 */ | |
| 653 static void | |
| 654 threadrsleep(Rendez *r, ulong pc) | |
| 655 { | |
| 656 if(singlethreaded()){ | |
| 657 fprint(2, "rsleep deadlock\n"); | |
| 658 abort(); | |
| 659 } | |
| 660 addthread(&r->waiting, proc()->thread); | |
| 661 qunlock(r->l); | |
| 662 _threadswitch(); | |
| 663 qlock(r->l); | |
| 664 } | |
| 665 | |
| 666 static int | |
| 667 threadrwakeup(Rendez *r, int all, ulong pc) | |
| 668 { | |
| 669 int i; | |
| 670 _Thread *t; | |
| 671 | |
| 672 _threaddebug(nil, "rwakeup %p %d", r, all); | |
| 673 for(i=0;; i++){ | |
| 674 if(i==1 && !all) | |
| 675 break; | |
| 676 if((t = r->waiting.head) == nil) | |
| 677 break; | |
| 678 _threaddebug(nil, "rwakeup %p %d -> wake %d", r, all, t-… | |
| 679 delthread(&r->waiting, t); | |
| 680 _threadready(t); | |
| 681 _threaddebug(nil, "rwakeup %p %d -> loop", r, all); | |
| 682 } | |
| 683 _threaddebug(nil, "rwakeup %p %d -> total %d", r, all, i); | |
| 684 return i; | |
| 685 } | |
| 686 | |
| 687 /* | |
| 688 * startup | |
| 689 */ | |
| 690 | |
| 691 static int threadargc; | |
| 692 static char **threadargv; | |
| 693 int mainstacksize; | |
| 694 extern int _p9usepwlibrary; /* getgrgid etc. smash the stack - te… | |
| 695 static void | |
| 696 threadmainstart(void *v) | |
| 697 { | |
| 698 USED(v); | |
| 699 | |
| 700 /* | |
| 701 * N.B. This call to proc() is a program's first call (indirectl… | |
| 702 * pthreads function while executing on a non-pthreads-allocated | |
| 703 * stack. If the pthreads implementation is using the stack poi… | |
| 704 * to locate the per-thread data, then this call will blow up. | |
| 705 * This means the pthread implementation is not suitable for | |
| 706 * running under libthread. Time to write your own. Sorry. | |
| 707 */ | |
| 708 _p9usepwlibrary = 0; | |
| 709 threadmainproc = proc(); | |
| 710 threadmain(threadargc, threadargv); | |
| 711 } | |
| 712 | |
| 713 extern void (*_sysfatal)(char*, va_list); | |
| 714 | |
| 715 int | |
| 716 main(int argc, char **argv) | |
| 717 { | |
| 718 Proc *p; | |
| 719 _Thread *t; | |
| 720 char *opts; | |
| 721 | |
| 722 argv0 = argv[0]; | |
| 723 | |
| 724 opts = getenv("LIBTHREAD"); | |
| 725 if(opts == nil) | |
| 726 opts = ""; | |
| 727 | |
| 728 if(threadmaybackground() && strstr(opts, "nodaemon") == nil && g… | |
| 729 _threadsetupdaemonize(); | |
| 730 | |
| 731 threadargc = argc; | |
| 732 threadargv = argv; | |
| 733 | |
| 734 /* | |
| 735 * Install locking routines into C library. | |
| 736 */ | |
| 737 _lock = _threadlock; | |
| 738 _unlock = _threadunlock; | |
| 739 _qlock = threadqlock; | |
| 740 _qunlock = threadqunlock; | |
| 741 _rlock = threadrlock; | |
| 742 _runlock = threadrunlock; | |
| 743 _wlock = threadwlock; | |
| 744 _wunlock = threadwunlock; | |
| 745 _rsleep = threadrsleep; | |
| 746 _rwakeup = threadrwakeup; | |
| 747 _notejmpbuf = threadnotejmp; | |
| 748 _pin = threadpin; | |
| 749 _unpin = threadunpin; | |
| 750 _sysfatal = threadsysfatal; | |
| 751 | |
| 752 _pthreadinit(); | |
| 753 p = procalloc(); | |
| 754 p->mainproc = 1; | |
| 755 _threadsetproc(p); | |
| 756 if(mainstacksize == 0) | |
| 757 mainstacksize = 256*1024; | |
| 758 atnotify(threadinfo, 1); | |
| 759 t = _threadcreate(p, threadmainstart, nil, mainstacksize); | |
| 760 t->mainthread = 1; | |
| 761 procmain(p); | |
| 762 sysfatal("procmain returned in libthread"); | |
| 763 /* does not return */ | |
| 764 return 0; | |
| 765 } | |
| 766 | |
| 767 /* | |
| 768 * hooray for linked lists | |
| 769 */ | |
| 770 static void | |
| 771 addthread(_Threadlist *l, _Thread *t) | |
| 772 { | |
| 773 if(l->tail){ | |
| 774 l->tail->next = t; | |
| 775 t->prev = l->tail; | |
| 776 }else{ | |
| 777 l->head = t; | |
| 778 t->prev = nil; | |
| 779 } | |
| 780 l->tail = t; | |
| 781 t->next = nil; | |
| 782 } | |
| 783 | |
| 784 static void | |
| 785 delthread(_Threadlist *l, _Thread *t) | |
| 786 { | |
| 787 if(t->prev) | |
| 788 t->prev->next = t->next; | |
| 789 else | |
| 790 l->head = t->next; | |
| 791 if(t->next) | |
| 792 t->next->prev = t->prev; | |
| 793 else | |
| 794 l->tail = t->prev; | |
| 795 } | |
| 796 | |
| 797 /* inefficient but rarely used */ | |
| 798 static int | |
| 799 onlist(_Threadlist *l, _Thread *t) | |
| 800 { | |
| 801 _Thread *tt; | |
| 802 | |
| 803 for(tt = l->head; tt; tt=tt->next) | |
| 804 if(tt == t) | |
| 805 return 1; | |
| 806 return 0; | |
| 807 } | |
| 808 | |
| 809 static void | |
| 810 addthreadinproc(Proc *p, _Thread *t) | |
| 811 { | |
| 812 _Threadlist *l; | |
| 813 | |
| 814 l = &p->allthreads; | |
| 815 if(l->tail){ | |
| 816 l->tail->allnext = t; | |
| 817 t->allprev = l->tail; | |
| 818 }else{ | |
| 819 l->head = t; | |
| 820 t->allprev = nil; | |
| 821 } | |
| 822 l->tail = t; | |
| 823 t->allnext = nil; | |
| 824 } | |
| 825 | |
| 826 static void | |
| 827 delthreadinproc(Proc *p, _Thread *t) | |
| 828 { | |
| 829 _Threadlist *l; | |
| 830 | |
| 831 l = &p->allthreads; | |
| 832 if(t->allprev) | |
| 833 t->allprev->allnext = t->allnext; | |
| 834 else | |
| 835 l->head = t->allnext; | |
| 836 if(t->allnext) | |
| 837 t->allnext->allprev = t->allprev; | |
| 838 else | |
| 839 l->tail = t->allprev; | |
| 840 } | |
| 841 | |
| 842 Proc *_threadprocs; | |
| 843 Lock _threadprocslock; | |
| 844 static Proc *_threadprocstail; | |
| 845 | |
| 846 static void | |
| 847 addproc(Proc *p) | |
| 848 { | |
| 849 lock(&_threadprocslock); | |
| 850 if(_threadprocstail){ | |
| 851 _threadprocstail->next = p; | |
| 852 p->prev = _threadprocstail; | |
| 853 }else{ | |
| 854 _threadprocs = p; | |
| 855 p->prev = nil; | |
| 856 } | |
| 857 _threadprocstail = p; | |
| 858 p->next = nil; | |
| 859 unlock(&_threadprocslock); | |
| 860 } | |
| 861 | |
| 862 static void | |
| 863 delproc(Proc *p) | |
| 864 { | |
| 865 lock(&_threadprocslock); | |
| 866 if(p->prev) | |
| 867 p->prev->next = p->next; | |
| 868 else | |
| 869 _threadprocs = p->next; | |
| 870 if(p->next) | |
| 871 p->next->prev = p->prev; | |
| 872 else | |
| 873 _threadprocstail = p->prev; | |
| 874 unlock(&_threadprocslock); | |
| 875 } | |
| 876 | |
| 877 /* | |
| 878 * notify - for now just use the usual mechanisms | |
| 879 */ | |
| 880 void | |
| 881 threadnotify(int (*f)(void*, char*), int in) | |
| 882 { | |
| 883 atnotify(f, in); | |
| 884 } | |
| 885 | |
| 886 static int | |
| 887 onrunqueue(Proc *p, _Thread *t) | |
| 888 { | |
| 889 _Thread *tt; | |
| 890 | |
| 891 for(tt=p->runqueue.head; tt; tt=tt->next) | |
| 892 if(tt == t) | |
| 893 return 1; | |
| 894 return 0; | |
| 895 } | |
| 896 | |
| 897 /* | |
| 898 * print state - called from SIGINFO | |
| 899 */ | |
| 900 static int | |
| 901 threadinfo(void *v, char *s) | |
| 902 { | |
| 903 Proc *p; | |
| 904 _Thread *t; | |
| 905 | |
| 906 if(strcmp(s, "quit") != 0 && strcmp(s, "sys: status request") !=… | |
| 907 return 0; | |
| 908 | |
| 909 for(p=_threadprocs; p; p=p->next){ | |
| 910 fprint(2, "proc %p %s%s\n", (void*)p->osprocid, p->msg, | |
| 911 p->sysproc ? " (sysproc)": ""); | |
| 912 for(t=p->allthreads.head; t; t=t->allnext){ | |
| 913 fprint(2, "\tthread %d %s: %s %s\n", | |
| 914 t->id, | |
| 915 t == p->thread ? "Running" : | |
| 916 onrunqueue(p, t) ? "Ready" : "Sleeping", | |
| 917 t->state, t->name); | |
| 918 } | |
| 919 } | |
| 920 return 1; | |
| 921 } |