LEFT | RIGHT |
1 // Copyright 2009 The Go Authors. All rights reserved. | 1 // Copyright 2009 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 #include "runtime.h" | 5 #include "runtime.h" |
6 #include "arch_GOARCH.h" | 6 #include "arch_GOARCH.h" |
7 #include "defs_GOOS_GOARCH.h" | 7 #include "defs_GOOS_GOARCH.h" |
8 #include "malloc.h" | 8 #include "malloc.h" |
9 #include "os_GOOS.h" | 9 #include "os_GOOS.h" |
10 #include "stack.h" | 10 #include "stack.h" |
| 11 #include "race.h" |
| 12 #include "type.h" |
11 | 13 |
12 // TODO(dvyukov): if a thread w/o mcache catches a signal (in particular SIGABOR
T), | 14 // TODO(dvyukov): if a thread w/o mcache catches a signal (in particular SIGABOR
T), |
13 // then it can't print dump. | 15 // then it can't print dump. |
14 | 16 |
15 enum { maxgomaxprocs = 1<<10 }; | 17 enum { maxgomaxprocs = 1<<10 }; |
16 #define LOG if(0) runtime·printf | 18 #define LOG if(0) runtime·printf |
17 #define LOG1 runtime·printf | 19 #define LOG1 runtime·printf |
18 #define CHECK(cond, fmt) if(cond) {} else { runtime·printf fmt; runtime·throw("C
HECK"); } | 20 #define CHECK(cond, fmt) /*if(cond) {} else { runtime·printf fmt; runtime·throw(
"CHECK"); }*/ |
19 | 21 |
20 // Go scheduler | 22 // Go scheduler |
21 // | 23 // |
22 // The go scheduler's job is to match ready-to-run goroutines (`g's) | 24 // The go scheduler's job is to match ready-to-run goroutines (`g's) |
23 // with waiting-for-work schedulers (`m's). If there are ready g's | 25 // with waiting-for-work schedulers (`m's). If there are ready g's |
24 // and no waiting m's, ready() will start a new m running in a new | 26 // and no waiting m's, ready() will start a new m running in a new |
25 // OS thread, so that all ready g's can run simultaneously, up to a limit. | 27 // OS thread, so that all ready g's can run simultaneously, up to a limit. |
26 // For now, m's never go away. | 28 // For now, m's never go away. |
27 // | 29 // |
28 // By default, Go keeps only one kernel thread (m) running user code | 30 // By default, Go keeps only one kernel thread (m) running user code |
(...skipping 24 matching lines...) Expand all Loading... |
53 int32 runqsize; | 55 int32 runqsize; |
54 | 56 |
55 Lock gflock; | 57 Lock gflock; |
56 G* gfree; | 58 G* gfree; |
57 int32 goidseq; | 59 int32 goidseq; |
58 | 60 |
59 int32 stopwait; | 61 int32 stopwait; |
60 Note stopnote; | 62 Note stopnote; |
61 int32 sysmonwait; | 63 int32 sysmonwait; |
62 Note sysmonnote; | 64 Note sysmonnote; |
63 int32 netmonwait; | |
64 Note netmonnote; | |
65 | 65 |
66 int32 profilehz; // cpu profiling rate | 66 int32 profilehz; // cpu profiling rate |
67 | 67 |
68 bool init; // running initialization | 68 bool init; // running initialization |
69 bool lockmain; // init called runtime.LockOSThread | 69 bool lockmain; // init called runtime.LockOSThread |
70 }; | 70 }; |
71 | 71 |
72 Sched runtime·sched; | 72 Sched runtime·sched; |
73 int32 runtime·gomaxprocs; | 73 int32 runtime·gomaxprocs; |
74 bool runtime·singleproc; | 74 bool runtime·singleproc; |
(...skipping 20 matching lines...) Expand all Loading... |
95 static void mcommoninit(M*); | 95 static void mcommoninit(M*); |
96 static void schedule(void); | 96 static void schedule(void); |
97 static void procresize(int32); | 97 static void procresize(int32); |
98 static void entergo(M*, P*); | 98 static void entergo(M*, P*); |
99 static P* releasep(void); | 99 static P* releasep(void); |
100 static M* newm(void(*)(void), P*, bool); | 100 static M* newm(void(*)(void), P*, bool); |
101 static void goidle(void); | 101 static void goidle(void); |
102 static void mstop(void); | 102 static void mstop(void); |
103 static void initgstack(G*, byte*, int32); | 103 static void initgstack(G*, byte*, int32); |
104 static void sysmon(void); | 104 static void sysmon(void); |
105 static void netmon(void); | |
106 static void inject(G*, int32*, int32*); | 105 static void inject(G*, int32*, int32*); |
107 static P* pidleget(void); | 106 static P* pidleget(void); |
108 static void pidleput(P*); | 107 static void pidleput(P*); |
109 | 108 |
110 // The bootstrap sequence is: | 109 // The bootstrap sequence is: |
111 // | 110 // |
112 // call osinit | 111 // call osinit |
113 // call schedinit | 112 // call schedinit |
114 // make & queue new G | 113 // make & queue new G |
115 // call runtime·mstart | 114 // call runtime·mstart |
(...skipping 26 matching lines...) Expand all Loading... |
142 if(p != nil && (n = runtime·atoi(p)) > 0) { | 141 if(p != nil && (n = runtime·atoi(p)) > 0) { |
143 if(n > maxgomaxprocs) | 142 if(n > maxgomaxprocs) |
144 n = maxgomaxprocs; | 143 n = maxgomaxprocs; |
145 procs = n; | 144 procs = n; |
146 } | 145 } |
147 runtime·allp = (P**)runtime·malloc((maxgomaxprocs+1)*sizeof(runtime·allp
[0])); | 146 runtime·allp = (P**)runtime·malloc((maxgomaxprocs+1)*sizeof(runtime·allp
[0])); |
148 procresize(procs); | 147 procresize(procs); |
149 | 148 |
150 mstats.enablegc = 1; | 149 mstats.enablegc = 1; |
151 m->nomemprof--; | 150 m->nomemprof--; |
| 151 |
| 152 if(raceenabled) |
| 153 runtime·raceinit(); |
152 } | 154 } |
153 | 155 |
154 extern void main·init(void); | 156 extern void main·init(void); |
155 extern void main·main(void); | 157 extern void main·main(void); |
156 | 158 |
157 // The main goroutine. | 159 // The main goroutine. |
158 void | 160 void |
159 runtime·main(void) | 161 runtime·main(void) |
160 { | 162 { |
161 LOG("%d: runtime·main\n", m->id); | 163 LOG("%d: runtime·main\n", m->id); |
162 | 164 |
163 //TODO(dvyukov): block signals because that thread can't handle them | 165 //TODO(dvyukov): block signals because that thread can't handle them |
164 newm(sysmon, nil, false); | 166 newm(sysmon, nil, false); |
165 newm(netmon, nil, false); | |
166 | 167 |
167 // Lock the main goroutine onto this, the main OS thread, | 168 // Lock the main goroutine onto this, the main OS thread, |
168 // during initialization. Most programs won't care, but a few | 169 // during initialization. Most programs won't care, but a few |
169 // do require certain calls to be made by the main thread. | 170 // do require certain calls to be made by the main thread. |
170 // Those can arrange for main.main to run in the main thread | 171 // Those can arrange for main.main to run in the main thread |
171 // by calling runtime.LockOSThread during initialization | 172 // by calling runtime.LockOSThread during initialization |
172 // to preserve the lock. | 173 // to preserve the lock. |
173 runtime·LockOSThread(); | 174 runtime·LockOSThread(); |
174 runtime·sched.init = true; | 175 runtime·sched.init = true; |
175 if(m != &runtime·m0) | 176 if(m != &runtime·m0) |
176 runtime·throw("runtime·main not on m0"); | 177 runtime·throw("runtime·main not on m0"); |
177 scvg = runtime·newproc1((byte*)runtime·MHeap_Scavenger, nil, 0, 0, runti
me·main); | 178 scvg = runtime·newproc1((byte*)runtime·MHeap_Scavenger, nil, 0, 0, runti
me·main); |
178 main·init(); | 179 main·init(); |
179 runtime·sched.init = false; | 180 runtime·sched.init = false; |
180 if(!runtime·sched.lockmain) | 181 if(!runtime·sched.lockmain) |
181 runtime·UnlockOSThread(); | 182 runtime·UnlockOSThread(); |
182 | 183 |
183 main·main(); | 184 main·main(); |
| 185 if(raceenabled) |
| 186 runtime·racefini(); |
184 runtime·exit(0); | 187 runtime·exit(0); |
185 for(;;) | 188 for(;;) |
186 *(int32*)runtime·main = 0; | 189 *(int32*)runtime·main = 0; |
187 } | 190 } |
188 | 191 |
189 void | 192 void |
190 runtime·goroutineheader(G *gp) | 193 runtime·goroutineheader(G *gp) |
191 { | 194 { |
192 int8 *status; | 195 int8 *status; |
193 | 196 |
(...skipping 13 matching lines...) Expand all Loading... |
207 case Gwaiting: | 210 case Gwaiting: |
208 if(gp->waitreason) | 211 if(gp->waitreason) |
209 status = gp->waitreason; | 212 status = gp->waitreason; |
210 else | 213 else |
211 status = "waiting"; | 214 status = "waiting"; |
212 break; | 215 break; |
213 default: | 216 default: |
214 status = "???"; | 217 status = "???"; |
215 break; | 218 break; |
216 } | 219 } |
217 » runtime·printf("goroutine %d [%s]:\n", gp->goid, status); | 220 » runtime·printf("goroutine %D [%s]:\n", gp->goid, status); |
218 } | 221 } |
219 | 222 |
220 void | 223 void |
221 runtime·tracebackothers(G *me) | 224 runtime·tracebackothers(G *me) |
222 { | 225 { |
223 G *gp; | 226 G *gp; |
224 | 227 |
225 for(gp = runtime·allg; gp != nil; gp = gp->alllink) { | 228 for(gp = runtime·allg; gp != nil; gp = gp->alllink) { |
226 if(gp == me || gp->status == Gdead) | 229 if(gp == me || gp->status == Gdead) |
227 continue; | 230 continue; |
(...skipping 29 matching lines...) Expand all Loading... |
257 runtime·ready(G *gp) | 260 runtime·ready(G *gp) |
258 { | 261 { |
259 P *p; | 262 P *p; |
260 M *mp; | 263 M *mp; |
261 | 264 |
262 if(gp->m) | 265 if(gp->m) |
263 runtime·throw("bad g->m in ready"); | 266 runtime·throw("bad g->m in ready"); |
264 | 267 |
265 // Mark runnable. | 268 // Mark runnable. |
266 if(gp->status == Grunnable || gp->status == Grunning) { | 269 if(gp->status == Grunnable || gp->status == Grunning) { |
267 » » runtime·printf("goroutine %p has status %d\n", gp, gp->status); | 270 » » runtime·printf("goroutine %D has status %d\n", gp->goid, gp->sta
tus); |
268 runtime·throw("bad g->status in ready"); | 271 runtime·throw("bad g->status in ready"); |
269 } | 272 } |
270 gp->status = Grunnable; | 273 gp->status = Grunnable; |
271 runqput(m->p, gp); | 274 runqput(m->p, gp); |
272 if(runtime·sched.pidle) { | 275 if(runtime·sched.pidle) { |
273 runtime·lock(&runtime·sched); | 276 runtime·lock(&runtime·sched); |
274 p = pidleget(); | 277 p = pidleget(); |
275 if(p) { | 278 if(p) { |
276 mp = mget(); | 279 mp = mget(); |
277 runtime·unlock(&runtime·sched); | 280 runtime·unlock(&runtime·sched); |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
376 LOG("%d: stoptheworld stopped\n", m->id); | 379 LOG("%d: stoptheworld stopped\n", m->id); |
377 CHECK(runtime·sched.stopwait == 0, ("stoptheworld: stopwait == %d\n", ru
ntime·sched.stopwait)); | 380 CHECK(runtime·sched.stopwait == 0, ("stoptheworld: stopwait == %d\n", ru
ntime·sched.stopwait)); |
378 for(i=0; i<runtime·gomaxprocs; i++) { | 381 for(i=0; i<runtime·gomaxprocs; i++) { |
379 CHECK(runtime·allp[i]->status == Plocked, ("stoptheworld: not st
opped (%d)\n", runtime·allp[i]->status)); | 382 CHECK(runtime·allp[i]->status == Plocked, ("stoptheworld: not st
opped (%d)\n", runtime·allp[i]->status)); |
380 } | 383 } |
381 } | 384 } |
382 | 385 |
383 void | 386 void |
384 runtime·starttheworld(void) | 387 runtime·starttheworld(void) |
385 { | 388 { |
386 » G *gp; | 389 » //G *gp; |
387 » P *p; | 390 » //P *p; |
388 » M *mp; | 391 » //M *mp; |
389 » int32 n, w; | 392 » //int32 n, w; |
390 | 393 |
391 LOG("%d: starttheworld\n", m->id); | 394 LOG("%d: starttheworld\n", m->id); |
392 runtime·gcwaiting = 0; | 395 runtime·gcwaiting = 0; |
393 if(newprocs) { | 396 if(newprocs) { |
394 procresize(newprocs); | 397 procresize(newprocs); |
395 newprocs = 0; | 398 newprocs = 0; |
396 } else { | 399 } else { |
397 procresize(runtime·gomaxprocs); | 400 procresize(runtime·gomaxprocs); |
398 } | 401 } |
399 » gp = runtime·netwait(0); | 402 » runtime·lock(&runtime·sched); |
| 403 » /* |
| 404 » gp = runtime·netwait(0, runtime·gomaxprocs); |
400 n = w = 0; | 405 n = w = 0; |
401 inject(gp, &w, &n); | 406 inject(gp, &w, &n); |
402 runtime·lock(&runtime·sched); | |
403 while(runtime·sched.pidle) { | 407 while(runtime·sched.pidle) { |
404 p = pidleget(); | 408 p = pidleget(); |
405 mp = mget(); | 409 mp = mget(); |
406 if(mp) { | 410 if(mp) { |
407 entergo(mp, p); | 411 entergo(mp, p); |
408 runtime·notewakeup(&mp->park); | 412 runtime·notewakeup(&mp->park); |
409 } else { | 413 } else { |
410 runtime·unlock(&runtime·sched); | 414 runtime·unlock(&runtime·sched); |
411 newm(runtime·mstart, p, false); | 415 newm(runtime·mstart, p, false); |
412 runtime·lock(&runtime·sched); | 416 runtime·lock(&runtime·sched); |
413 } | 417 } |
414 } | 418 } |
| 419 */ |
415 if(runtime·sched.sysmonwait) { | 420 if(runtime·sched.sysmonwait) { |
416 runtime·sched.sysmonwait = 0; | 421 runtime·sched.sysmonwait = 0; |
417 runtime·notewakeup(&runtime·sched.sysmonnote); | 422 runtime·notewakeup(&runtime·sched.sysmonnote); |
418 } | |
419 if(runtime·sched.netmonwait) { | |
420 runtime·sched.netmonwait = 0; | |
421 runtime·notewakeup(&runtime·sched.netmonnote); | |
422 } | 423 } |
423 runtime·unlock(&runtime·sched); | 424 runtime·unlock(&runtime·sched); |
424 } | 425 } |
425 | 426 |
426 // Called to start an M. | 427 // Called to start an M. |
427 void | 428 void |
428 runtime·mstart(void) | 429 runtime·mstart(void) |
429 { | 430 { |
430 // It is used by windows-386 only. Unfortunately, seh needs | 431 // It is used by windows-386 only. Unfortunately, seh needs |
431 // to be located on os stack, and mstart runs on os stack | 432 // to be located on os stack, and mstart runs on os stack |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
494 newg->stackbase = (uintptr)stk + stacksize - sizeof(Stktop); | 495 newg->stackbase = (uintptr)stk + stacksize - sizeof(Stktop); |
495 runtime·memclr((byte*)newg->stackbase, sizeof(Stktop)); | 496 runtime·memclr((byte*)newg->stackbase, sizeof(Stktop)); |
496 } | 497 } |
497 | 498 |
498 // Create a new m. It will start off with a call to runtime·mstart. | 499 // Create a new m. It will start off with a call to runtime·mstart. |
499 static M* | 500 static M* |
500 newm(void(*fn)(void), P *p, bool helpgc) | 501 newm(void(*fn)(void), P *p, bool helpgc) |
501 { | 502 { |
502 M *mp; | 503 M *mp; |
503 int32 addmem,stksiz, stkoff; | 504 int32 addmem,stksiz, stkoff; |
| 505 //!!!static Type *mtype; // The Go type M |
504 | 506 |
505 LOG("%d: newm\n", m->id); | 507 LOG("%d: newm\n", m->id); |
506 addmem = sizeof(*mp->stackalloc); | 508 addmem = sizeof(*mp->stackalloc); |
507 if(runtime·gsignalstk) | 509 if(runtime·gsignalstk) |
508 addmem += sizeof(G) + runtime·gsignalstk; | 510 addmem += sizeof(G) + runtime·gsignalstk; |
509 stkoff = sizeof(M) + addmem; | 511 stkoff = sizeof(M) + addmem; |
510 stksiz = StackSystem + (fn == runtime·mstart ? 8192 : 64*1024); | 512 stksiz = StackSystem + (fn == runtime·mstart ? 8192 : 64*1024); |
511 if(!runtime·iscgo && !Windows) | 513 if(!runtime·iscgo && !Windows) |
512 addmem += stksiz; | 514 addmem += stksiz; |
513 //!!! all that is now non-GC, can it break something? | 515 //!!! all that is now non-GC, can it break something? |
514 mp = runtime·SysAlloc(sizeof(M) + addmem); | 516 mp = runtime·SysAlloc(sizeof(M) + addmem); |
515 mp->stackalloc = (FixAlloc*)(mp+1); | 517 mp->stackalloc = (FixAlloc*)(mp+1); |
| 518 //!!!if(mtype == nil) { |
| 519 //!!! Eface e; |
| 520 //!!! runtime·gc_m_ptr(&e); |
| 521 //!!! mtype = ((PtrType*)e.type)->elem; |
| 522 //!!!} |
| 523 //!!! mp = runtime·cnew(mtype); |
516 mcommoninit(mp); | 524 mcommoninit(mp); |
517 mp->g0 = &mp->g0buf; | 525 mp->g0 = &mp->g0buf; |
518 mp->p = p; | 526 mp->p = p; |
519 mp->helpgc = helpgc; | 527 mp->helpgc = helpgc; |
520 if(runtime·gsignalstk) { | 528 if(runtime·gsignalstk) { |
521 mp->gsignal = (G*)((byte*)mp+sizeof(*mp)+sizeof(*mp->stackalloc)
); | 529 mp->gsignal = (G*)((byte*)mp+sizeof(*mp)+sizeof(*mp->stackalloc)
); |
522 initgstack(mp->gsignal, (byte*)(mp->gsignal+1), runtime·gsignals
tk); | 530 initgstack(mp->gsignal, (byte*)(mp->gsignal+1), runtime·gsignals
tk); |
523 } | 531 } |
524 | 532 |
525 if(runtime·iscgo) { | 533 if(runtime·iscgo) { |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
569 // Schedules gp to run on M. Never returns. | 577 // Schedules gp to run on M. Never returns. |
570 static void | 578 static void |
571 execute(G *gp) | 579 execute(G *gp) |
572 { | 580 { |
573 int32 hz; | 581 int32 hz; |
574 | 582 |
575 LOG("%d: start running goroutine %p\n", m->id, gp); | 583 LOG("%d: start running goroutine %p\n", m->id, gp); |
576 CHECK(m->locks == 0, ("")); | 584 CHECK(m->locks == 0, ("")); |
577 CHECK(g == m->g0, ("execute: not on g0\n")); | 585 CHECK(g == m->g0, ("execute: not on g0\n")); |
578 CHECK(m->p != nil, ("execute: no p\n")); | 586 CHECK(m->p != nil, ("execute: no p\n")); |
579 » CHECK(gp->status == Grunnable, ("execute: gp->status=%d\n", gp->status))
; | 587 » CHECK(gp->status == Grunnable, ("execute: gp=%d gp->status=%d\n", gp->go
id, gp->status)); |
580 CHECK(gp->m == nil, ("execute: gp->m=%p\n", gp->m)); | 588 CHECK(gp->m == nil, ("execute: gp->m=%p\n", gp->m)); |
581 CHECK(gp->lockedm == nil && m->lockedg == nil || gp->lockedm == m && m->
lockedg == gp, | 589 CHECK(gp->lockedm == nil && m->lockedg == nil || gp->lockedm == m && m->
lockedg == gp, |
582 ("bad locking: gp->lockedm=%p m->lockedg=%p\n", gp->lockedm, m->
lockedg)); | 590 ("bad locking: gp->lockedm=%p m->lockedg=%p\n", gp->lockedm, m->
lockedg)); |
583 m->p->tick++; | 591 m->p->tick++; |
584 gp->status = Grunning; | 592 gp->status = Grunning; |
585 m->curg = gp; | 593 m->curg = gp; |
586 gp->m = m; | 594 gp->m = m; |
587 | 595 |
588 // Check whether the profiler needs to be turned on or off. | 596 // Check whether the profiler needs to be turned on or off. |
589 hz = runtime·sched.profilehz; | 597 hz = runtime·sched.profilehz; |
(...skipping 12 matching lines...) Expand all Loading... |
602 static void | 610 static void |
603 schedule(void) | 611 schedule(void) |
604 { | 612 { |
605 int32 i, try; | 613 int32 i, try; |
606 G *gp, *gp1; | 614 G *gp, *gp1; |
607 P *p; | 615 P *p; |
608 M *mp; | 616 M *mp; |
609 | 617 |
610 LOG("%d: schedule p=%p\n", m->id, m->p); | 618 LOG("%d: schedule p=%p\n", m->id, m->p); |
611 USED(&gp); | 619 USED(&gp); |
612 » if(m->locks != 0) | 620 » CHECK(m->locks == 0, ("schedule: holding locks\n")); |
613 » » runtime·throw("schedule: holding locks"); | 621 » CHECK(m->lockedg == nil, ("schedule: locked M\n")); |
614 » if(m->lockedg) | |
615 » » runtime·throw("schedule: locked M"); | |
616 | 622 |
617 top: | 623 top: |
618 if(runtime·gcwaiting) { | 624 if(runtime·gcwaiting) { |
619 p = releasep(); | 625 p = releasep(); |
620 p->status = Plocked; | 626 p->status = Plocked; |
621 runtime·lock(&runtime·sched); | 627 runtime·lock(&runtime·sched); |
622 runtime·sched.stopwait--; | 628 runtime·sched.stopwait--; |
623 if(runtime·sched.stopwait == 0) | 629 if(runtime·sched.stopwait == 0) |
624 runtime·notewakeup(&runtime·sched.stopnote); | 630 runtime·notewakeup(&runtime·sched.stopnote); |
625 runtime·unlock(&runtime·sched); | 631 runtime·unlock(&runtime·sched); |
626 » » mstop();» » | 632 » » mstop(); |
627 goto top; | 633 goto top; |
628 } | 634 } |
629 | 635 |
630 gp = runqget(m->p); | 636 gp = runqget(m->p); |
631 if(gp == nil) { | 637 if(gp == nil) { |
632 for(try=0; try<2; try++) { | 638 for(try=0; try<2; try++) { |
633 if(runtime·sched.runqsize) { | 639 if(runtime·sched.runqsize) { |
634 runtime·lock(&runtime·sched); | 640 runtime·lock(&runtime·sched); |
635 gp = globrunqget(); | 641 gp = globrunqget(); |
636 if(gp) { | 642 if(gp) { |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
716 { | 722 { |
717 P *p; | 723 P *p; |
718 M *mp; | 724 M *mp; |
719 | 725 |
720 USED(&gp); | 726 USED(&gp); |
721 if(m->lockedg) { | 727 if(m->lockedg) { |
722 p = releasep(); | 728 p = releasep(); |
723 if(m->waitunlockf) { | 729 if(m->waitunlockf) { |
724 m->waitunlockf(m->waitlock); | 730 m->waitunlockf(m->waitlock); |
725 m->waitunlockf = nil; | 731 m->waitunlockf = nil; |
726 » » }» » | 732 » » } |
727 // After this point another thread may schedule gp on m again. | 733 // After this point another thread may schedule gp on m again. |
728 // Schedule another M to run P. | 734 // Schedule another M to run P. |
729 runtime·lock(&runtime·sched); | 735 runtime·lock(&runtime·sched); |
730 mp = mget(); | 736 mp = mget(); |
731 runtime·unlock(&runtime·sched); | 737 runtime·unlock(&runtime·sched); |
732 munpark(mp, p); | 738 munpark(mp, p); |
733 // Wait until another thread schedules gp and so m again. | 739 // Wait until another thread schedules gp and so m again. |
734 runtime·notesleep(&m->park); | 740 runtime·notesleep(&m->park); |
735 runtime·noteclear(&m->park); | 741 runtime·noteclear(&m->park); |
736 execute(gp); // Never returns. | 742 execute(gp); // Never returns. |
737 } | 743 } |
738 if(m->waitunlockf) { | 744 if(m->waitunlockf) { |
739 m->waitunlockf(m->waitlock); | 745 m->waitunlockf(m->waitlock); |
740 m->waitunlockf = nil; | 746 m->waitunlockf = nil; |
741 } | 747 } |
742 schedule(); | 748 schedule(); |
743 } | 749 } |
744 | 750 |
745 // Atomically parks g and unlocks the lock. | 751 // Puts the current goroutine into a waiting state and unlocks the lock. |
746 void | 752 // The goroutine can be made runnable again by calling runtime·ready(gp). |
747 runtime·park(void *l, void(*unlockf)(void*), int8 *reason) | 753 void |
| 754 runtime·park(void(*unlockf)(Lock*), Lock *l, int8 *reason) |
748 { | 755 { |
749 LOG("%d: park l=%p reason=%s\n", m->id, l, reason); | 756 LOG("%d: park l=%p reason=%s\n", m->id, l, reason); |
750 » if(g == m->g0) | 757 » CHECK(g != m->g0, ("park of g0\n")); |
751 » » runtime·throw("park of g0"); | |
752 m->waitlock = l; | 758 m->waitlock = l; |
753 m->waitunlockf = unlockf; | 759 m->waitunlockf = unlockf; |
754 g->status = Gwaiting; | 760 g->status = Gwaiting; |
755 g->waitreason = reason; | 761 g->waitreason = reason; |
756 g->m = nil; | 762 g->m = nil; |
757 runtime·mcall(park0); | 763 runtime·mcall(park0); |
758 } | 764 } |
759 | 765 |
760 static void | 766 static void |
761 gosched0(G *gp) | 767 gosched0(G *gp) |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
855 m->mcache = nil; | 861 m->mcache = nil; |
856 m->p->m = nil; | 862 m->p->m = nil; |
857 runtime·atomicstore(&m->p->status, Psyscall); | 863 runtime·atomicstore(&m->p->status, Psyscall); |
858 if(runtime·gcwaiting) { | 864 if(runtime·gcwaiting) { |
859 runtime·lock(&runtime·sched); | 865 runtime·lock(&runtime·sched); |
860 if (runtime·sched.stopwait > 0 && runtime·cas(&m->p->status, Psy
scall, Plocked)) { | 866 if (runtime·sched.stopwait > 0 && runtime·cas(&m->p->status, Psy
scall, Plocked)) { |
861 runtime·sched.stopwait--; | 867 runtime·sched.stopwait--; |
862 if(runtime·sched.stopwait == 0) | 868 if(runtime·sched.stopwait == 0) |
863 runtime·notewakeup(&runtime·sched.stopnote); | 869 runtime·notewakeup(&runtime·sched.stopnote); |
864 } | 870 } |
865 » » runtime·unlock(&runtime·sched);» | 871 » » runtime·unlock(&runtime·sched); |
866 } | 872 } |
867 } | 873 } |
868 | 874 |
869 #pragma textflag 7 | 875 #pragma textflag 7 |
870 void | 876 void |
871 runtime·entersyscallblock(void) | 877 runtime·entersyscallblock(void) |
872 { | 878 { |
873 m->blockingsyscall = true; | 879 m->blockingsyscall = true; |
874 runtime·entersyscall(); | 880 runtime·entersyscall(); |
875 } | 881 } |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1156 // address of the go statement that created this. The new g is put | 1162 // address of the go statement that created this. The new g is put |
1157 // on the queue of g's waiting to run. | 1163 // on the queue of g's waiting to run. |
1158 G* | 1164 G* |
1159 runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc) | 1165 runtime·newproc1(byte *fn, byte *argp, int32 narg, int32 nret, void *callerpc) |
1160 { | 1166 { |
1161 byte *sp; | 1167 byte *sp; |
1162 G *newg; | 1168 G *newg; |
1163 M *mp; | 1169 M *mp; |
1164 P *p; | 1170 P *p; |
1165 int32 siz; | 1171 int32 siz; |
| 1172 //int64 goid; |
1166 | 1173 |
1167 //printf("newproc1 %p %p narg=%d nret=%d\n", fn, argp, narg, nret); | 1174 //printf("newproc1 %p %p narg=%d nret=%d\n", fn, argp, narg, nret); |
1168 siz = narg + nret; | 1175 siz = narg + nret; |
1169 siz = (siz+7) & ~7; | 1176 siz = (siz+7) & ~7; |
1170 | 1177 |
1171 // We could instead create a secondary stack frame | 1178 // We could instead create a secondary stack frame |
1172 // and make it look like goexit was on the original but | 1179 // and make it look like goexit was on the original but |
1173 // the call to the actual goroutine function was split. | 1180 // the call to the actual goroutine function was split. |
1174 // Not worth it: this is almost always an error. | 1181 // Not worth it: this is almost always an error. |
1175 if(siz > StackMin - 1024) | 1182 if(siz > StackMin - 1024) |
1176 runtime·throw("runtime.newproc: function arguments too large for
new goroutine"); | 1183 runtime·throw("runtime.newproc: function arguments too large for
new goroutine"); |
1177 | 1184 |
1178 if((newg = gfget(m->p)) != nil) { | 1185 if((newg = gfget(m->p)) != nil) { |
| 1186 //!!!if(raceenabled) |
| 1187 //!!! runtime·racegostart(goid, callerpc); |
1179 if(newg->stackguard - StackGuard != newg->stack0) | 1188 if(newg->stackguard - StackGuard != newg->stack0) |
1180 runtime·throw("invalid stack in newg"); | 1189 runtime·throw("invalid stack in newg"); |
1181 } else { | 1190 } else { |
1182 newg = runtime·malg(StackMin); | 1191 newg = runtime·malg(StackMin); |
1183 runtime·lock(&runtime·sched); | 1192 runtime·lock(&runtime·sched); |
1184 newg->goid = ++runtime·sched.goidseq; | 1193 newg->goid = ++runtime·sched.goidseq; |
1185 if(runtime·lastg == nil) | 1194 if(runtime·lastg == nil) |
1186 runtime·allg = newg; | 1195 runtime·allg = newg; |
1187 else | 1196 else |
1188 runtime·lastg->alllink = newg; | 1197 runtime·lastg->alllink = newg; |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1304 | 1313 |
1305 // for testing of wire, unwire | 1314 // for testing of wire, unwire |
1306 void | 1315 void |
1307 runtime·mid(uint32 ret) | 1316 runtime·mid(uint32 ret) |
1308 { | 1317 { |
1309 ret = m->id; | 1318 ret = m->id; |
1310 FLUSH(&ret); | 1319 FLUSH(&ret); |
1311 } | 1320 } |
1312 | 1321 |
1313 void | 1322 void |
1314 runtime·NumGoroutine(int32 ret) | 1323 runtime·NumGoroutine(intgo ret) |
1315 { | 1324 { |
1316 //ret = runtime·sched.gcount; | 1325 //ret = runtime·sched.gcount; |
1317 ret = 1; | 1326 ret = 1; |
1318 FLUSH(&ret); | 1327 FLUSH(&ret); |
1319 } | 1328 } |
1320 | 1329 |
1321 int32 | 1330 int32 |
1322 runtime·gcount(void) | 1331 runtime·gcount(void) |
1323 { | 1332 { |
1324 //return runtime·sched.gcount; | 1333 //return runtime·sched.gcount; |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1567 | 1576 |
1568 // This is a special dedicated thread. | 1577 // This is a special dedicated thread. |
1569 // It works w/o mcache nor stackalloc, it may work concurrently with GC. | 1578 // It works w/o mcache nor stackalloc, it may work concurrently with GC. |
1570 runtime·asminit(); | 1579 runtime·asminit(); |
1571 runtime·minit(); | 1580 runtime·minit(); |
1572 LOG("sysmon\n"); | 1581 LOG("sysmon\n"); |
1573 t0 = runtime·nanotime(); | 1582 t0 = runtime·nanotime(); |
1574 for(;;) { | 1583 for(;;) { |
1575 //!!! sleep more if possible | 1584 //!!! sleep more if possible |
1576 runtime·usleep(20); | 1585 runtime·usleep(20); |
1577 runtime·lock(&runtime·sched); | |
1578 if(runtime·gcwaiting) { | 1586 if(runtime·gcwaiting) { |
1579 » » » runtime·sched.sysmonwait = 1; | 1587 » » » runtime·lock(&runtime·sched); |
1580 » » » runtime·unlock(&runtime·sched); | 1588 » » » if(runtime·gcwaiting) { |
1581 » » » runtime·notesleep(&runtime·sched.sysmonnote); | 1589 » » » » runtime·sched.sysmonwait = 1; |
1582 » » » runtime·noteclear(&runtime·sched.sysmonnote); | 1590 » » » » runtime·unlock(&runtime·sched); |
1583 » » } else | 1591 » » » » runtime·notesleep(&runtime·sched.sysmonnote); |
1584 » » » runtime·unlock(&runtime·sched); | 1592 » » » » runtime·noteclear(&runtime·sched.sysmonnote); |
| 1593 » » » } else |
| 1594 » » » » runtime·unlock(&runtime·sched); |
| 1595 » » } |
1585 now = runtime·nanotime() - t0; | 1596 now = runtime·nanotime() - t0; |
1586 retake(now, ps); | 1597 retake(now, ps); |
1587 } | |
1588 } | |
1589 | |
1590 void runtime·raiseprio(int32 *p); | |
1591 | |
1592 static void | |
1593 netmon(void) | |
1594 { | |
1595 G *gp; | |
1596 int32 n, w; | |
1597 | |
1598 runtime·asminit(); | |
1599 runtime·minit(); | |
1600 int32 prio = 99; | |
1601 runtime·raiseprio(&prio); | |
1602 for(;;) { | |
1603 LOG("netmon\n"); | |
1604 runtime·lock(&runtime·sched); | |
1605 if(runtime·gcwaiting) { | |
1606 runtime·sched.netmonwait = 1; | |
1607 runtime·unlock(&runtime·sched); | |
1608 runtime·notesleep(&runtime·sched.netmonnote); | |
1609 runtime·noteclear(&runtime·sched.netmonnote); | |
1610 } else | |
1611 runtime·unlock(&runtime·sched); | |
1612 gp = runtime·netwait(-1); | |
1613 n = w = 0; | |
1614 inject(gp, &w, &n); | |
1615 } | 1598 } |
1616 } | 1599 } |
1617 | 1600 |
1618 static void | 1601 static void |
1619 inject(G *gp0, int32 *w, int32 *n) | 1602 inject(G *gp0, int32 *w, int32 *n) |
1620 { | 1603 { |
1621 int32 nw; | 1604 int32 nw; |
1622 G *gp; | 1605 G *gp; |
1623 M *mp; | 1606 M *mp; |
1624 P *p; | 1607 P *p; |
1625 | 1608 |
1626 runtime·lock(&runtime·sched); | 1609 runtime·lock(&runtime·sched); |
1627 while(gp0) { | 1610 while(gp0) { |
1628 gp = gp0; | 1611 gp = gp0; |
1629 gp0 = gp->schedlink; | 1612 gp0 = gp->schedlink; |
| 1613 gp->status = Grunnable; |
1630 globrunqput(gp); | 1614 globrunqput(gp); |
1631 (*n)++; | 1615 (*n)++; |
1632 } | 1616 } |
1633 runtime·unlock(&runtime·sched); | 1617 runtime·unlock(&runtime·sched); |
1634 | 1618 |
1635 nw = *n; | 1619 nw = *n; |
1636 while(runtime·sched.pidle && nw) { | 1620 while(runtime·sched.pidle && nw) { |
1637 runtime·lock(&runtime·sched); | 1621 runtime·lock(&runtime·sched); |
1638 if(runtime·sched.pidle == nil) { | 1622 if(runtime·sched.pidle == nil) { |
1639 runtime·unlock(&runtime·sched); | 1623 runtime·unlock(&runtime·sched); |
(...skipping 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1906 } | 1890 } |
1907 runtime·unlock(&runtime·sched.gflock); | 1891 runtime·unlock(&runtime·sched.gflock); |
1908 goto retry; | 1892 goto retry; |
1909 } | 1893 } |
1910 if(gp) { | 1894 if(gp) { |
1911 p->gfree = gp->schedlink; | 1895 p->gfree = gp->schedlink; |
1912 p->gfreecnt--; | 1896 p->gfreecnt--; |
1913 } | 1897 } |
1914 return gp; | 1898 return gp; |
1915 } | 1899 } |
LEFT | RIGHT |