github.com/xushiwei/go@v0.0.0-20130601165731-2b9d83f45bc9/src/pkg/runtime/proc.c (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 #include "runtime.h" 6 #include "arch_GOARCH.h" 7 #include "malloc.h" 8 #include "stack.h" 9 #include "race.h" 10 #include "type.h" 11 12 // Goroutine scheduler 13 // The scheduler's job is to distribute ready-to-run goroutines over worker threads. 14 // 15 // The main concepts are: 16 // G - goroutine. 17 // M - worker thread, or machine. 18 // P - processor, a resource that is required to execute Go code. 19 // M must have an associated P to execute Go code, however it can be 20 // blocked or in a syscall w/o an associated P. 21 // 22 // Design doc at http://golang.org/s/go11sched. 23 24 typedef struct Sched Sched; 25 struct Sched { 26 Lock; 27 28 uint64 goidgen; 29 30 M* midle; // idle m's waiting for work 31 int32 nmidle; // number of idle m's waiting for work 32 int32 mlocked; // number of locked m's waiting for work 33 int32 mcount; // number of m's that have been created 34 35 P* pidle; // idle P's 36 uint32 npidle; 37 uint32 nmspinning; 38 39 // Global runnable queue. 40 G* runqhead; 41 G* runqtail; 42 int32 runqsize; 43 44 // Global cache of dead G's. 45 Lock gflock; 46 G* gfree; 47 48 int32 stopwait; 49 Note stopnote; 50 uint32 sysmonwait; 51 Note sysmonnote; 52 uint64 lastpoll; 53 54 int32 profilehz; // cpu profiling rate 55 }; 56 57 // The max value of GOMAXPROCS. 58 // There are no fundamental restrictions on the value. 59 enum { MaxGomaxprocs = 1<<8 }; 60 61 Sched runtime·sched; 62 int32 runtime·gomaxprocs; 63 bool runtime·singleproc; 64 bool runtime·iscgo; 65 uint32 runtime·gcwaiting; 66 M runtime·m0; 67 G runtime·g0; // idle goroutine for m0 68 G* runtime·allg; 69 G* runtime·lastg; 70 M* runtime·allm; 71 M* runtime·extram; 72 int8* runtime·goos; 73 int32 runtime·ncpu; 74 static int32 newprocs; 75 76 void runtime·mstart(void); 77 static void runqput(P*, G*); 78 static G* runqget(P*); 79 static void runqgrow(P*); 80 static G* runqsteal(P*, P*); 81 static void mput(M*); 82 static M* mget(void); 83 static void mcommoninit(M*); 84 static void schedule(void); 85 static void procresize(int32); 86 static void acquirep(P*); 87 static P* releasep(void); 88 static void newm(void(*)(void), P*); 89 static void goidle(void); 90 static void stopm(void); 91 static void startm(P*, bool); 92 static void handoffp(P*); 93 static void wakep(void); 94 static void stoplockedm(void); 95 static void startlockedm(G*); 96 static void sysmon(void); 97 static uint32 retake(uint32*); 98 static void inclocked(int32); 99 static void checkdead(void); 100 static void exitsyscall0(G*); 101 static void park0(G*); 102 static void gosched0(G*); 103 static void goexit0(G*); 104 static void gfput(P*, G*); 105 static G* gfget(P*); 106 static void gfpurge(P*); 107 static void globrunqput(G*); 108 static G* globrunqget(P*); 109 static P* pidleget(void); 110 static void pidleput(P*); 111 static void injectglist(G*); 112 113 // The bootstrap sequence is: 114 // 115 // call osinit 116 // call schedinit 117 // make & queue new G 118 // call runtime·mstart 119 // 120 // The new G calls runtime·main. 121 void 122 runtime·schedinit(void) 123 { 124 int32 n, procs; 125 byte *p; 126 127 m->nomemprof++; 128 runtime·mprofinit(); 129 runtime·mallocinit(); 130 mcommoninit(m); 131 132 runtime·goargs(); 133 runtime·goenvs(); 134 135 // For debugging: 136 // Allocate internal symbol table representation now, 137 // so that we don't need to call malloc when we crash. 138 // runtime·findfunc(0); 139 140 runtime·sched.lastpoll = runtime·nanotime(); 141 procs = 1; 142 p = runtime·getenv("GOMAXPROCS"); 143 if(p != nil && (n = runtime·atoi(p)) > 0) { 144 if(n > MaxGomaxprocs) 145 n = MaxGomaxprocs; 146 procs = n; 147 } 148 runtime·allp = runtime·malloc((MaxGomaxprocs+1)*sizeof(runtime·allp[0])); 149 procresize(procs); 150 151 mstats.enablegc = 1; 152 m->nomemprof--; 153 154 if(raceenabled) 155 g->racectx = runtime·raceinit(); 156 } 157 158 extern void main·init(void); 159 extern void main·main(void); 160 161 static FuncVal scavenger = {runtime·MHeap_Scavenger}; 162 163 // The main goroutine. 164 void 165 runtime·main(void) 166 { 167 newm(sysmon, nil); 168 169 // Lock the main goroutine onto this, the main OS thread, 170 // during initialization. Most programs won't care, but a few 171 // do require certain calls to be made by the main thread. 172 // Those can arrange for main.main to run in the main thread 173 // by calling runtime.LockOSThread during initialization 174 // to preserve the lock. 175 runtime·lockOSThread(); 176 if(m != &runtime·m0) 177 runtime·throw("runtime·main not on m0"); 178 runtime·newproc1(&scavenger, nil, 0, 0, runtime·main); 179 main·init(); 180 runtime·unlockOSThread(); 181 182 main·main(); 183 if(raceenabled) 184 runtime·racefini(); 185 186 // Make racy client program work: if panicking on 187 // another goroutine at the same time as main returns, 188 // let the other goroutine finish printing the panic trace. 189 // Once it does, it will exit. See issue 3934. 190 if(runtime·panicking) 191 runtime·park(nil, nil, "panicwait"); 192 193 runtime·exit(0); 194 for(;;) 195 *(int32*)runtime·main = 0; 196 } 197 198 void 199 runtime·goroutineheader(G *gp) 200 { 201 int8 *status; 202 203 switch(gp->status) { 204 case Gidle: 205 status = "idle"; 206 break; 207 case Grunnable: 208 status = "runnable"; 209 break; 210 case Grunning: 211 status = "running"; 212 break; 213 case Gsyscall: 214 status = "syscall"; 215 break; 216 case Gwaiting: 217 if(gp->waitreason) 218 status = gp->waitreason; 219 else 220 status = "waiting"; 221 break; 222 default: 223 status = "???"; 224 break; 225 } 226 runtime·printf("goroutine %D [%s]:\n", gp->goid, status); 227 } 228 229 void 230 runtime·tracebackothers(G *me) 231 { 232 G *gp; 233 int32 traceback; 234 235 traceback = runtime·gotraceback(nil); 236 for(gp = runtime·allg; gp != nil; gp = gp->alllink) { 237 if(gp == me || gp->status == Gdead) 238 continue; 239 if(gp->issystem && traceback < 2) 240 continue; 241 runtime·printf("\n"); 242 runtime·goroutineheader(gp); 243 runtime·traceback(gp->sched.pc, (byte*)gp->sched.sp, 0, gp); 244 } 245 } 246 247 static void 248 mcommoninit(M *mp) 249 { 250 // If there is no mcache runtime·callers() will crash, 251 // and we are most likely in sysmon thread so the stack is senseless anyway. 252 if(m->mcache) 253 runtime·callers(1, mp->createstack, nelem(mp->createstack)); 254 255 mp->fastrand = 0x49f6428aUL + mp->id + runtime·cputicks(); 256 257 runtime·lock(&runtime·sched); 258 mp->id = runtime·sched.mcount++; 259 260 runtime·mpreinit(mp); 261 262 // Add to runtime·allm so garbage collector doesn't free m 263 // when it is just in a register or thread-local storage. 264 mp->alllink = runtime·allm; 265 // runtime·NumCgoCall() iterates over allm w/o schedlock, 266 // so we need to publish it safely. 267 runtime·atomicstorep(&runtime·allm, mp); 268 runtime·unlock(&runtime·sched); 269 } 270 271 // Mark gp ready to run. 272 void 273 runtime·ready(G *gp) 274 { 275 // Mark runnable. 276 if(gp->status != Gwaiting) { 277 runtime·printf("goroutine %D has status %d\n", gp->goid, gp->status); 278 runtime·throw("bad g->status in ready"); 279 } 280 gp->status = Grunnable; 281 runqput(m->p, gp); 282 if(runtime·atomicload(&runtime·sched.npidle) != 0 && runtime·atomicload(&runtime·sched.nmspinning) == 0) // TODO: fast atomic 283 wakep(); 284 } 285 286 int32 287 runtime·gcprocs(void) 288 { 289 int32 n; 290 291 // Figure out how many CPUs to use during GC. 292 // Limited by gomaxprocs, number of actual CPUs, and MaxGcproc. 293 runtime·lock(&runtime·sched); 294 n = runtime·gomaxprocs; 295 if(n > runtime·ncpu) 296 n = runtime·ncpu; 297 if(n > MaxGcproc) 298 n = MaxGcproc; 299 if(n > runtime·sched.nmidle+1) // one M is currently running 300 n = runtime·sched.nmidle+1; 301 runtime·unlock(&runtime·sched); 302 return n; 303 } 304 305 static bool 306 needaddgcproc(void) 307 { 308 int32 n; 309 310 runtime·lock(&runtime·sched); 311 n = runtime·gomaxprocs; 312 if(n > runtime·ncpu) 313 n = runtime·ncpu; 314 if(n > MaxGcproc) 315 n = MaxGcproc; 316 n -= runtime·sched.nmidle+1; // one M is currently running 317 runtime·unlock(&runtime·sched); 318 return n > 0; 319 } 320 321 void 322 runtime·helpgc(int32 nproc) 323 { 324 M *mp; 325 int32 n, pos; 326 327 runtime·lock(&runtime·sched); 328 pos = 0; 329 for(n = 1; n < nproc; n++) { // one M is currently running 330 if(runtime·allp[pos]->mcache == m->mcache) 331 pos++; 332 mp = mget(); 333 if(mp == nil) 334 runtime·throw("runtime·gcprocs inconsistency"); 335 mp->helpgc = n; 336 mp->mcache = runtime·allp[pos]->mcache; 337 pos++; 338 runtime·notewakeup(&mp->park); 339 } 340 runtime·unlock(&runtime·sched); 341 } 342 343 void 344 runtime·stoptheworld(void) 345 { 346 int32 i; 347 uint32 s; 348 P *p; 349 bool wait; 350 351 runtime·lock(&runtime·sched); 352 runtime·sched.stopwait = runtime·gomaxprocs; 353 runtime·atomicstore((uint32*)&runtime·gcwaiting, 1); 354 // stop current P 355 m->p->status = Pgcstop; 356 runtime·sched.stopwait--; 357 // try to retake all P's in Psyscall status 358 for(i = 0; i < runtime·gomaxprocs; i++) { 359 p = runtime·allp[i]; 360 s = p->status; 361 if(s == Psyscall && runtime·cas(&p->status, s, Pgcstop)) 362 runtime·sched.stopwait--; 363 } 364 // stop idle P's 365 while(p = pidleget()) { 366 p->status = Pgcstop; 367 runtime·sched.stopwait--; 368 } 369 wait = runtime·sched.stopwait > 0; 370 runtime·unlock(&runtime·sched); 371 372 // wait for remaining P's to stop voluntary 373 if(wait) { 374 runtime·notesleep(&runtime·sched.stopnote); 375 runtime·noteclear(&runtime·sched.stopnote); 376 } 377 if(runtime·sched.stopwait) 378 runtime·throw("stoptheworld: not stopped"); 379 for(i = 0; i < runtime·gomaxprocs; i++) { 380 p = runtime·allp[i]; 381 if(p->status != Pgcstop) 382 runtime·throw("stoptheworld: not stopped"); 383 } 384 } 385 386 static void 387 mhelpgc(void) 388 { 389 m->helpgc = -1; 390 } 391 392 void 393 runtime·starttheworld(void) 394 { 395 P *p, *p1; 396 M *mp; 397 G *gp; 398 bool add; 399 400 gp = runtime·netpoll(false); // non-blocking 401 injectglist(gp); 402 add = needaddgcproc(); 403 runtime·lock(&runtime·sched); 404 if(newprocs) { 405 procresize(newprocs); 406 newprocs = 0; 407 } else 408 procresize(runtime·gomaxprocs); 409 runtime·gcwaiting = 0; 410 411 p1 = nil; 412 while(p = pidleget()) { 413 // procresize() puts p's with work at the beginning of the list. 414 // Once we reach a p without a run queue, the rest don't have one either. 415 if(p->runqhead == p->runqtail) { 416 pidleput(p); 417 break; 418 } 419 mp = mget(); 420 if(mp == nil) { 421 p->link = p1; 422 p1 = p; 423 continue; 424 } 425 if(mp->nextp) 426 runtime·throw("starttheworld: inconsistent mp->nextp"); 427 mp->nextp = p; 428 runtime·notewakeup(&mp->park); 429 } 430 if(runtime·sched.sysmonwait) { 431 runtime·sched.sysmonwait = false; 432 runtime·notewakeup(&runtime·sched.sysmonnote); 433 } 434 runtime·unlock(&runtime·sched); 435 436 while(p1) { 437 p = p1; 438 p1 = p1->link; 439 add = false; 440 newm(nil, p); 441 } 442 443 if(add) { 444 // If GC could have used another helper proc, start one now, 445 // in the hope that it will be available next time. 446 // It would have been even better to start it before the collection, 447 // but doing so requires allocating memory, so it's tricky to 448 // coordinate. This lazy approach works out in practice: 449 // we don't mind if the first couple gc rounds don't have quite 450 // the maximum number of procs. 451 newm(mhelpgc, nil); 452 } 453 } 454 455 // Called to start an M. 456 void 457 runtime·mstart(void) 458 { 459 // It is used by windows-386 only. Unfortunately, seh needs 460 // to be located on os stack, and mstart runs on os stack 461 // for both m0 and m. 462 SEH seh; 463 464 if(g != m->g0) 465 runtime·throw("bad runtime·mstart"); 466 467 // Record top of stack for use by mcall. 468 // Once we call schedule we're never coming back, 469 // so other calls can reuse this stack space. 470 runtime·gosave(&m->g0->sched); 471 m->g0->sched.pc = (void*)-1; // make sure it is never used 472 m->seh = &seh; 473 runtime·asminit(); 474 runtime·minit(); 475 476 // Install signal handlers; after minit so that minit can 477 // prepare the thread to be able to handle the signals. 478 if(m == &runtime·m0) { 479 runtime·initsig(); 480 if(runtime·iscgo) 481 runtime·newextram(); 482 } 483 484 if(m->mstartfn) 485 m->mstartfn(); 486 487 if(m->helpgc) { 488 m->helpgc = 0; 489 stopm(); 490 } else if(m != &runtime·m0) { 491 acquirep(m->nextp); 492 m->nextp = nil; 493 } 494 schedule(); 495 496 // TODO(brainman): This point is never reached, because scheduler 497 // does not release os threads at the moment. But once this path 498 // is enabled, we must remove our seh here. 499 } 500 501 // When running with cgo, we call _cgo_thread_start 502 // to start threads for us so that we can play nicely with 503 // foreign code. 504 void (*_cgo_thread_start)(void*); 505 506 typedef struct CgoThreadStart CgoThreadStart; 507 struct CgoThreadStart 508 { 509 M *m; 510 G *g; 511 void (*fn)(void); 512 }; 513 514 // Allocate a new m unassociated with any thread. 515 // Can use p for allocation context if needed. 516 M* 517 runtime·allocm(P *p) 518 { 519 M *mp; 520 static Type *mtype; // The Go type M 521 522 m->locks++; // disable GC because it can be called from sysmon 523 if(m->p == nil) 524 acquirep(p); // temporarily borrow p for mallocs in this function 525 if(mtype == nil) { 526 Eface e; 527 runtime·gc_m_ptr(&e); 528 mtype = ((PtrType*)e.type)->elem; 529 } 530 531 mp = runtime·cnew(mtype); 532 mcommoninit(mp); 533 534 // In case of cgo, pthread_create will make us a stack. 535 // Windows will layout sched stack on OS stack. 536 if(runtime·iscgo || Windows) 537 mp->g0 = runtime·malg(-1); 538 else 539 mp->g0 = runtime·malg(8192); 540 541 if(p == m->p) 542 releasep(); 543 m->locks--; 544 545 return mp; 546 } 547 548 static M* lockextra(bool nilokay); 549 static void unlockextra(M*); 550 551 // needm is called when a cgo callback happens on a 552 // thread without an m (a thread not created by Go). 553 // In this case, needm is expected to find an m to use 554 // and return with m, g initialized correctly. 555 // Since m and g are not set now (likely nil, but see below) 556 // needm is limited in what routines it can call. In particular 557 // it can only call nosplit functions (textflag 7) and cannot 558 // do any scheduling that requires an m. 559 // 560 // In order to avoid needing heavy lifting here, we adopt 561 // the following strategy: there is a stack of available m's 562 // that can be stolen. Using compare-and-swap 563 // to pop from the stack has ABA races, so we simulate 564 // a lock by doing an exchange (via casp) to steal the stack 565 // head and replace the top pointer with MLOCKED (1). 566 // This serves as a simple spin lock that we can use even 567 // without an m. The thread that locks the stack in this way 568 // unlocks the stack by storing a valid stack head pointer. 569 // 570 // In order to make sure that there is always an m structure 571 // available to be stolen, we maintain the invariant that there 572 // is always one more than needed. At the beginning of the 573 // program (if cgo is in use) the list is seeded with a single m. 574 // If needm finds that it has taken the last m off the list, its job 575 // is - once it has installed its own m so that it can do things like 576 // allocate memory - to create a spare m and put it on the list. 577 // 578 // Each of these extra m's also has a g0 and a curg that are 579 // pressed into service as the scheduling stack and current 580 // goroutine for the duration of the cgo callback. 581 // 582 // When the callback is done with the m, it calls dropm to 583 // put the m back on the list. 584 #pragma textflag 7 585 void 586 runtime·needm(byte x) 587 { 588 M *mp; 589 590 // Lock extra list, take head, unlock popped list. 591 // nilokay=false is safe here because of the invariant above, 592 // that the extra list always contains or will soon contain 593 // at least one m. 594 mp = lockextra(false); 595 596 // Set needextram when we've just emptied the list, 597 // so that the eventual call into cgocallbackg will 598 // allocate a new m for the extra list. We delay the 599 // allocation until then so that it can be done 600 // after exitsyscall makes sure it is okay to be 601 // running at all (that is, there's no garbage collection 602 // running right now). 603 mp->needextram = mp->schedlink == nil; 604 unlockextra(mp->schedlink); 605 606 // Install m and g (= m->g0) and set the stack bounds 607 // to match the current stack. We don't actually know 608 // how big the stack is, like we don't know how big any 609 // scheduling stack is, but we assume there's at least 32 kB, 610 // which is more than enough for us. 611 runtime·setmg(mp, mp->g0); 612 g->stackbase = (uintptr)(&x + 1024); 613 g->stackguard = (uintptr)(&x - 32*1024); 614 615 // On windows/386, we need to put an SEH frame (two words) 616 // somewhere on the current stack. We are called 617 // from needm, and we know there is some available 618 // space one word into the argument frame. Use that. 619 m->seh = (SEH*)((uintptr*)&x + 1); 620 621 // Initialize this thread to use the m. 622 runtime·asminit(); 623 runtime·minit(); 624 } 625 626 // newextram allocates an m and puts it on the extra list. 627 // It is called with a working local m, so that it can do things 628 // like call schedlock and allocate. 629 void 630 runtime·newextram(void) 631 { 632 M *mp, *mnext; 633 G *gp; 634 635 // Create extra goroutine locked to extra m. 636 // The goroutine is the context in which the cgo callback will run. 637 // The sched.pc will never be returned to, but setting it to 638 // runtime.goexit makes clear to the traceback routines where 639 // the goroutine stack ends. 640 mp = runtime·allocm(nil); 641 gp = runtime·malg(4096); 642 gp->sched.pc = (void*)runtime·goexit; 643 gp->sched.sp = gp->stackbase; 644 gp->sched.g = gp; 645 gp->status = Gsyscall; 646 mp->curg = gp; 647 mp->locked = LockInternal; 648 mp->lockedg = gp; 649 gp->lockedm = mp; 650 // put on allg for garbage collector 651 runtime·lock(&runtime·sched); 652 if(runtime·lastg == nil) 653 runtime·allg = gp; 654 else 655 runtime·lastg->alllink = gp; 656 runtime·lastg = gp; 657 runtime·unlock(&runtime·sched); 658 gp->goid = runtime·xadd64(&runtime·sched.goidgen, 1); 659 if(raceenabled) 660 gp->racectx = runtime·racegostart(runtime·newextram); 661 662 // Add m to the extra list. 663 mnext = lockextra(true); 664 mp->schedlink = mnext; 665 unlockextra(mp); 666 } 667 668 // dropm is called when a cgo callback has called needm but is now 669 // done with the callback and returning back into the non-Go thread. 670 // It puts the current m back onto the extra list. 671 // 672 // The main expense here is the call to signalstack to release the 673 // m's signal stack, and then the call to needm on the next callback 674 // from this thread. It is tempting to try to save the m for next time, 675 // which would eliminate both these costs, but there might not be 676 // a next time: the current thread (which Go does not control) might exit. 677 // If we saved the m for that thread, there would be an m leak each time 678 // such a thread exited. Instead, we acquire and release an m on each 679 // call. These should typically not be scheduling operations, just a few 680 // atomics, so the cost should be small. 681 // 682 // TODO(rsc): An alternative would be to allocate a dummy pthread per-thread 683 // variable using pthread_key_create. Unlike the pthread keys we already use 684 // on OS X, this dummy key would never be read by Go code. It would exist 685 // only so that we could register at thread-exit-time destructor. 686 // That destructor would put the m back onto the extra list. 687 // This is purely a performance optimization. The current version, 688 // in which dropm happens on each cgo call, is still correct too. 689 // We may have to keep the current version on systems with cgo 690 // but without pthreads, like Windows. 691 void 692 runtime·dropm(void) 693 { 694 M *mp, *mnext; 695 696 // Undo whatever initialization minit did during needm. 697 runtime·unminit(); 698 m->seh = nil; // reset dangling typed pointer 699 700 // Clear m and g, and return m to the extra list. 701 // After the call to setmg we can only call nosplit functions. 702 mp = m; 703 runtime·setmg(nil, nil); 704 705 mnext = lockextra(true); 706 mp->schedlink = mnext; 707 unlockextra(mp); 708 } 709 710 #define MLOCKED ((M*)1) 711 712 // lockextra locks the extra list and returns the list head. 713 // The caller must unlock the list by storing a new list head 714 // to runtime.extram. If nilokay is true, then lockextra will 715 // return a nil list head if that's what it finds. If nilokay is false, 716 // lockextra will keep waiting until the list head is no longer nil. 717 #pragma textflag 7 718 static M* 719 lockextra(bool nilokay) 720 { 721 M *mp; 722 void (*yield)(void); 723 724 for(;;) { 725 mp = runtime·atomicloadp(&runtime·extram); 726 if(mp == MLOCKED) { 727 yield = runtime·osyield; 728 yield(); 729 continue; 730 } 731 if(mp == nil && !nilokay) { 732 runtime·usleep(1); 733 continue; 734 } 735 if(!runtime·casp(&runtime·extram, mp, MLOCKED)) { 736 yield = runtime·osyield; 737 yield(); 738 continue; 739 } 740 break; 741 } 742 return mp; 743 } 744 745 #pragma textflag 7 746 static void 747 unlockextra(M *mp) 748 { 749 runtime·atomicstorep(&runtime·extram, mp); 750 } 751 752 753 // Create a new m. It will start off with a call to fn, or else the scheduler. 754 static void 755 newm(void(*fn)(void), P *p) 756 { 757 M *mp; 758 759 mp = runtime·allocm(p); 760 mp->nextp = p; 761 mp->mstartfn = fn; 762 763 if(runtime·iscgo) { 764 CgoThreadStart ts; 765 766 if(_cgo_thread_start == nil) 767 runtime·throw("_cgo_thread_start missing"); 768 ts.m = mp; 769 ts.g = mp->g0; 770 ts.fn = runtime·mstart; 771 runtime·asmcgocall(_cgo_thread_start, &ts); 772 return; 773 } 774 runtime·newosproc(mp, (byte*)mp->g0->stackbase); 775 } 776 777 // Stops execution of the current m until new work is available. 778 // Returns with acquired P. 779 static void 780 stopm(void) 781 { 782 if(m->locks) 783 runtime·throw("stopm holding locks"); 784 if(m->p) 785 runtime·throw("stopm holding p"); 786 if(m->spinning) { 787 m->spinning = false; 788 runtime·xadd(&runtime·sched.nmspinning, -1); 789 } 790 791 retry: 792 runtime·lock(&runtime·sched); 793 mput(m); 794 runtime·unlock(&runtime·sched); 795 runtime·notesleep(&m->park); 796 runtime·noteclear(&m->park); 797 if(m->helpgc) { 798 runtime·gchelper(); 799 m->helpgc = 0; 800 m->mcache = nil; 801 goto retry; 802 } 803 acquirep(m->nextp); 804 m->nextp = nil; 805 } 806 807 static void 808 mspinning(void) 809 { 810 m->spinning = true; 811 } 812 813 // Schedules some M to run the p (creates an M if necessary). 814 // If p==nil, tries to get an idle P, if no idle P's returns false. 815 static void 816 startm(P *p, bool spinning) 817 { 818 M *mp; 819 void (*fn)(void); 820 821 runtime·lock(&runtime·sched); 822 if(p == nil) { 823 p = pidleget(); 824 if(p == nil) { 825 runtime·unlock(&runtime·sched); 826 if(spinning) 827 runtime·xadd(&runtime·sched.nmspinning, -1); 828 return; 829 } 830 } 831 mp = mget(); 832 runtime·unlock(&runtime·sched); 833 if(mp == nil) { 834 fn = nil; 835 if(spinning) 836 fn = mspinning; 837 newm(fn, p); 838 return; 839 } 840 if(mp->spinning) 841 runtime·throw("startm: m is spinning"); 842 if(mp->nextp) 843 runtime·throw("startm: m has p"); 844 mp->spinning = spinning; 845 mp->nextp = p; 846 runtime·notewakeup(&mp->park); 847 } 848 849 // Hands off P from syscall or locked M. 850 static void 851 handoffp(P *p) 852 { 853 // if it has local work, start it straight away 854 if(p->runqhead != p->runqtail || runtime·sched.runqsize) { 855 startm(p, false); 856 return; 857 } 858 // no local work, check that there are no spinning/idle M's, 859 // otherwise our help is not required 860 if(runtime·atomicload(&runtime·sched.nmspinning) + runtime·atomicload(&runtime·sched.npidle) == 0 && // TODO: fast atomic 861 runtime·cas(&runtime·sched.nmspinning, 0, 1)) { 862 startm(p, true); 863 return; 864 } 865 runtime·lock(&runtime·sched); 866 if(runtime·gcwaiting) { 867 p->status = Pgcstop; 868 if(--runtime·sched.stopwait == 0) 869 runtime·notewakeup(&runtime·sched.stopnote); 870 runtime·unlock(&runtime·sched); 871 return; 872 } 873 if(runtime·sched.runqsize) { 874 runtime·unlock(&runtime·sched); 875 startm(p, false); 876 return; 877 } 878 // If this is the last running P and nobody is polling network, 879 // need to wakeup another M to poll network. 880 if(runtime·sched.npidle == runtime·gomaxprocs-1 && runtime·atomicload64(&runtime·sched.lastpoll) != 0) { 881 runtime·unlock(&runtime·sched); 882 startm(p, false); 883 return; 884 } 885 pidleput(p); 886 runtime·unlock(&runtime·sched); 887 } 888 889 // Tries to add one more P to execute G's. 890 // Called when a G is made runnable (newproc, ready). 891 static void 892 wakep(void) 893 { 894 // be conservative about spinning threads 895 if(!runtime·cas(&runtime·sched.nmspinning, 0, 1)) 896 return; 897 startm(nil, true); 898 } 899 900 // Stops execution of the current m that is locked to a g until the g is runnable again. 901 // Returns with acquired P. 902 static void 903 stoplockedm(void) 904 { 905 P *p; 906 907 if(m->lockedg == nil || m->lockedg->lockedm != m) 908 runtime·throw("stoplockedm: inconsistent locking"); 909 if(m->p) { 910 // Schedule another M to run this p. 911 p = releasep(); 912 handoffp(p); 913 } 914 inclocked(1); 915 // Wait until another thread schedules lockedg again. 916 runtime·notesleep(&m->park); 917 runtime·noteclear(&m->park); 918 if(m->lockedg->status != Grunnable) 919 runtime·throw("stoplockedm: not runnable"); 920 acquirep(m->nextp); 921 m->nextp = nil; 922 } 923 924 // Schedules the locked m to run the locked gp. 925 static void 926 startlockedm(G *gp) 927 { 928 M *mp; 929 P *p; 930 931 mp = gp->lockedm; 932 if(mp == m) 933 runtime·throw("startlockedm: locked to me"); 934 if(mp->nextp) 935 runtime·throw("startlockedm: m has p"); 936 // directly handoff current P to the locked m 937 inclocked(-1); 938 p = releasep(); 939 mp->nextp = p; 940 runtime·notewakeup(&mp->park); 941 stopm(); 942 } 943 944 // Stops the current m for stoptheworld. 945 // Returns when the world is restarted. 946 static void 947 gcstopm(void) 948 { 949 P *p; 950 951 if(!runtime·gcwaiting) 952 runtime·throw("gcstopm: not waiting for gc"); 953 if(m->spinning) { 954 m->spinning = false; 955 runtime·xadd(&runtime·sched.nmspinning, -1); 956 } 957 p = releasep(); 958 runtime·lock(&runtime·sched); 959 p->status = Pgcstop; 960 if(--runtime·sched.stopwait == 0) 961 runtime·notewakeup(&runtime·sched.stopnote); 962 runtime·unlock(&runtime·sched); 963 stopm(); 964 } 965 966 // Schedules gp to run on the current M. 967 // Never returns. 968 static void 969 execute(G *gp) 970 { 971 int32 hz; 972 973 if(gp->status != Grunnable) { 974 runtime·printf("execute: bad g status %d\n", gp->status); 975 runtime·throw("execute: bad g status"); 976 } 977 gp->status = Grunning; 978 m->p->tick++; 979 m->curg = gp; 980 gp->m = m; 981 982 // Check whether the profiler needs to be turned on or off. 983 hz = runtime·sched.profilehz; 984 if(m->profilehz != hz) 985 runtime·resetcpuprofiler(hz); 986 987 if(gp->sched.pc == (byte*)runtime·goexit) // kickoff 988 runtime·gogocallfn(&gp->sched, gp->fnstart); 989 runtime·gogo(&gp->sched, 0); 990 } 991 992 // Finds a runnable goroutine to execute. 993 // Tries to steal from other P's, get g from global queue, poll network. 994 static G* 995 findrunnable(void) 996 { 997 G *gp; 998 P *p; 999 int32 i; 1000 1001 top: 1002 if(runtime·gcwaiting) { 1003 gcstopm(); 1004 goto top; 1005 } 1006 // local runq 1007 gp = runqget(m->p); 1008 if(gp) 1009 return gp; 1010 // global runq 1011 if(runtime·sched.runqsize) { 1012 runtime·lock(&runtime·sched); 1013 gp = globrunqget(m->p); 1014 runtime·unlock(&runtime·sched); 1015 if(gp) 1016 return gp; 1017 } 1018 // poll network 1019 gp = runtime·netpoll(false); // non-blocking 1020 if(gp) { 1021 injectglist(gp->schedlink); 1022 gp->status = Grunnable; 1023 return gp; 1024 } 1025 // If number of spinning M's >= number of busy P's, block. 1026 // This is necessary to prevent excessive CPU consumption 1027 // when GOMAXPROCS>>1 but the program parallelism is low. 1028 if(!m->spinning && 2 * runtime·atomicload(&runtime·sched.nmspinning) >= runtime·gomaxprocs - runtime·atomicload(&runtime·sched.npidle)) // TODO: fast atomic 1029 goto stop; 1030 if(!m->spinning) { 1031 m->spinning = true; 1032 runtime·xadd(&runtime·sched.nmspinning, 1); 1033 } 1034 // random steal from other P's 1035 for(i = 0; i < 2*runtime·gomaxprocs; i++) { 1036 if(runtime·gcwaiting) 1037 goto top; 1038 p = runtime·allp[runtime·fastrand1()%runtime·gomaxprocs]; 1039 if(p == m->p) 1040 gp = runqget(p); 1041 else 1042 gp = runqsteal(m->p, p); 1043 if(gp) 1044 return gp; 1045 } 1046 stop: 1047 // return P and block 1048 runtime·lock(&runtime·sched); 1049 if(runtime·gcwaiting) { 1050 runtime·unlock(&runtime·sched); 1051 goto top; 1052 } 1053 if(runtime·sched.runqsize) { 1054 gp = globrunqget(m->p); 1055 runtime·unlock(&runtime·sched); 1056 return gp; 1057 } 1058 p = releasep(); 1059 pidleput(p); 1060 runtime·unlock(&runtime·sched); 1061 if(m->spinning) { 1062 m->spinning = false; 1063 runtime·xadd(&runtime·sched.nmspinning, -1); 1064 } 1065 // check all runqueues once again 1066 for(i = 0; i < runtime·gomaxprocs; i++) { 1067 p = runtime·allp[i]; 1068 if(p && p->runqhead != p->runqtail) { 1069 runtime·lock(&runtime·sched); 1070 p = pidleget(); 1071 runtime·unlock(&runtime·sched); 1072 if(p) { 1073 acquirep(p); 1074 goto top; 1075 } 1076 break; 1077 } 1078 } 1079 // poll network 1080 if(runtime·xchg64(&runtime·sched.lastpoll, 0) != 0) { 1081 if(m->p) 1082 runtime·throw("findrunnable: netpoll with p"); 1083 if(m->spinning) 1084 runtime·throw("findrunnable: netpoll with spinning"); 1085 gp = runtime·netpoll(true); // block until new work is available 1086 runtime·atomicstore64(&runtime·sched.lastpoll, runtime·nanotime()); 1087 if(gp) { 1088 runtime·lock(&runtime·sched); 1089 p = pidleget(); 1090 runtime·unlock(&runtime·sched); 1091 if(p) { 1092 acquirep(p); 1093 injectglist(gp->schedlink); 1094 gp->status = Grunnable; 1095 return gp; 1096 } 1097 injectglist(gp); 1098 } 1099 } 1100 stopm(); 1101 goto top; 1102 } 1103 1104 // Injects the list of runnable G's into the scheduler. 1105 // Can run concurrently with GC. 1106 static void 1107 injectglist(G *glist) 1108 { 1109 int32 n; 1110 G *gp; 1111 1112 if(glist == nil) 1113 return; 1114 runtime·lock(&runtime·sched); 1115 for(n = 0; glist; n++) { 1116 gp = glist; 1117 glist = gp->schedlink; 1118 gp->status = Grunnable; 1119 globrunqput(gp); 1120 } 1121 runtime·unlock(&runtime·sched); 1122 1123 for(; n && runtime·sched.npidle; n--) 1124 startm(nil, false); 1125 } 1126 1127 // One round of scheduler: find a runnable goroutine and execute it. 1128 // Never returns. 1129 static void 1130 schedule(void) 1131 { 1132 G *gp; 1133 1134 if(m->locks) 1135 runtime·throw("schedule: holding locks"); 1136 1137 top: 1138 if(runtime·gcwaiting) { 1139 gcstopm(); 1140 goto top; 1141 } 1142 1143 gp = runqget(m->p); 1144 if(gp == nil) 1145 gp = findrunnable(); 1146 1147 if(m->spinning) { 1148 m->spinning = false; 1149 runtime·xadd(&runtime·sched.nmspinning, -1); 1150 } 1151 1152 // M wakeup policy is deliberately somewhat conservative (see nmspinning handling), 1153 // so see if we need to wakeup another M here. 1154 if (m->p->runqhead != m->p->runqtail && 1155 runtime·atomicload(&runtime·sched.nmspinning) == 0 && 1156 runtime·atomicload(&runtime·sched.npidle) > 0) // TODO: fast atomic 1157 wakep(); 1158 1159 if(gp->lockedm) { 1160 startlockedm(gp); 1161 goto top; 1162 } 1163 1164 execute(gp); 1165 } 1166 1167 // Puts the current goroutine into a waiting state and unlocks the lock. 1168 // The goroutine can be made runnable again by calling runtime·ready(gp). 1169 void 1170 runtime·park(void(*unlockf)(Lock*), Lock *lock, int8 *reason) 1171 { 1172 m->waitlock = lock; 1173 m->waitunlockf = unlockf; 1174 g->waitreason = reason; 1175 runtime·mcall(park0); 1176 } 1177 1178 // runtime·park continuation on g0. 1179 static void 1180 park0(G *gp) 1181 { 1182 gp->status = Gwaiting; 1183 gp->m = nil; 1184 m->curg = nil; 1185 if(m->waitunlockf) { 1186 m->waitunlockf(m->waitlock); 1187 m->waitunlockf = nil; 1188 m->waitlock = nil; 1189 } 1190 if(m->lockedg) { 1191 stoplockedm(); 1192 execute(gp); // Never returns. 1193 } 1194 schedule(); 1195 } 1196 1197 // Scheduler yield. 1198 void 1199 runtime·gosched(void) 1200 { 1201 runtime·mcall(gosched0); 1202 } 1203 1204 // runtime·gosched continuation on g0. 1205 static void 1206 gosched0(G *gp) 1207 { 1208 gp->status = Grunnable; 1209 gp->m = nil; 1210 m->curg = nil; 1211 runtime·lock(&runtime·sched); 1212 globrunqput(gp); 1213 runtime·unlock(&runtime·sched); 1214 if(m->lockedg) { 1215 stoplockedm(); 1216 execute(gp); // Never returns. 1217 } 1218 schedule(); 1219 } 1220 1221 // Finishes execution of the current goroutine. 1222 void 1223 runtime·goexit(void) 1224 { 1225 if(raceenabled) 1226 runtime·racegoend(); 1227 runtime·mcall(goexit0); 1228 } 1229 1230 // runtime·goexit continuation on g0. 1231 static void 1232 goexit0(G *gp) 1233 { 1234 gp->status = Gdead; 1235 gp->m = nil; 1236 gp->lockedm = nil; 1237 m->curg = nil; 1238 m->lockedg = nil; 1239 if(m->locked & ~LockExternal) { 1240 runtime·printf("invalid m->locked = %d", m->locked); 1241 runtime·throw("internal lockOSThread error"); 1242 } 1243 m->locked = 0; 1244 runtime·unwindstack(gp, nil); 1245 gfput(m->p, gp); 1246 schedule(); 1247 } 1248 1249 // The goroutine g is about to enter a system call. 1250 // Record that it's not using the cpu anymore. 1251 // This is called only from the go syscall library and cgocall, 1252 // not from the low-level system calls used by the runtime. 1253 // 1254 // Entersyscall cannot split the stack: the runtime·gosave must 1255 // make g->sched refer to the caller's stack segment, because 1256 // entersyscall is going to return immediately after. 1257 #pragma textflag 7 1258 void 1259 ·entersyscall(int32 dummy) 1260 { 1261 if(m->profilehz > 0) 1262 runtime·setprof(false); 1263 1264 // Leave SP around for gc and traceback. 1265 g->sched.sp = (uintptr)runtime·getcallersp(&dummy); 1266 g->sched.pc = runtime·getcallerpc(&dummy); 1267 g->sched.g = g; 1268 g->gcsp = g->sched.sp; 1269 g->gcpc = g->sched.pc; 1270 g->gcstack = g->stackbase; 1271 g->gcguard = g->stackguard; 1272 g->status = Gsyscall; 1273 if(g->gcsp < g->gcguard-StackGuard || g->gcstack < g->gcsp) { 1274 // runtime·printf("entersyscall inconsistent %p [%p,%p]\n", 1275 // g->gcsp, g->gcguard-StackGuard, g->gcstack); 1276 runtime·throw("entersyscall"); 1277 } 1278 1279 if(runtime·atomicload(&runtime·sched.sysmonwait)) { // TODO: fast atomic 1280 runtime·lock(&runtime·sched); 1281 if(runtime·atomicload(&runtime·sched.sysmonwait)) { 1282 runtime·atomicstore(&runtime·sched.sysmonwait, 0); 1283 runtime·notewakeup(&runtime·sched.sysmonnote); 1284 } 1285 runtime·unlock(&runtime·sched); 1286 runtime·gosave(&g->sched); // re-save for traceback 1287 } 1288 1289 m->mcache = nil; 1290 m->p->tick++; 1291 m->p->m = nil; 1292 runtime·atomicstore(&m->p->status, Psyscall); 1293 if(runtime·gcwaiting) { 1294 runtime·lock(&runtime·sched); 1295 if (runtime·sched.stopwait > 0 && runtime·cas(&m->p->status, Psyscall, Pgcstop)) { 1296 if(--runtime·sched.stopwait == 0) 1297 runtime·notewakeup(&runtime·sched.stopnote); 1298 } 1299 runtime·unlock(&runtime·sched); 1300 runtime·gosave(&g->sched); // re-save for traceback 1301 } 1302 } 1303 1304 // The same as runtime·entersyscall(), but with a hint that the syscall is blocking. 1305 #pragma textflag 7 1306 void 1307 ·entersyscallblock(int32 dummy) 1308 { 1309 P *p; 1310 1311 if(m->profilehz > 0) 1312 runtime·setprof(false); 1313 1314 // Leave SP around for gc and traceback. 1315 g->sched.sp = (uintptr)runtime·getcallersp(&dummy); 1316 g->sched.pc = runtime·getcallerpc(&dummy); 1317 g->sched.g = g; 1318 g->gcsp = g->sched.sp; 1319 g->gcpc = g->sched.pc; 1320 g->gcstack = g->stackbase; 1321 g->gcguard = g->stackguard; 1322 g->status = Gsyscall; 1323 if(g->gcsp < g->gcguard-StackGuard || g->gcstack < g->gcsp) { 1324 // runtime·printf("entersyscallblock inconsistent %p [%p,%p]\n", 1325 // g->gcsp, g->gcguard-StackGuard, g->gcstack); 1326 runtime·throw("entersyscallblock"); 1327 } 1328 1329 p = releasep(); 1330 handoffp(p); 1331 if(g->isbackground) // do not consider blocked scavenger for deadlock detection 1332 inclocked(1); 1333 runtime·gosave(&g->sched); // re-save for traceback 1334 } 1335 1336 // The goroutine g exited its system call. 1337 // Arrange for it to run on a cpu again. 1338 // This is called only from the go syscall library, not 1339 // from the low-level system calls used by the runtime. 1340 void 1341 runtime·exitsyscall(void) 1342 { 1343 P *p; 1344 1345 // Check whether the profiler needs to be turned on. 1346 if(m->profilehz > 0) 1347 runtime·setprof(true); 1348 1349 // Try to re-acquire the last P. 1350 if(m->p && m->p->status == Psyscall && runtime·cas(&m->p->status, Psyscall, Prunning)) { 1351 // There's a cpu for us, so we can run. 1352 m->mcache = m->p->mcache; 1353 m->p->m = m; 1354 m->p->tick++; 1355 g->status = Grunning; 1356 // Garbage collector isn't running (since we are), 1357 // so okay to clear gcstack and gcsp. 1358 g->gcstack = (uintptr)nil; 1359 g->gcsp = (uintptr)nil; 1360 return; 1361 } 1362 1363 if(g->isbackground) // do not consider blocked scavenger for deadlock detection 1364 inclocked(-1); 1365 // Try to get any other idle P. 1366 m->p = nil; 1367 if(runtime·sched.pidle) { 1368 runtime·lock(&runtime·sched); 1369 p = pidleget(); 1370 runtime·unlock(&runtime·sched); 1371 if(p) { 1372 acquirep(p); 1373 g->gcstack = (uintptr)nil; 1374 g->gcsp = (uintptr)nil; 1375 return; 1376 } 1377 } 1378 1379 // Call the scheduler. 1380 runtime·mcall(exitsyscall0); 1381 1382 // Scheduler returned, so we're allowed to run now. 1383 // Delete the gcstack information that we left for 1384 // the garbage collector during the system call. 1385 // Must wait until now because until gosched returns 1386 // we don't know for sure that the garbage collector 1387 // is not running. 1388 g->gcstack = (uintptr)nil; 1389 g->gcsp = (uintptr)nil; 1390 } 1391 1392 // runtime·exitsyscall slow path on g0. 1393 // Failed to acquire P, enqueue gp as runnable. 1394 static void 1395 exitsyscall0(G *gp) 1396 { 1397 P *p; 1398 1399 gp->status = Grunnable; 1400 gp->m = nil; 1401 m->curg = nil; 1402 runtime·lock(&runtime·sched); 1403 p = pidleget(); 1404 if(p == nil) 1405 globrunqput(gp); 1406 runtime·unlock(&runtime·sched); 1407 if(p) { 1408 acquirep(p); 1409 execute(gp); // Never returns. 1410 } 1411 if(m->lockedg) { 1412 // Wait until another thread schedules gp and so m again. 1413 stoplockedm(); 1414 execute(gp); // Never returns. 1415 } 1416 stopm(); 1417 schedule(); // Never returns. 1418 } 1419 1420 // Hook used by runtime·malg to call runtime·stackalloc on the 1421 // scheduler stack. This exists because runtime·stackalloc insists 1422 // on being called on the scheduler stack, to avoid trying to grow 1423 // the stack while allocating a new stack segment. 1424 static void 1425 mstackalloc(G *gp) 1426 { 1427 gp->param = runtime·stackalloc((uintptr)gp->param); 1428 runtime·gogo(&gp->sched, 0); 1429 } 1430 1431 // Allocate a new g, with a stack big enough for stacksize bytes. 1432 G* 1433 runtime·malg(int32 stacksize) 1434 { 1435 G *newg; 1436 byte *stk; 1437 1438 if(StackTop < sizeof(Stktop)) { 1439 runtime·printf("runtime: SizeofStktop=%d, should be >=%d\n", (int32)StackTop, (int32)sizeof(Stktop)); 1440 runtime·throw("runtime: bad stack.h"); 1441 } 1442 1443 newg = runtime·malloc(sizeof(G)); 1444 if(stacksize >= 0) { 1445 if(g == m->g0) { 1446 // running on scheduler stack already. 1447 stk = runtime·stackalloc(StackSystem + stacksize); 1448 } else { 1449 // have to call stackalloc on scheduler stack. 1450 g->param = (void*)(StackSystem + stacksize); 1451 runtime·mcall(mstackalloc); 1452 stk = g->param; 1453 g->param = nil; 1454 } 1455 newg->stack0 = (uintptr)stk; 1456 newg->stackguard = (uintptr)stk + StackGuard; 1457 newg->stackbase = (uintptr)stk + StackSystem + stacksize - sizeof(Stktop); 1458 runtime·memclr((byte*)newg->stackbase, sizeof(Stktop)); 1459 } 1460 return newg; 1461 } 1462 1463 // Create a new g running fn with siz bytes of arguments. 1464 // Put it on the queue of g's waiting to run. 1465 // The compiler turns a go statement into a call to this. 1466 // Cannot split the stack because it assumes that the arguments 1467 // are available sequentially after &fn; they would not be 1468 // copied if a stack split occurred. It's OK for this to call 1469 // functions that split the stack. 1470 #pragma textflag 7 1471 void 1472 runtime·newproc(int32 siz, FuncVal* fn, ...) 1473 { 1474 byte *argp; 1475 1476 if(thechar == '5') 1477 argp = (byte*)(&fn+2); // skip caller's saved LR 1478 else 1479 argp = (byte*)(&fn+1); 1480 runtime·newproc1(fn, argp, siz, 0, runtime·getcallerpc(&siz)); 1481 } 1482 1483 // Create a new g running fn with narg bytes of arguments starting 1484 // at argp and returning nret bytes of results. callerpc is the 1485 // address of the go statement that created this. The new g is put 1486 // on the queue of g's waiting to run. 1487 G* 1488 runtime·newproc1(FuncVal *fn, byte *argp, int32 narg, int32 nret, void *callerpc) 1489 { 1490 byte *sp; 1491 G *newg; 1492 int32 siz; 1493 1494 //printf("newproc1 %p %p narg=%d nret=%d\n", fn, argp, narg, nret); 1495 siz = narg + nret; 1496 siz = (siz+7) & ~7; 1497 1498 // We could instead create a secondary stack frame 1499 // and make it look like goexit was on the original but 1500 // the call to the actual goroutine function was split. 1501 // Not worth it: this is almost always an error. 1502 if(siz > StackMin - 1024) 1503 runtime·throw("runtime.newproc: function arguments too large for new goroutine"); 1504 1505 if((newg = gfget(m->p)) != nil) { 1506 if(newg->stackguard - StackGuard != newg->stack0) 1507 runtime·throw("invalid stack in newg"); 1508 } else { 1509 newg = runtime·malg(StackMin); 1510 runtime·lock(&runtime·sched); 1511 if(runtime·lastg == nil) 1512 runtime·allg = newg; 1513 else 1514 runtime·lastg->alllink = newg; 1515 runtime·lastg = newg; 1516 runtime·unlock(&runtime·sched); 1517 } 1518 1519 sp = (byte*)newg->stackbase; 1520 sp -= siz; 1521 runtime·memmove(sp, argp, narg); 1522 if(thechar == '5') { 1523 // caller's LR 1524 sp -= sizeof(void*); 1525 *(void**)sp = nil; 1526 } 1527 1528 newg->sched.sp = (uintptr)sp; 1529 newg->sched.pc = (byte*)runtime·goexit; 1530 newg->sched.g = newg; 1531 newg->fnstart = fn; 1532 newg->gopc = (uintptr)callerpc; 1533 newg->status = Grunnable; 1534 newg->goid = runtime·xadd64(&runtime·sched.goidgen, 1); 1535 if(raceenabled) 1536 newg->racectx = runtime·racegostart(callerpc); 1537 runqput(m->p, newg); 1538 1539 if(runtime·atomicload(&runtime·sched.npidle) != 0 && runtime·atomicload(&runtime·sched.nmspinning) == 0 && fn->fn != runtime·main) // TODO: fast atomic 1540 wakep(); 1541 return newg; 1542 } 1543 1544 // Put on gfree list. 1545 // If local list is too long, transfer a batch to the global list. 1546 static void 1547 gfput(P *p, G *gp) 1548 { 1549 if(gp->stackguard - StackGuard != gp->stack0) 1550 runtime·throw("invalid stack in gfput"); 1551 gp->schedlink = p->gfree; 1552 p->gfree = gp; 1553 p->gfreecnt++; 1554 if(p->gfreecnt >= 64) { 1555 runtime·lock(&runtime·sched.gflock); 1556 while(p->gfreecnt >= 32) { 1557 p->gfreecnt--; 1558 gp = p->gfree; 1559 p->gfree = gp->schedlink; 1560 gp->schedlink = runtime·sched.gfree; 1561 runtime·sched.gfree = gp; 1562 } 1563 runtime·unlock(&runtime·sched.gflock); 1564 } 1565 } 1566 1567 // Get from gfree list. 1568 // If local list is empty, grab a batch from global list. 1569 static G* 1570 gfget(P *p) 1571 { 1572 G *gp; 1573 1574 retry: 1575 gp = p->gfree; 1576 if(gp == nil && runtime·sched.gfree) { 1577 runtime·lock(&runtime·sched.gflock); 1578 while(p->gfreecnt < 32 && runtime·sched.gfree) { 1579 p->gfreecnt++; 1580 gp = runtime·sched.gfree; 1581 runtime·sched.gfree = gp->schedlink; 1582 gp->schedlink = p->gfree; 1583 p->gfree = gp; 1584 } 1585 runtime·unlock(&runtime·sched.gflock); 1586 goto retry; 1587 } 1588 if(gp) { 1589 p->gfree = gp->schedlink; 1590 p->gfreecnt--; 1591 } 1592 return gp; 1593 } 1594 1595 // Purge all cached G's from gfree list to the global list. 1596 static void 1597 gfpurge(P *p) 1598 { 1599 G *gp; 1600 1601 runtime·lock(&runtime·sched.gflock); 1602 while(p->gfreecnt) { 1603 p->gfreecnt--; 1604 gp = p->gfree; 1605 p->gfree = gp->schedlink; 1606 gp->schedlink = runtime·sched.gfree; 1607 runtime·sched.gfree = gp; 1608 } 1609 runtime·unlock(&runtime·sched.gflock); 1610 } 1611 1612 void 1613 runtime·Breakpoint(void) 1614 { 1615 runtime·breakpoint(); 1616 } 1617 1618 void 1619 runtime·Gosched(void) 1620 { 1621 runtime·gosched(); 1622 } 1623 1624 // Implementation of runtime.GOMAXPROCS. 1625 // delete when scheduler is even stronger 1626 int32 1627 runtime·gomaxprocsfunc(int32 n) 1628 { 1629 int32 ret; 1630 1631 if(n > MaxGomaxprocs) 1632 n = MaxGomaxprocs; 1633 runtime·lock(&runtime·sched); 1634 ret = runtime·gomaxprocs; 1635 if(n <= 0 || n == ret) { 1636 runtime·unlock(&runtime·sched); 1637 return ret; 1638 } 1639 runtime·unlock(&runtime·sched); 1640 1641 runtime·semacquire(&runtime·worldsema); 1642 m->gcing = 1; 1643 runtime·stoptheworld(); 1644 newprocs = n; 1645 m->gcing = 0; 1646 runtime·semrelease(&runtime·worldsema); 1647 runtime·starttheworld(); 1648 1649 return ret; 1650 } 1651 1652 static void 1653 LockOSThread(void) 1654 { 1655 m->lockedg = g; 1656 g->lockedm = m; 1657 } 1658 1659 void 1660 runtime·LockOSThread(void) 1661 { 1662 m->locked |= LockExternal; 1663 LockOSThread(); 1664 } 1665 1666 void 1667 runtime·lockOSThread(void) 1668 { 1669 m->locked += LockInternal; 1670 LockOSThread(); 1671 } 1672 1673 static void 1674 UnlockOSThread(void) 1675 { 1676 if(m->locked != 0) 1677 return; 1678 m->lockedg = nil; 1679 g->lockedm = nil; 1680 } 1681 1682 void 1683 runtime·UnlockOSThread(void) 1684 { 1685 m->locked &= ~LockExternal; 1686 UnlockOSThread(); 1687 } 1688 1689 void 1690 runtime·unlockOSThread(void) 1691 { 1692 if(m->locked < LockInternal) 1693 runtime·throw("runtime: internal error: misuse of lockOSThread/unlockOSThread"); 1694 m->locked -= LockInternal; 1695 UnlockOSThread(); 1696 } 1697 1698 bool 1699 runtime·lockedOSThread(void) 1700 { 1701 return g->lockedm != nil && m->lockedg != nil; 1702 } 1703 1704 // for testing of callbacks 1705 void 1706 runtime·golockedOSThread(bool ret) 1707 { 1708 ret = runtime·lockedOSThread(); 1709 FLUSH(&ret); 1710 } 1711 1712 // for testing of wire, unwire 1713 void 1714 runtime·mid(uint32 ret) 1715 { 1716 ret = m->id; 1717 FLUSH(&ret); 1718 } 1719 1720 void 1721 runtime·NumGoroutine(intgo ret) 1722 { 1723 ret = runtime·gcount(); 1724 FLUSH(&ret); 1725 } 1726 1727 int32 1728 runtime·gcount(void) 1729 { 1730 G *gp; 1731 int32 n, s; 1732 1733 n = 0; 1734 runtime·lock(&runtime·sched); 1735 // TODO(dvyukov): runtime.NumGoroutine() is O(N). 1736 // We do not want to increment/decrement centralized counter in newproc/goexit, 1737 // just to make runtime.NumGoroutine() faster. 1738 // Compromise solution is to introduce per-P counters of active goroutines. 1739 for(gp = runtime·allg; gp; gp = gp->alllink) { 1740 s = gp->status; 1741 if(s == Grunnable || s == Grunning || s == Gsyscall || s == Gwaiting) 1742 n++; 1743 } 1744 runtime·unlock(&runtime·sched); 1745 return n; 1746 } 1747 1748 int32 1749 runtime·mcount(void) 1750 { 1751 return runtime·sched.mcount; 1752 } 1753 1754 void 1755 runtime·badmcall(void) // called from assembly 1756 { 1757 runtime·throw("runtime: mcall called on m->g0 stack"); 1758 } 1759 1760 void 1761 runtime·badmcall2(void) // called from assembly 1762 { 1763 runtime·throw("runtime: mcall function returned"); 1764 } 1765 1766 static struct { 1767 Lock; 1768 void (*fn)(uintptr*, int32); 1769 int32 hz; 1770 uintptr pcbuf[100]; 1771 } prof; 1772 1773 // Called if we receive a SIGPROF signal. 1774 void 1775 runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp) 1776 { 1777 int32 n; 1778 1779 // Windows does profiling in a dedicated thread w/o m. 1780 if(!Windows && (m == nil || m->mcache == nil)) 1781 return; 1782 if(prof.fn == nil || prof.hz == 0) 1783 return; 1784 1785 runtime·lock(&prof); 1786 if(prof.fn == nil) { 1787 runtime·unlock(&prof); 1788 return; 1789 } 1790 n = runtime·gentraceback(pc, sp, lr, gp, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil); 1791 if(n > 0) 1792 prof.fn(prof.pcbuf, n); 1793 runtime·unlock(&prof); 1794 } 1795 1796 // Arrange to call fn with a traceback hz times a second. 1797 void 1798 runtime·setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz) 1799 { 1800 // Force sane arguments. 1801 if(hz < 0) 1802 hz = 0; 1803 if(hz == 0) 1804 fn = nil; 1805 if(fn == nil) 1806 hz = 0; 1807 1808 // Stop profiler on this cpu so that it is safe to lock prof. 1809 // if a profiling signal came in while we had prof locked, 1810 // it would deadlock. 1811 runtime·resetcpuprofiler(0); 1812 1813 runtime·lock(&prof); 1814 prof.fn = fn; 1815 prof.hz = hz; 1816 runtime·unlock(&prof); 1817 runtime·lock(&runtime·sched); 1818 runtime·sched.profilehz = hz; 1819 runtime·unlock(&runtime·sched); 1820 1821 if(hz != 0) 1822 runtime·resetcpuprofiler(hz); 1823 } 1824 1825 // Change number of processors. The world is stopped, sched is locked. 1826 static void 1827 procresize(int32 new) 1828 { 1829 int32 i, old; 1830 G *gp; 1831 P *p; 1832 1833 old = runtime·gomaxprocs; 1834 if(old < 0 || old > MaxGomaxprocs || new <= 0 || new >MaxGomaxprocs) 1835 runtime·throw("procresize: invalid arg"); 1836 // initialize new P's 1837 for(i = 0; i < new; i++) { 1838 p = runtime·allp[i]; 1839 if(p == nil) { 1840 p = (P*)runtime·mallocgc(sizeof(*p), 0, 0, 1); 1841 p->status = Pgcstop; 1842 runtime·atomicstorep(&runtime·allp[i], p); 1843 } 1844 if(p->mcache == nil) { 1845 if(old==0 && i==0) 1846 p->mcache = m->mcache; // bootstrap 1847 else 1848 p->mcache = runtime·allocmcache(); 1849 } 1850 if(p->runq == nil) { 1851 p->runqsize = 128; 1852 p->runq = (G**)runtime·mallocgc(p->runqsize*sizeof(G*), 0, 0, 1); 1853 } 1854 } 1855 1856 // redistribute runnable G's evenly 1857 for(i = 0; i < old; i++) { 1858 p = runtime·allp[i]; 1859 while(gp = runqget(p)) 1860 globrunqput(gp); 1861 } 1862 // start at 1 because current M already executes some G and will acquire allp[0] below, 1863 // so if we have a spare G we want to put it into allp[1]. 1864 for(i = 1; runtime·sched.runqhead; i++) { 1865 gp = runtime·sched.runqhead; 1866 runtime·sched.runqhead = gp->schedlink; 1867 runqput(runtime·allp[i%new], gp); 1868 } 1869 runtime·sched.runqtail = nil; 1870 runtime·sched.runqsize = 0; 1871 1872 // free unused P's 1873 for(i = new; i < old; i++) { 1874 p = runtime·allp[i]; 1875 runtime·freemcache(p->mcache); 1876 p->mcache = nil; 1877 gfpurge(p); 1878 p->status = Pdead; 1879 // can't free P itself because it can be referenced by an M in syscall 1880 } 1881 1882 if(m->p) 1883 m->p->m = nil; 1884 m->p = nil; 1885 m->mcache = nil; 1886 p = runtime·allp[0]; 1887 p->m = nil; 1888 p->status = Pidle; 1889 acquirep(p); 1890 for(i = new-1; i > 0; i--) { 1891 p = runtime·allp[i]; 1892 p->status = Pidle; 1893 pidleput(p); 1894 } 1895 runtime·singleproc = new == 1; 1896 runtime·atomicstore((uint32*)&runtime·gomaxprocs, new); 1897 } 1898 1899 // Associate p and the current m. 1900 static void 1901 acquirep(P *p) 1902 { 1903 if(m->p || m->mcache) 1904 runtime·throw("acquirep: already in go"); 1905 if(p->m || p->status != Pidle) { 1906 runtime·printf("acquirep: p->m=%p(%d) p->status=%d\n", p->m, p->m ? p->m->id : 0, p->status); 1907 runtime·throw("acquirep: invalid p state"); 1908 } 1909 m->mcache = p->mcache; 1910 m->p = p; 1911 p->m = m; 1912 p->status = Prunning; 1913 } 1914 1915 // Disassociate p and the current m. 1916 static P* 1917 releasep(void) 1918 { 1919 P *p; 1920 1921 if(m->p == nil || m->mcache == nil) 1922 runtime·throw("releasep: invalid arg"); 1923 p = m->p; 1924 if(p->m != m || p->mcache != m->mcache || p->status != Prunning) { 1925 runtime·printf("releasep: m=%p m->p=%p p->m=%p m->mcache=%p p->mcache=%p p->status=%d\n", 1926 m, m->p, p->m, m->mcache, p->mcache, p->status); 1927 runtime·throw("releasep: invalid p state"); 1928 } 1929 m->p = nil; 1930 m->mcache = nil; 1931 p->m = nil; 1932 p->status = Pidle; 1933 return p; 1934 } 1935 1936 static void 1937 inclocked(int32 v) 1938 { 1939 runtime·lock(&runtime·sched); 1940 runtime·sched.mlocked += v; 1941 if(v > 0) 1942 checkdead(); 1943 runtime·unlock(&runtime·sched); 1944 } 1945 1946 // Check for deadlock situation. 1947 // The check is based on number of running M's, if 0 -> deadlock. 1948 static void 1949 checkdead(void) 1950 { 1951 G *gp; 1952 int32 run, grunning, s; 1953 1954 // -1 for sysmon 1955 run = runtime·sched.mcount - runtime·sched.nmidle - runtime·sched.mlocked - 1; 1956 if(run > 0) 1957 return; 1958 if(run < 0) { 1959 runtime·printf("checkdead: nmidle=%d mlocked=%d mcount=%d\n", 1960 runtime·sched.nmidle, runtime·sched.mlocked, runtime·sched.mcount); 1961 runtime·throw("checkdead: inconsistent counts"); 1962 } 1963 grunning = 0; 1964 for(gp = runtime·allg; gp; gp = gp->alllink) { 1965 if(gp->isbackground) 1966 continue; 1967 s = gp->status; 1968 if(s == Gwaiting) 1969 grunning++; 1970 else if(s == Grunnable || s == Grunning || s == Gsyscall) { 1971 runtime·printf("checkdead: find g %D in status %d\n", gp->goid, s); 1972 runtime·throw("checkdead: runnable g"); 1973 } 1974 } 1975 if(grunning == 0) // possible if main goroutine calls runtime·Goexit() 1976 runtime·exit(0); 1977 m->throwing = -1; // do not dump full stacks 1978 runtime·throw("all goroutines are asleep - deadlock!"); 1979 } 1980 1981 static void 1982 sysmon(void) 1983 { 1984 uint32 idle, delay; 1985 int64 now, lastpoll; 1986 G *gp; 1987 uint32 ticks[MaxGomaxprocs]; 1988 1989 idle = 0; // how many cycles in succession we had not wokeup somebody 1990 delay = 0; 1991 for(;;) { 1992 if(idle == 0) // start with 20us sleep... 1993 delay = 20; 1994 else if(idle > 50) // start doubling the sleep after 1ms... 1995 delay *= 2; 1996 if(delay > 10*1000) // up to 10ms 1997 delay = 10*1000; 1998 runtime·usleep(delay); 1999 if(runtime·gcwaiting || runtime·atomicload(&runtime·sched.npidle) == runtime·gomaxprocs) { // TODO: fast atomic 2000 runtime·lock(&runtime·sched); 2001 if(runtime·atomicload(&runtime·gcwaiting) || runtime·atomicload(&runtime·sched.npidle) == runtime·gomaxprocs) { 2002 runtime·atomicstore(&runtime·sched.sysmonwait, 1); 2003 runtime·unlock(&runtime·sched); 2004 runtime·notesleep(&runtime·sched.sysmonnote); 2005 runtime·noteclear(&runtime·sched.sysmonnote); 2006 idle = 0; 2007 delay = 20; 2008 } else 2009 runtime·unlock(&runtime·sched); 2010 } 2011 // poll network if not polled for more than 10ms 2012 lastpoll = runtime·atomicload64(&runtime·sched.lastpoll); 2013 now = runtime·nanotime(); 2014 if(lastpoll != 0 && lastpoll + 10*1000*1000 > now) { 2015 gp = runtime·netpoll(false); // non-blocking 2016 injectglist(gp); 2017 } 2018 // retake P's blocked in syscalls 2019 if(retake(ticks)) 2020 idle = 0; 2021 else 2022 idle++; 2023 } 2024 } 2025 2026 static uint32 2027 retake(uint32 *ticks) 2028 { 2029 uint32 i, s, n; 2030 int64 t; 2031 P *p; 2032 2033 n = 0; 2034 for(i = 0; i < runtime·gomaxprocs; i++) { 2035 p = runtime·allp[i]; 2036 if(p==nil) 2037 continue; 2038 t = p->tick; 2039 if(ticks[i] != t) { 2040 ticks[i] = t; 2041 continue; 2042 } 2043 s = p->status; 2044 if(s != Psyscall) 2045 continue; 2046 if(p->runqhead == p->runqtail && runtime·atomicload(&runtime·sched.nmspinning) + runtime·atomicload(&runtime·sched.npidle) > 0) // TODO: fast atomic 2047 continue; 2048 // Need to increment number of locked M's before the CAS. 2049 // Otherwise the M from which we retake can exit the syscall, 2050 // increment nmidle and report deadlock. 2051 inclocked(-1); 2052 if(runtime·cas(&p->status, s, Pidle)) { 2053 n++; 2054 handoffp(p); 2055 } 2056 inclocked(1); 2057 } 2058 return n; 2059 } 2060 2061 // Put mp on midle list. 2062 // Sched must be locked. 2063 static void 2064 mput(M *mp) 2065 { 2066 mp->schedlink = runtime·sched.midle; 2067 runtime·sched.midle = mp; 2068 runtime·sched.nmidle++; 2069 checkdead(); 2070 } 2071 2072 // Try to get an m from midle list. 2073 // Sched must be locked. 2074 static M* 2075 mget(void) 2076 { 2077 M *mp; 2078 2079 if((mp = runtime·sched.midle) != nil){ 2080 runtime·sched.midle = mp->schedlink; 2081 runtime·sched.nmidle--; 2082 } 2083 return mp; 2084 } 2085 2086 // Put gp on the global runnable queue. 2087 // Sched must be locked. 2088 static void 2089 globrunqput(G *gp) 2090 { 2091 gp->schedlink = nil; 2092 if(runtime·sched.runqtail) 2093 runtime·sched.runqtail->schedlink = gp; 2094 else 2095 runtime·sched.runqhead = gp; 2096 runtime·sched.runqtail = gp; 2097 runtime·sched.runqsize++; 2098 } 2099 2100 // Try get a batch of G's from the global runnable queue. 2101 // Sched must be locked. 2102 static G* 2103 globrunqget(P *p) 2104 { 2105 G *gp, *gp1; 2106 int32 n; 2107 2108 if(runtime·sched.runqsize == 0) 2109 return nil; 2110 n = runtime·sched.runqsize/runtime·gomaxprocs+1; 2111 if(n > runtime·sched.runqsize) 2112 n = runtime·sched.runqsize; 2113 runtime·sched.runqsize -= n; 2114 if(runtime·sched.runqsize == 0) 2115 runtime·sched.runqtail = nil; 2116 gp = runtime·sched.runqhead; 2117 runtime·sched.runqhead = gp->schedlink; 2118 n--; 2119 while(n--) { 2120 gp1 = runtime·sched.runqhead; 2121 runtime·sched.runqhead = gp1->schedlink; 2122 runqput(p, gp1); 2123 } 2124 return gp; 2125 } 2126 2127 // Put p to on pidle list. 2128 // Sched must be locked. 2129 static void 2130 pidleput(P *p) 2131 { 2132 p->link = runtime·sched.pidle; 2133 runtime·sched.pidle = p; 2134 runtime·xadd(&runtime·sched.npidle, 1); // TODO: fast atomic 2135 } 2136 2137 // Try get a p from pidle list. 2138 // Sched must be locked. 2139 static P* 2140 pidleget(void) 2141 { 2142 P *p; 2143 2144 p = runtime·sched.pidle; 2145 if(p) { 2146 runtime·sched.pidle = p->link; 2147 runtime·xadd(&runtime·sched.npidle, -1); // TODO: fast atomic 2148 } 2149 return p; 2150 } 2151 2152 // Put g on local runnable queue. 2153 // TODO(dvyukov): consider using lock-free queue. 2154 static void 2155 runqput(P *p, G *gp) 2156 { 2157 int32 h, t, s; 2158 2159 runtime·lock(p); 2160 retry: 2161 h = p->runqhead; 2162 t = p->runqtail; 2163 s = p->runqsize; 2164 if(t == h-1 || (h == 0 && t == s-1)) { 2165 runqgrow(p); 2166 goto retry; 2167 } 2168 p->runq[t++] = gp; 2169 if(t == s) 2170 t = 0; 2171 p->runqtail = t; 2172 runtime·unlock(p); 2173 } 2174 2175 // Get g from local runnable queue. 2176 static G* 2177 runqget(P *p) 2178 { 2179 G *gp; 2180 int32 t, h, s; 2181 2182 if(p->runqhead == p->runqtail) 2183 return nil; 2184 runtime·lock(p); 2185 h = p->runqhead; 2186 t = p->runqtail; 2187 s = p->runqsize; 2188 if(t == h) { 2189 runtime·unlock(p); 2190 return nil; 2191 } 2192 gp = p->runq[h++]; 2193 if(h == s) 2194 h = 0; 2195 p->runqhead = h; 2196 runtime·unlock(p); 2197 return gp; 2198 } 2199 2200 // Grow local runnable queue. 2201 // TODO(dvyukov): consider using fixed-size array 2202 // and transfer excess to the global list (local queue can grow way too big). 2203 static void 2204 runqgrow(P *p) 2205 { 2206 G **q; 2207 int32 s, t, h, t2; 2208 2209 h = p->runqhead; 2210 t = p->runqtail; 2211 s = p->runqsize; 2212 t2 = 0; 2213 q = runtime·malloc(2*s*sizeof(*q)); 2214 while(t != h) { 2215 q[t2++] = p->runq[h++]; 2216 if(h == s) 2217 h = 0; 2218 } 2219 runtime·free(p->runq); 2220 p->runq = q; 2221 p->runqhead = 0; 2222 p->runqtail = t2; 2223 p->runqsize = 2*s; 2224 } 2225 2226 // Steal half of elements from local runnable queue of p2 2227 // and put onto local runnable queue of p. 2228 // Returns one of the stolen elements (or nil if failed). 2229 static G* 2230 runqsteal(P *p, P *p2) 2231 { 2232 G *gp, *gp1; 2233 int32 t, h, s, t2, h2, s2, c, i; 2234 2235 if(p2->runqhead == p2->runqtail) 2236 return nil; 2237 // sort locks to prevent deadlocks 2238 if(p < p2) 2239 runtime·lock(p); 2240 runtime·lock(p2); 2241 if(p2->runqhead == p2->runqtail) { 2242 runtime·unlock(p2); 2243 if(p < p2) 2244 runtime·unlock(p); 2245 return nil; 2246 } 2247 if(p >= p2) 2248 runtime·lock(p); 2249 // now we've locked both queues and know the victim is not empty 2250 h = p->runqhead; 2251 t = p->runqtail; 2252 s = p->runqsize; 2253 h2 = p2->runqhead; 2254 t2 = p2->runqtail; 2255 s2 = p2->runqsize; 2256 gp = p2->runq[h2++]; // return value 2257 if(h2 == s2) 2258 h2 = 0; 2259 // steal roughly half 2260 if(t2 > h2) 2261 c = (t2 - h2) / 2; 2262 else 2263 c = (s2 - h2 + t2) / 2; 2264 // copy 2265 for(i = 0; i != c; i++) { 2266 // the target queue is full? 2267 if(t == h-1 || (h == 0 && t == s-1)) 2268 break; 2269 // the victim queue is empty? 2270 if(t2 == h2) 2271 break; 2272 gp1 = p2->runq[h2++]; 2273 if(h2 == s2) 2274 h2 = 0; 2275 p->runq[t++] = gp1; 2276 if(t == s) 2277 t = 0; 2278 } 2279 p->runqtail = t; 2280 p2->runqhead = h2; 2281 runtime·unlock(p2); 2282 runtime·unlock(p); 2283 return gp; 2284 } 2285 2286 void 2287 runtime·testSchedLocalQueue(void) 2288 { 2289 P p; 2290 G gs[1000]; 2291 int32 i, j; 2292 2293 runtime·memclr((byte*)&p, sizeof(p)); 2294 p.runqsize = 1; 2295 p.runqhead = 0; 2296 p.runqtail = 0; 2297 p.runq = runtime·malloc(p.runqsize*sizeof(*p.runq)); 2298 2299 for(i = 0; i < nelem(gs); i++) { 2300 if(runqget(&p) != nil) 2301 runtime·throw("runq is not empty initially"); 2302 for(j = 0; j < i; j++) 2303 runqput(&p, &gs[i]); 2304 for(j = 0; j < i; j++) { 2305 if(runqget(&p) != &gs[i]) { 2306 runtime·printf("bad element at iter %d/%d\n", i, j); 2307 runtime·throw("bad element"); 2308 } 2309 } 2310 if(runqget(&p) != nil) 2311 runtime·throw("runq is not empty afterwards"); 2312 } 2313 } 2314 2315 void 2316 runtime·testSchedLocalQueueSteal(void) 2317 { 2318 P p1, p2; 2319 G gs[1000], *gp; 2320 int32 i, j, s; 2321 2322 runtime·memclr((byte*)&p1, sizeof(p1)); 2323 p1.runqsize = 1; 2324 p1.runqhead = 0; 2325 p1.runqtail = 0; 2326 p1.runq = runtime·malloc(p1.runqsize*sizeof(*p1.runq)); 2327 2328 runtime·memclr((byte*)&p2, sizeof(p2)); 2329 p2.runqsize = nelem(gs); 2330 p2.runqhead = 0; 2331 p2.runqtail = 0; 2332 p2.runq = runtime·malloc(p2.runqsize*sizeof(*p2.runq)); 2333 2334 for(i = 0; i < nelem(gs); i++) { 2335 for(j = 0; j < i; j++) { 2336 gs[j].sig = 0; 2337 runqput(&p1, &gs[j]); 2338 } 2339 gp = runqsteal(&p2, &p1); 2340 s = 0; 2341 if(gp) { 2342 s++; 2343 gp->sig++; 2344 } 2345 while(gp = runqget(&p2)) { 2346 s++; 2347 gp->sig++; 2348 } 2349 while(gp = runqget(&p1)) 2350 gp->sig++; 2351 for(j = 0; j < i; j++) { 2352 if(gs[j].sig != 1) { 2353 runtime·printf("bad element %d(%d) at iter %d\n", j, gs[j].sig, i); 2354 runtime·throw("bad element"); 2355 } 2356 } 2357 if(s != i/2 && s != i/2+1) { 2358 runtime·printf("bad steal %d, want %d or %d, iter %d\n", 2359 s, i/2, i/2+1, i); 2360 runtime·throw("bad steal"); 2361 } 2362 } 2363 } 2364