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 "zaexperiment.h" | 7 #include "zaexperiment.h" |
8 #include "malloc.h" | 8 #include "malloc.h" |
9 #include "stack.h" | 9 #include "stack.h" |
10 #include "race.h" | 10 #include "race.h" |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
137 // | 137 // |
138 // The new G calls runtime·main. | 138 // The new G calls runtime·main. |
139 void | 139 void |
140 runtime·schedinit(void) | 140 runtime·schedinit(void) |
141 { | 141 { |
142 int32 n, procs; | 142 int32 n, procs; |
143 byte *p; | 143 byte *p; |
144 Eface i; | 144 Eface i; |
145 | 145 |
146 runtime·sched.maxmcount = 10000; | 146 runtime·sched.maxmcount = 10000; |
147 » runtime·precisestack = haveexperiment("precisestack"); | 147 » runtime·precisestack = true; // haveexperiment("precisestack"); |
148 | 148 |
149 runtime·mallocinit(); | 149 runtime·mallocinit(); |
150 mcommoninit(m); | 150 mcommoninit(m); |
151 ········ | 151 ········ |
152 // Initialize the itable value for newErrorCString, | 152 // Initialize the itable value for newErrorCString, |
153 // so that the next time it gets called, possibly | 153 // so that the next time it gets called, possibly |
154 // in a fault during a garbage collection, it will not | 154 // in a fault during a garbage collection, it will not |
155 // need to allocated memory. | 155 // need to allocated memory. |
156 runtime·newErrorCString(0, &i); | 156 runtime·newErrorCString(0, &i); |
157 | 157 |
158 runtime·goargs(); | 158 runtime·goargs(); |
159 runtime·goenvs(); | 159 runtime·goenvs(); |
160 runtime·parsedebugvars(); | 160 runtime·parsedebugvars(); |
161 | 161 |
162 // Allocate internal symbol table representation now, we need it for GC
anyway. | 162 // Allocate internal symbol table representation now, we need it for GC
anyway. |
163 runtime·symtabinit(); | 163 runtime·symtabinit(); |
164 | 164 |
165 runtime·sched.lastpoll = runtime·nanotime(); | 165 runtime·sched.lastpoll = runtime·nanotime(); |
166 procs = 1; | 166 procs = 1; |
167 p = runtime·getenv("GOMAXPROCS"); | 167 p = runtime·getenv("GOMAXPROCS"); |
168 if(p != nil && (n = runtime·atoi(p)) > 0) { | 168 if(p != nil && (n = runtime·atoi(p)) > 0) { |
169 if(n > MaxGomaxprocs) | 169 if(n > MaxGomaxprocs) |
170 n = MaxGomaxprocs; | 170 n = MaxGomaxprocs; |
171 procs = n; | 171 procs = n; |
172 } | 172 } |
173 runtime·allp = runtime·malloc((MaxGomaxprocs+1)*sizeof(runtime·allp[0]))
; | 173 runtime·allp = runtime·malloc((MaxGomaxprocs+1)*sizeof(runtime·allp[0]))
; |
174 procresize(procs); | 174 procresize(procs); |
175 | 175 |
| 176 runtime·copystack = runtime·precisestack; |
| 177 p = runtime·getenv("GOCOPYSTACK"); |
| 178 if(p != nil && !runtime·strcmp(p, (byte*)"0")) |
| 179 runtime·copystack = false; |
| 180 |
176 mstats.enablegc = 1; | 181 mstats.enablegc = 1; |
177 | 182 |
178 if(raceenabled) | 183 if(raceenabled) |
179 g->racectx = runtime·raceinit(); | 184 g->racectx = runtime·raceinit(); |
180 } | 185 } |
181 | 186 |
182 extern void main·init(void); | 187 extern void main·init(void); |
183 extern void main·main(void); | 188 extern void main·main(void); |
184 | 189 |
185 static FuncVal scavenger = {runtime·MHeap_Scavenger}; | 190 static FuncVal scavenger = {runtime·MHeap_Scavenger}; |
186 | 191 |
187 static FuncVal initDone = { runtime·unlockOSThread }; | 192 static FuncVal initDone = { runtime·unlockOSThread }; |
188 | 193 |
189 // The main goroutine. | 194 // The main goroutine. |
| 195 // Note: C frames in general are not copyable during stack growth, for two reaso
ns: |
| 196 // 1) We don't know where in a frame to find pointers to other stack locations
. |
| 197 // 2) There's no guarantee that globals or heap values do not point into the f
rame. |
| 198 // |
| 199 // The C frame for runtime.main is copyable, because: |
| 200 // 1) There are no pointers to other stack locations in the frame |
| 201 // (d.fn points at a global, d.link is nil, d.argp is -1). |
| 202 // 2) The only pointer into this frame is from the defer chain, |
| 203 // which is explicitly handled during stack copying. |
190 void | 204 void |
191 runtime·main(void) | 205 runtime·main(void) |
192 { | 206 { |
193 Defer d; | 207 Defer d; |
194 ········ | 208 ········ |
195 // Max stack size is 1 GB on 64-bit, 250 MB on 32-bit. | 209 // Max stack size is 1 GB on 64-bit, 250 MB on 32-bit. |
196 // Using decimal instead of binary GB and MB because | 210 // Using decimal instead of binary GB and MB because |
197 // they look nicer in the stack overflow failure message. | 211 // they look nicer in the stack overflow failure message. |
198 if(sizeof(void*) == 8) | 212 if(sizeof(void*) == 8) |
199 runtime·maxstacksize = 1000000000; | 213 runtime·maxstacksize = 1000000000; |
(...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
580 } | 594 } |
581 m->locks--; | 595 m->locks--; |
582 if(m->locks == 0 && g->preempt) // restore the preemption request in ca
se we've cleared it in newstack | 596 if(m->locks == 0 && g->preempt) // restore the preemption request in ca
se we've cleared it in newstack |
583 g->stackguard0 = StackPreempt; | 597 g->stackguard0 = StackPreempt; |
584 } | 598 } |
585 | 599 |
586 // Called to start an M. | 600 // Called to start an M. |
587 void | 601 void |
588 runtime·mstart(void) | 602 runtime·mstart(void) |
589 { | 603 { |
590 #ifdef GOOS_windows | 604 #ifdef GOOSARCH_windows_386 |
591 #ifdef GOARCH_386 | |
592 // It is used by windows-386 only. Unfortunately, seh needs | 605 // It is used by windows-386 only. Unfortunately, seh needs |
593 // to be located on os stack, and mstart runs on os stack | 606 // to be located on os stack, and mstart runs on os stack |
594 // for both m0 and m. | 607 // for both m0 and m. |
595 SEH seh; | 608 SEH seh; |
596 #endif | |
597 #endif | 609 #endif |
598 | 610 |
599 if(g != m->g0) | 611 if(g != m->g0) |
600 runtime·throw("bad runtime·mstart"); | 612 runtime·throw("bad runtime·mstart"); |
601 | 613 |
602 // Record top of stack for use by mcall. | 614 // Record top of stack for use by mcall. |
603 // Once we call schedule we're never coming back, | 615 // Once we call schedule we're never coming back, |
604 // so other calls can reuse this stack space. | 616 // so other calls can reuse this stack space. |
605 runtime·gosave(&m->g0->sched); | 617 runtime·gosave(&m->g0->sched); |
606 m->g0->sched.pc = (uintptr)-1; // make sure it is never used | 618 m->g0->sched.pc = (uintptr)-1; // make sure it is never used |
607 m->g0->stackguard = m->g0->stackguard0; // cgo sets only stackguard0, c
opy it to stackguard | 619 m->g0->stackguard = m->g0->stackguard0; // cgo sets only stackguard0, c
opy it to stackguard |
608 #ifdef GOOS_windows | 620 #ifdef GOOSARCH_windows_386 |
609 #ifdef GOARCH_386 | |
610 m->seh = &seh; | 621 m->seh = &seh; |
611 #endif | |
612 #endif | 622 #endif |
613 runtime·asminit(); | 623 runtime·asminit(); |
614 runtime·minit(); | 624 runtime·minit(); |
615 | 625 |
616 // Install signal handlers; after minit so that minit can | 626 // Install signal handlers; after minit so that minit can |
617 // prepare the thread to be able to handle the signals. | 627 // prepare the thread to be able to handle the signals. |
618 if(m == &runtime·m0) | 628 if(m == &runtime·m0) |
619 runtime·initsig(); | 629 runtime·initsig(); |
620 ········ | 630 ········ |
621 if(m->mstartfn) | 631 if(m->mstartfn) |
(...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
754 // Install m and g (= m->g0) and set the stack bounds | 764 // Install m and g (= m->g0) and set the stack bounds |
755 // to match the current stack. We don't actually know | 765 // to match the current stack. We don't actually know |
756 // how big the stack is, like we don't know how big any | 766 // how big the stack is, like we don't know how big any |
757 // scheduling stack is, but we assume there's at least 32 kB, | 767 // scheduling stack is, but we assume there's at least 32 kB, |
758 // which is more than enough for us. | 768 // which is more than enough for us. |
759 runtime·setmg(mp, mp->g0); | 769 runtime·setmg(mp, mp->g0); |
760 g->stackbase = (uintptr)(&x + 1024); | 770 g->stackbase = (uintptr)(&x + 1024); |
761 g->stackguard = (uintptr)(&x - 32*1024); | 771 g->stackguard = (uintptr)(&x - 32*1024); |
762 g->stackguard0 = g->stackguard; | 772 g->stackguard0 = g->stackguard; |
763 | 773 |
764 #ifdef GOOS_windows | 774 #ifdef GOOSARCH_windows_386 |
765 #ifdef GOARCH_386 | |
766 // On windows/386, we need to put an SEH frame (two words) | 775 // On windows/386, we need to put an SEH frame (two words) |
767 // somewhere on the current stack. We are called from cgocallback_gofunc | 776 // somewhere on the current stack. We are called from cgocallback_gofunc |
768 // and we know that it will leave two unused words below m->curg->sched.
sp. | 777 // and we know that it will leave two unused words below m->curg->sched.
sp. |
769 // Use those. | 778 // Use those. |
770 m->seh = (SEH*)((uintptr*)&x + 1); | 779 m->seh = (SEH*)((uintptr*)&x + 1); |
771 #endif | |
772 #endif | 780 #endif |
773 | 781 |
774 // Initialize this thread to use the m. | 782 // Initialize this thread to use the m. |
775 runtime·asminit(); | 783 runtime·asminit(); |
776 runtime·minit(); | 784 runtime·minit(); |
777 } | 785 } |
778 | 786 |
779 // newextram allocates an m and puts it on the extra list. | 787 // newextram allocates an m and puts it on the extra list. |
780 // It is called with a working local m, so that it can do things | 788 // It is called with a working local m, so that it can do things |
781 // like call schedlock and allocate. | 789 // like call schedlock and allocate. |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
841 // We may have to keep the current version on systems with cgo | 849 // We may have to keep the current version on systems with cgo |
842 // but without pthreads, like Windows. | 850 // but without pthreads, like Windows. |
843 void | 851 void |
844 runtime·dropm(void) | 852 runtime·dropm(void) |
845 { | 853 { |
846 M *mp, *mnext; | 854 M *mp, *mnext; |
847 | 855 |
848 // Undo whatever initialization minit did during needm. | 856 // Undo whatever initialization minit did during needm. |
849 runtime·unminit(); | 857 runtime·unminit(); |
850 | 858 |
851 #ifdef GOOS_windows | 859 #ifdef GOOSARCH_windows_386 |
852 #ifdef GOARCH_386 | |
853 m->seh = nil; // reset dangling typed pointer | 860 m->seh = nil; // reset dangling typed pointer |
854 #endif | |
855 #endif | 861 #endif |
856 | 862 |
857 // Clear m and g, and return m to the extra list. | 863 // Clear m and g, and return m to the extra list. |
858 // After the call to setmg we can only call nosplit functions. | 864 // After the call to setmg we can only call nosplit functions. |
859 mp = m; | 865 mp = m; |
860 runtime·setmg(nil, nil); | 866 runtime·setmg(nil, nil); |
861 | 867 |
862 mnext = lockextra(true); | 868 mnext = lockextra(true); |
863 mp->schedlink = mnext; | 869 mp->schedlink = mnext; |
864 unlockextra(mp); | 870 unlockextra(mp); |
(...skipping 486 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1351 } | 1357 } |
1352 | 1358 |
1353 execute(gp); | 1359 execute(gp); |
1354 } | 1360 } |
1355 | 1361 |
1356 // Puts the current goroutine into a waiting state and calls unlockf. | 1362 // Puts the current goroutine into a waiting state and calls unlockf. |
1357 // If unlockf returns false, the goroutine is resumed. | 1363 // If unlockf returns false, the goroutine is resumed. |
1358 void | 1364 void |
1359 runtime·park(bool(*unlockf)(G*, void*), void *lock, int8 *reason) | 1365 runtime·park(bool(*unlockf)(G*, void*), void *lock, int8 *reason) |
1360 { | 1366 { |
| 1367 if(g->status != Grunning) |
| 1368 runtime·throw("bad g status"); |
1361 m->waitlock = lock; | 1369 m->waitlock = lock; |
1362 m->waitunlockf = unlockf; | 1370 m->waitunlockf = unlockf; |
1363 g->waitreason = reason; | 1371 g->waitreason = reason; |
1364 runtime·mcall(park0); | 1372 runtime·mcall(park0); |
1365 } | 1373 } |
1366 | 1374 |
1367 static bool | 1375 static bool |
1368 parkunlock(G *gp, void *lock) | 1376 parkunlock(G *gp, void *lock) |
1369 { | 1377 { |
1370 USED(gp); | 1378 USED(gp); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1402 stoplockedm(); | 1410 stoplockedm(); |
1403 execute(gp); // Never returns. | 1411 execute(gp); // Never returns. |
1404 } | 1412 } |
1405 schedule(); | 1413 schedule(); |
1406 } | 1414 } |
1407 | 1415 |
1408 // Scheduler yield. | 1416 // Scheduler yield. |
1409 void | 1417 void |
1410 runtime·gosched(void) | 1418 runtime·gosched(void) |
1411 { | 1419 { |
| 1420 if(g->status != Grunning) |
| 1421 runtime·throw("bad g status"); |
1412 runtime·mcall(runtime·gosched0); | 1422 runtime·mcall(runtime·gosched0); |
1413 } | 1423 } |
1414 | 1424 |
1415 // runtime·gosched continuation on g0. | 1425 // runtime·gosched continuation on g0. |
1416 void | 1426 void |
1417 runtime·gosched0(G *gp) | 1427 runtime·gosched0(G *gp) |
1418 { | 1428 { |
1419 gp->status = Grunnable; | 1429 gp->status = Grunnable; |
1420 gp->m = nil; | 1430 gp->m = nil; |
1421 m->curg = nil; | 1431 m->curg = nil; |
1422 runtime·lock(&runtime·sched); | 1432 runtime·lock(&runtime·sched); |
1423 globrunqput(gp); | 1433 globrunqput(gp); |
1424 runtime·unlock(&runtime·sched); | 1434 runtime·unlock(&runtime·sched); |
1425 if(m->lockedg) { | 1435 if(m->lockedg) { |
1426 stoplockedm(); | 1436 stoplockedm(); |
1427 execute(gp); // Never returns. | 1437 execute(gp); // Never returns. |
1428 } | 1438 } |
1429 schedule(); | 1439 schedule(); |
1430 } | 1440 } |
1431 | 1441 |
1432 // Finishes execution of the current goroutine. | 1442 // Finishes execution of the current goroutine. |
1433 // Need to mark it as nosplit, because it runs with sp > stackbase (as runtime·l
essstack). | 1443 // Need to mark it as nosplit, because it runs with sp > stackbase (as runtime·l
essstack). |
1434 // Since it does not return it does not matter. But if it is preempted | 1444 // Since it does not return it does not matter. But if it is preempted |
1435 // at the split stack check, GC will complain about inconsistent sp. | 1445 // at the split stack check, GC will complain about inconsistent sp. |
1436 #pragma textflag NOSPLIT | 1446 #pragma textflag NOSPLIT |
1437 void | 1447 void |
1438 runtime·goexit(void) | 1448 runtime·goexit(void) |
1439 { | 1449 { |
| 1450 if(g->status != Grunning) |
| 1451 runtime·throw("bad g status"); |
1440 if(raceenabled) | 1452 if(raceenabled) |
1441 runtime·racegoend(); | 1453 runtime·racegoend(); |
1442 runtime·mcall(goexit0); | 1454 runtime·mcall(goexit0); |
1443 } | 1455 } |
1444 | 1456 |
1445 // runtime·goexit continuation on g0. | 1457 // runtime·goexit continuation on g0. |
1446 static void | 1458 static void |
1447 goexit0(G *gp) | 1459 goexit0(G *gp) |
1448 { | 1460 { |
1449 gp->status = Gdead; | 1461 gp->status = Gdead; |
1450 gp->m = nil; | 1462 gp->m = nil; |
1451 gp->lockedm = nil; | 1463 gp->lockedm = nil; |
| 1464 gp->paniconfault = 0; |
1452 m->curg = nil; | 1465 m->curg = nil; |
1453 m->lockedg = nil; | 1466 m->lockedg = nil; |
1454 if(m->locked & ~LockExternal) { | 1467 if(m->locked & ~LockExternal) { |
1455 runtime·printf("invalid m->locked = %d\n", m->locked); | 1468 runtime·printf("invalid m->locked = %d\n", m->locked); |
1456 runtime·throw("internal lockOSThread error"); | 1469 runtime·throw("internal lockOSThread error"); |
1457 }······· | 1470 }······· |
1458 m->locked = 0; | 1471 m->locked = 0; |
1459 runtime·unwindstack(gp, nil); | 1472 runtime·unwindstack(gp, nil); |
1460 gfput(m->p, gp); | 1473 gfput(m->p, gp); |
1461 schedule(); | 1474 schedule(); |
(...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1862 } | 1875 } |
1863 runtime·allg[runtime·allglen++] = gp; | 1876 runtime·allg[runtime·allglen++] = gp; |
1864 runtime·unlock(&allglock); | 1877 runtime·unlock(&allglock); |
1865 } | 1878 } |
1866 | 1879 |
1867 // Put on gfree list. | 1880 // Put on gfree list. |
1868 // If local list is too long, transfer a batch to the global list. | 1881 // If local list is too long, transfer a batch to the global list. |
1869 static void | 1882 static void |
1870 gfput(P *p, G *gp) | 1883 gfput(P *p, G *gp) |
1871 { | 1884 { |
| 1885 uintptr stksize; |
| 1886 |
1872 if(gp->stackguard - StackGuard != gp->stack0) | 1887 if(gp->stackguard - StackGuard != gp->stack0) |
1873 runtime·throw("invalid stack in gfput"); | 1888 runtime·throw("invalid stack in gfput"); |
| 1889 stksize = gp->stackbase + sizeof(Stktop) - gp->stack0; |
| 1890 if(stksize != FixedStack) { |
| 1891 // non-standard stack size - free it. |
| 1892 runtime·stackfree((void*)gp->stack0, stksize); |
| 1893 gp->stacksize = 0; |
| 1894 gp->stack0 = 0; |
| 1895 gp->stackguard = 0; |
| 1896 gp->stackguard0 = 0; |
| 1897 gp->stackbase = 0; |
| 1898 } |
1874 gp->schedlink = p->gfree; | 1899 gp->schedlink = p->gfree; |
1875 p->gfree = gp; | 1900 p->gfree = gp; |
1876 p->gfreecnt++; | 1901 p->gfreecnt++; |
1877 if(p->gfreecnt >= 64) { | 1902 if(p->gfreecnt >= 64) { |
1878 runtime·lock(&runtime·sched.gflock); | 1903 runtime·lock(&runtime·sched.gflock); |
1879 while(p->gfreecnt >= 32) { | 1904 while(p->gfreecnt >= 32) { |
1880 p->gfreecnt--; | 1905 p->gfreecnt--; |
1881 gp = p->gfree; | 1906 gp = p->gfree; |
1882 p->gfree = gp->schedlink; | 1907 p->gfree = gp->schedlink; |
1883 gp->schedlink = runtime·sched.gfree; | 1908 gp->schedlink = runtime·sched.gfree; |
1884 runtime·sched.gfree = gp; | 1909 runtime·sched.gfree = gp; |
1885 } | 1910 } |
1886 runtime·unlock(&runtime·sched.gflock); | 1911 runtime·unlock(&runtime·sched.gflock); |
1887 } | 1912 } |
1888 } | 1913 } |
1889 | 1914 |
1890 // Get from gfree list. | 1915 // Get from gfree list. |
1891 // If local list is empty, grab a batch from global list. | 1916 // If local list is empty, grab a batch from global list. |
1892 static G* | 1917 static G* |
1893 gfget(P *p) | 1918 gfget(P *p) |
1894 { | 1919 { |
1895 G *gp; | 1920 G *gp; |
| 1921 byte *stk; |
1896 | 1922 |
1897 retry: | 1923 retry: |
1898 gp = p->gfree; | 1924 gp = p->gfree; |
1899 if(gp == nil && runtime·sched.gfree) { | 1925 if(gp == nil && runtime·sched.gfree) { |
1900 runtime·lock(&runtime·sched.gflock); | 1926 runtime·lock(&runtime·sched.gflock); |
1901 while(p->gfreecnt < 32 && runtime·sched.gfree) { | 1927 while(p->gfreecnt < 32 && runtime·sched.gfree) { |
1902 p->gfreecnt++; | 1928 p->gfreecnt++; |
1903 gp = runtime·sched.gfree; | 1929 gp = runtime·sched.gfree; |
1904 runtime·sched.gfree = gp->schedlink; | 1930 runtime·sched.gfree = gp->schedlink; |
1905 gp->schedlink = p->gfree; | 1931 gp->schedlink = p->gfree; |
1906 p->gfree = gp; | 1932 p->gfree = gp; |
1907 } | 1933 } |
1908 runtime·unlock(&runtime·sched.gflock); | 1934 runtime·unlock(&runtime·sched.gflock); |
1909 goto retry; | 1935 goto retry; |
1910 } | 1936 } |
1911 if(gp) { | 1937 if(gp) { |
1912 p->gfree = gp->schedlink; | 1938 p->gfree = gp->schedlink; |
1913 p->gfreecnt--; | 1939 p->gfreecnt--; |
| 1940 |
| 1941 if(gp->stack0 == 0) { |
| 1942 // Stack was deallocated in gfput. Allocate a new one. |
| 1943 if(g == m->g0) { |
| 1944 stk = runtime·stackalloc(FixedStack); |
| 1945 } else { |
| 1946 g->param = (void*)FixedStack; |
| 1947 runtime·mcall(mstackalloc); |
| 1948 stk = g->param; |
| 1949 g->param = nil; |
| 1950 } |
| 1951 gp->stacksize = FixedStack; |
| 1952 gp->stack0 = (uintptr)stk; |
| 1953 gp->stackbase = (uintptr)stk + FixedStack - sizeof(Stkto
p); |
| 1954 gp->stackguard = (uintptr)stk + StackGuard; |
| 1955 gp->stackguard0 = gp->stackguard; |
| 1956 runtime·memclr((byte*)gp->stackbase, sizeof(Stktop)); |
| 1957 } |
1914 } | 1958 } |
1915 return gp; | 1959 return gp; |
1916 } | 1960 } |
1917 | 1961 |
1918 // Purge all cached G's from gfree list to the global list. | 1962 // Purge all cached G's from gfree list to the global list. |
1919 static void | 1963 static void |
1920 gfpurge(P *p) | 1964 gfpurge(P *p) |
1921 { | 1965 { |
1922 G *gp; | 1966 G *gp; |
1923 | 1967 |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2024 if(m->locked < LockInternal) | 2068 if(m->locked < LockInternal) |
2025 runtime·throw("runtime: internal error: misuse of lockOSThread/u
nlockOSThread"); | 2069 runtime·throw("runtime: internal error: misuse of lockOSThread/u
nlockOSThread"); |
2026 m->locked -= LockInternal; | 2070 m->locked -= LockInternal; |
2027 unlockOSThread(); | 2071 unlockOSThread(); |
2028 } | 2072 } |
2029 | 2073 |
2030 bool | 2074 bool |
2031 runtime·lockedOSThread(void) | 2075 runtime·lockedOSThread(void) |
2032 { | 2076 { |
2033 return g->lockedm != nil && m->lockedg != nil; | 2077 return g->lockedm != nil && m->lockedg != nil; |
2034 } | |
2035 | |
2036 // for testing of callbacks | |
2037 void | |
2038 runtime·golockedOSThread(bool ret) | |
2039 { | |
2040 ret = runtime·lockedOSThread(); | |
2041 FLUSH(&ret); | |
2042 } | |
2043 | |
2044 void | |
2045 runtime·NumGoroutine(intgo ret) | |
2046 { | |
2047 ret = runtime·gcount(); | |
2048 FLUSH(&ret); | |
2049 } | 2078 } |
2050 | 2079 |
2051 int32 | 2080 int32 |
2052 runtime·gcount(void) | 2081 runtime·gcount(void) |
2053 { | 2082 { |
2054 G *gp; | 2083 G *gp; |
2055 int32 n, s; | 2084 int32 n, s; |
2056 uintptr i; | 2085 uintptr i; |
2057 | 2086 |
2058 n = 0; | 2087 n = 0; |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2097 runtime·panicstring("runtime: arg size to reflect.call more than 1GB"); | 2126 runtime·panicstring("runtime: arg size to reflect.call more than 1GB"); |
2098 } | 2127 } |
2099 | 2128 |
2100 static struct { | 2129 static struct { |
2101 Lock; | 2130 Lock; |
2102 void (*fn)(uintptr*, int32); | 2131 void (*fn)(uintptr*, int32); |
2103 int32 hz; | 2132 int32 hz; |
2104 uintptr pcbuf[100]; | 2133 uintptr pcbuf[100]; |
2105 } prof; | 2134 } prof; |
2106 | 2135 |
2107 static void | 2136 static void System(void) {} |
2108 System(void) | 2137 static void ExternalCode(void) {} |
2109 { | 2138 static void GC(void) {} |
2110 } | 2139 extern byte etext[]; |
2111 | 2140 |
2112 // Called if we receive a SIGPROF signal. | 2141 // Called if we receive a SIGPROF signal. |
2113 void | 2142 void |
2114 runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp) | 2143 runtime·sigprof(uint8 *pc, uint8 *sp, uint8 *lr, G *gp, M *mp) |
2115 { | 2144 { |
2116 int32 n; | 2145 int32 n; |
2117 bool traceback; | 2146 bool traceback; |
2118 MCache *mcache; | |
2119 // Do not use global m in this function, use mp instead. | 2147 // Do not use global m in this function, use mp instead. |
2120 // On windows one m is sending reports about all the g's, so m means a w
rong thing. | 2148 // On windows one m is sending reports about all the g's, so m means a w
rong thing. |
2121 byte m; | 2149 byte m; |
2122 | 2150 |
2123 m = 0; | 2151 m = 0; |
2124 USED(m); | 2152 USED(m); |
2125 | 2153 |
2126 if(prof.fn == nil || prof.hz == 0) | 2154 if(prof.fn == nil || prof.hz == 0) |
2127 return; | 2155 return; |
2128 | 2156 |
2129 // Profiling runs concurrently with GC, so it must not allocate. | 2157 // Profiling runs concurrently with GC, so it must not allocate. |
2130 » mcache = mp->mcache; | 2158 » mp->mallocing++; |
2131 » mp->mcache = nil; | |
2132 | 2159 |
2133 // Define that a "user g" is a user-created goroutine, and a "system g" | 2160 // Define that a "user g" is a user-created goroutine, and a "system g" |
2134 // is one that is m->g0 or m->gsignal. We've only made sure that we | 2161 // is one that is m->g0 or m->gsignal. We've only made sure that we |
2135 // can unwind user g's, so exclude the system g's. | 2162 // can unwind user g's, so exclude the system g's. |
2136 // | 2163 // |
2137 // It is not quite as easy as testing gp == m->curg (the current user g) | 2164 // It is not quite as easy as testing gp == m->curg (the current user g) |
2138 // because we might be interrupted for profiling halfway through a | 2165 // because we might be interrupted for profiling halfway through a |
2139 // goroutine switch. The switch involves updating three (or four) values
: | 2166 // goroutine switch. The switch involves updating three (or four) values
: |
2140 // g, PC, SP, and (on arm) LR. The PC must be the last to be updated, | 2167 // g, PC, SP, and (on arm) LR. The PC must be the last to be updated, |
2141 // because once it gets updated the new g is running. | 2168 // because once it gets updated the new g is running. |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2204 // in runtime.gogo. | 2231 // in runtime.gogo. |
2205 traceback = true; | 2232 traceback = true; |
2206 if(gp == nil || gp != mp->curg || | 2233 if(gp == nil || gp != mp->curg || |
2207 (uintptr)sp < gp->stackguard - StackGuard || gp->stackbase < (uintptr
)sp || | 2234 (uintptr)sp < gp->stackguard - StackGuard || gp->stackbase < (uintptr
)sp || |
2208 ((uint8*)runtime·gogo <= pc && pc < (uint8*)runtime·gogo + RuntimeGog
oBytes)) | 2235 ((uint8*)runtime·gogo <= pc && pc < (uint8*)runtime·gogo + RuntimeGog
oBytes)) |
2209 traceback = false; | 2236 traceback = false; |
2210 | 2237 |
2211 runtime·lock(&prof); | 2238 runtime·lock(&prof); |
2212 if(prof.fn == nil) { | 2239 if(prof.fn == nil) { |
2213 runtime·unlock(&prof); | 2240 runtime·unlock(&prof); |
2214 » » mp->mcache = mcache; | 2241 » » mp->mallocing--; |
2215 return; | 2242 return; |
2216 } | 2243 } |
2217 n = 0; | 2244 n = 0; |
2218 if(traceback) | 2245 if(traceback) |
2219 n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr,
gp, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false); | 2246 n = runtime·gentraceback((uintptr)pc, (uintptr)sp, (uintptr)lr,
gp, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false); |
2220 if(!traceback || n <= 0) { | 2247 if(!traceback || n <= 0) { |
2221 » » n = 2; | 2248 » » // Normal traceback is impossible or has failed. |
2222 » » prof.pcbuf[0] = (uintptr)pc; | 2249 » » // See if it falls into several common cases. |
2223 » » prof.pcbuf[1] = (uintptr)System + 1; | 2250 » » n = 0; |
| 2251 » » if(mp->ncgo > 0 && mp->curg != nil && |
| 2252 » » » mp->curg->syscallpc != 0 && mp->curg->syscallsp != 0) { |
| 2253 » » » // Cgo, we can't unwind and symbolize arbitrary C code, |
| 2254 » » » // so instead collect Go stack that leads to the cgo cal
l. |
| 2255 » » » // This is especially important on windows, since all sy
scalls are cgo calls. |
| 2256 » » » n = runtime·gentraceback(mp->curg->syscallpc, mp->curg->
syscallsp, 0, mp->curg, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false); |
| 2257 » » } |
| 2258 #ifdef GOOS_windows |
| 2259 » » if(n == 0 && mp->libcallg != nil && mp->libcallpc != 0 && mp->li
bcallsp != 0) { |
| 2260 » » » // Libcall, i.e. runtime syscall on windows. |
| 2261 » » » // Collect Go stack that leads to the call. |
| 2262 » » » n = runtime·gentraceback(mp->libcallpc, mp->libcallsp, 0
, mp->libcallg, 0, prof.pcbuf, nelem(prof.pcbuf), nil, nil, false); |
| 2263 » » } |
| 2264 #endif |
| 2265 » » if(n == 0) { |
| 2266 » » » // If all of the above has failed, account it against ab
stract "System" or "GC". |
| 2267 » » » n = 2; |
| 2268 » » » // "ExternalCode" is better than "etext". |
| 2269 » » » if((uintptr)pc > (uintptr)etext) |
| 2270 » » » » pc = (byte*)ExternalCode + PCQuantum; |
| 2271 » » » prof.pcbuf[0] = (uintptr)pc; |
| 2272 » » » if(mp->gcing || mp->helpgc) |
| 2273 » » » » prof.pcbuf[1] = (uintptr)GC + PCQuantum; |
| 2274 » » » else |
| 2275 » » » » prof.pcbuf[1] = (uintptr)System + PCQuantum; |
| 2276 » » } |
2224 } | 2277 } |
2225 prof.fn(prof.pcbuf, n); | 2278 prof.fn(prof.pcbuf, n); |
2226 runtime·unlock(&prof); | 2279 runtime·unlock(&prof); |
2227 » mp->mcache = mcache; | 2280 » mp->mallocing--; |
2228 } | 2281 } |
2229 | 2282 |
2230 // Arrange to call fn with a traceback hz times a second. | 2283 // Arrange to call fn with a traceback hz times a second. |
2231 void | 2284 void |
2232 runtime·setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz) | 2285 runtime·setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz) |
2233 { | 2286 { |
2234 // Force sane arguments. | 2287 // Force sane arguments. |
2235 if(hz < 0) | 2288 if(hz < 0) |
2236 hz = 0; | 2289 hz = 0; |
2237 if(hz == 0) | 2290 if(hz == 0) |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2405 checkdead(void) | 2458 checkdead(void) |
2406 { | 2459 { |
2407 G *gp; | 2460 G *gp; |
2408 int32 run, grunning, s; | 2461 int32 run, grunning, s; |
2409 uintptr i; | 2462 uintptr i; |
2410 | 2463 |
2411 // -1 for sysmon | 2464 // -1 for sysmon |
2412 run = runtime·sched.mcount - runtime·sched.nmidle - runtime·sched.nmidle
locked - 1; | 2465 run = runtime·sched.mcount - runtime·sched.nmidle - runtime·sched.nmidle
locked - 1; |
2413 if(run > 0) | 2466 if(run > 0) |
2414 return; | 2467 return; |
| 2468 // If we are dying because of a signal caught on an already idle thread, |
| 2469 // freezetheworld will cause all running threads to block. |
| 2470 // And runtime will essentially enter into deadlock state, |
| 2471 // except that there is a thread that will call runtime·exit soon. |
| 2472 if(runtime·panicking > 0) |
| 2473 return; |
2415 if(run < 0) { | 2474 if(run < 0) { |
2416 » » runtime·printf("checkdead: nmidle=%d nmidlelocked=%d mcount=%d\n
", | 2475 » » runtime·printf("runtime: checkdead: nmidle=%d nmidlelocked=%d mc
ount=%d\n", |
2417 runtime·sched.nmidle, runtime·sched.nmidlelocked, runtim
e·sched.mcount); | 2476 runtime·sched.nmidle, runtime·sched.nmidlelocked, runtim
e·sched.mcount); |
2418 runtime·throw("checkdead: inconsistent counts"); | 2477 runtime·throw("checkdead: inconsistent counts"); |
2419 } | 2478 } |
2420 grunning = 0; | 2479 grunning = 0; |
2421 runtime·lock(&allglock); | 2480 runtime·lock(&allglock); |
2422 for(i = 0; i < runtime·allglen; i++) { | 2481 for(i = 0; i < runtime·allglen; i++) { |
2423 gp = runtime·allg[i]; | 2482 gp = runtime·allg[i]; |
2424 if(gp->isbackground) | 2483 if(gp->isbackground) |
2425 continue; | 2484 continue; |
2426 s = gp->status; | 2485 s = gp->status; |
2427 if(s == Gwaiting) | 2486 if(s == Gwaiting) |
2428 grunning++; | 2487 grunning++; |
2429 else if(s == Grunnable || s == Grunning || s == Gsyscall) { | 2488 else if(s == Grunnable || s == Grunning || s == Gsyscall) { |
2430 runtime·unlock(&allglock); | 2489 runtime·unlock(&allglock); |
2431 » » » runtime·printf("checkdead: find g %D in status %d\n", gp
->goid, s); | 2490 » » » runtime·printf("runtime: checkdead: find g %D in status
%d\n", gp->goid, s); |
2432 runtime·throw("checkdead: runnable g"); | 2491 runtime·throw("checkdead: runnable g"); |
2433 } | 2492 } |
2434 } | 2493 } |
2435 runtime·unlock(&allglock); | 2494 runtime·unlock(&allglock); |
2436 if(grunning == 0) // possible if main goroutine calls runtime·Goexit() | 2495 if(grunning == 0) // possible if main goroutine calls runtime·Goexit() |
2437 runtime·exit(0); | 2496 runtime·exit(0); |
2438 m->throwing = -1; // do not dump full stacks | 2497 m->throwing = -1; // do not dump full stacks |
2439 runtime·throw("all goroutines are asleep - deadlock!"); | 2498 runtime·throw("all goroutines are asleep - deadlock!"); |
2440 } | 2499 } |
2441 | 2500 |
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2678 id1 = -1; | 2737 id1 = -1; |
2679 if(p) | 2738 if(p) |
2680 id1 = p->id; | 2739 id1 = p->id; |
2681 id2 = -1; | 2740 id2 = -1; |
2682 if(gp) | 2741 if(gp) |
2683 id2 = gp->goid; | 2742 id2 = gp->goid; |
2684 id3 = -1; | 2743 id3 = -1; |
2685 if(lockedg) | 2744 if(lockedg) |
2686 id3 = lockedg->goid; | 2745 id3 = lockedg->goid; |
2687 runtime·printf(" M%d: p=%D curg=%D mallocing=%d throwing=%d gci
ng=%d" | 2746 runtime·printf(" M%d: p=%D curg=%D mallocing=%d throwing=%d gci
ng=%d" |
2688 » » » " locks=%d dying=%d helpgc=%d spinning=%d lockedg=%D\n", | 2747 » » » " locks=%d dying=%d helpgc=%d spinning=%d blocked=%d loc
kedg=%D\n", |
2689 mp->id, id1, id2, | 2748 mp->id, id1, id2, |
2690 mp->mallocing, mp->throwing, mp->gcing, mp->locks, mp->d
ying, mp->helpgc, | 2749 mp->mallocing, mp->throwing, mp->gcing, mp->locks, mp->d
ying, mp->helpgc, |
2691 » » » mp->spinning, id3); | 2750 » » » mp->spinning, m->blocked, id3); |
2692 } | 2751 } |
2693 runtime·lock(&allglock); | 2752 runtime·lock(&allglock); |
2694 for(gi = 0; gi < runtime·allglen; gi++) { | 2753 for(gi = 0; gi < runtime·allglen; gi++) { |
2695 gp = runtime·allg[gi]; | 2754 gp = runtime·allg[gi]; |
2696 mp = gp->m; | 2755 mp = gp->m; |
2697 lockedm = gp->lockedm; | 2756 lockedm = gp->lockedm; |
2698 runtime·printf(" G%D: status=%d(%s) m=%d lockedm=%d\n", | 2757 runtime·printf(" G%D: status=%d(%s) m=%d lockedm=%d\n", |
2699 gp->goid, gp->status, gp->waitreason, mp ? mp->id : -1, | 2758 gp->goid, gp->status, gp->waitreason, mp ? mp->id : -1, |
2700 lockedm ? lockedm->id : -1); | 2759 lockedm ? lockedm->id : -1); |
2701 } | 2760 } |
(...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2993 } | 3052 } |
2994 if(s != i/2 && s != i/2+1) { | 3053 if(s != i/2 && s != i/2+1) { |
2995 runtime·printf("bad steal %d, want %d or %d, iter %d\n", | 3054 runtime·printf("bad steal %d, want %d or %d, iter %d\n", |
2996 s, i/2, i/2+1, i); | 3055 s, i/2, i/2+1, i); |
2997 runtime·throw("bad steal"); | 3056 runtime·throw("bad steal"); |
2998 } | 3057 } |
2999 } | 3058 } |
3000 } | 3059 } |
3001 | 3060 |
3002 extern void runtime·morestack(void); | 3061 extern void runtime·morestack(void); |
| 3062 uintptr runtime·externalthreadhandlerp; |
3003 | 3063 |
3004 // Does f mark the top of a goroutine stack? | 3064 // Does f mark the top of a goroutine stack? |
3005 bool | 3065 bool |
3006 runtime·topofstack(Func *f) | 3066 runtime·topofstack(Func *f) |
3007 { | 3067 { |
3008 return f->entry == (uintptr)runtime·goexit || | 3068 return f->entry == (uintptr)runtime·goexit || |
3009 f->entry == (uintptr)runtime·mstart || | 3069 f->entry == (uintptr)runtime·mstart || |
3010 f->entry == (uintptr)runtime·mcall || | 3070 f->entry == (uintptr)runtime·mcall || |
3011 f->entry == (uintptr)runtime·morestack || | 3071 f->entry == (uintptr)runtime·morestack || |
3012 f->entry == (uintptr)runtime·lessstack || | 3072 f->entry == (uintptr)runtime·lessstack || |
3013 » » f->entry == (uintptr)_rt0_go; | 3073 » » f->entry == (uintptr)_rt0_go || |
3014 } | 3074 » » (runtime·externalthreadhandlerp != 0 && f->entry == runtime·exte
rnalthreadhandlerp); |
3015 | 3075 } |
3016 void | 3076 |
3017 runtime∕debug·setMaxThreads(intgo in, intgo out) | 3077 int32 |
3018 { | 3078 runtime·setmaxthreads(int32 in) |
| 3079 { |
| 3080 » int32 out; |
| 3081 |
3019 runtime·lock(&runtime·sched); | 3082 runtime·lock(&runtime·sched); |
3020 out = runtime·sched.maxmcount; | 3083 out = runtime·sched.maxmcount; |
3021 runtime·sched.maxmcount = in; | 3084 runtime·sched.maxmcount = in; |
3022 checkmcount(); | 3085 checkmcount(); |
3023 runtime·unlock(&runtime·sched); | 3086 runtime·unlock(&runtime·sched); |
3024 » FLUSH(&out); | 3087 » return out; |
3025 } | 3088 } |
3026 | 3089 |
3027 static int8 experiment[] = GOEXPERIMENT; // defined in zaexperiment.h | 3090 static int8 experiment[] = GOEXPERIMENT; // defined in zaexperiment.h |
3028 | 3091 |
3029 static bool | 3092 static bool |
3030 haveexperiment(int8 *name) | 3093 haveexperiment(int8 *name) |
3031 { | 3094 { |
3032 int32 i, j; | 3095 int32 i, j; |
3033 ········ | 3096 ········ |
3034 for(i=0; i<sizeof(experiment); i++) { | 3097 for(i=0; i<sizeof(experiment); i++) { |
3035 if((i == 0 || experiment[i-1] == ',') && experiment[i] == name[0
]) { | 3098 if((i == 0 || experiment[i-1] == ',') && experiment[i] == name[0
]) { |
3036 for(j=0; name[j]; j++) | 3099 for(j=0; name[j]; j++) |
3037 if(experiment[i+j] != name[j]) | 3100 if(experiment[i+j] != name[j]) |
3038 goto nomatch; | 3101 goto nomatch; |
3039 if(experiment[i+j] != '\0' && experiment[i+j] != ',') | 3102 if(experiment[i+j] != '\0' && experiment[i+j] != ',') |
3040 goto nomatch; | 3103 goto nomatch; |
3041 return 1; | 3104 return 1; |
3042 } | 3105 } |
3043 nomatch:; | 3106 nomatch:; |
3044 } | 3107 } |
3045 return 0; | 3108 return 0; |
3046 } | 3109 } |
3047 | |
3048 // func runtime_procPin() int | |
3049 void | |
3050 sync·runtime_procPin(intgo p) | |
3051 { | |
3052 M *mp; | |
3053 | |
3054 mp = m; | |
3055 // Disable preemption. | |
3056 mp->locks++; | |
3057 p = mp->p->id; | |
3058 FLUSH(&p); | |
3059 } | |
3060 | |
3061 // func runtime_procUnpin() | |
3062 void | |
3063 sync·runtime_procUnpin(void) | |
3064 { | |
3065 m->locks--; | |
3066 } | |
LEFT | RIGHT |