" wincallbackcontext struct{};" +
" _select struct{}; " +
"); " +
- "const ( cb_max = 2000 )"
+ "const (" +
+ " cb_max = 2000;" +
+ " _Gidle = 1;" +
+ " _Grunnable = 2;" +
+ " _Grunning = 3;" +
+ " _Gsyscall = 4;" +
+ " _Gwaiting = 5;" +
+ " _Gdead = 6;" +
+ " _Genqueue = 7;" +
+ " _Gcopystack = 8;" +
+ ")"
f, err = parser.ParseFile(fset, filename, src, 0)
if err != nil {
log.Fatalf("incorrect generated file: %s", err)
#include "funcdata.h"
#include "../../cmd/ld/textflag.h"
-TEXT _rt0_go(SB),NOSPLIT,$0
+TEXT runtime·rt0_go(SB),NOSPLIT,$0
// copy arguments forward on an even stack
MOVL argc+0(FP), AX
MOVL argv+4(FP), BX
#include "funcdata.h"
#include "../../cmd/ld/textflag.h"
-TEXT _rt0_go(SB),NOSPLIT,$0
+TEXT runtime·rt0_go(SB),NOSPLIT,$0
// copy arguments forward on an even stack
MOVQ DI, AX // argc
MOVQ SI, BX // argv
#include "funcdata.h"
#include "../../cmd/ld/textflag.h"
-TEXT _rt0_go(SB),NOSPLIT,$0
+TEXT runtime·rt0_go(SB),NOSPLIT,$0
// copy arguments forward on an even stack
MOVL argc+0(FP), AX
MOVL argv+4(FP), BX
#include "../../cmd/ld/textflag.h"
// using frame size $-4 means do not save LR on stack.
-TEXT _rt0_go(SB),NOSPLIT,$-4
+TEXT runtime·rt0_go(SB),NOSPLIT,$-4
MOVW $0xcafebabe, R12
// copy arguments forward on an even stack
if(p != nil && !runtime·strcmp(p, (byte*)"0"))
runtime·copystack = false;
- mstats.enablegc = 1;
-
if(runtime·buildVersion.str == nil) {
// Condition should never trigger. This code just serves
// to ensure runtime·buildVersion is kept in the resulting binary.
if(g->m != &runtime·m0)
runtime·throw("runtime·main not on m0");
+
runtime·init();
+ mstats.enablegc = 1; // now that runtime is initialized, GC is okay
+
main·init();
if(g->defer != &d || d.fn != &initDone)
*(int32*)runtime·main = 0;
}
-void
-runtime·goroutineheader(G *gp)
-{
- String status;
- int64 waitfor;
- uint32 gpstatus;
-
- gpstatus = runtime·readgstatus(gp);
- switch(gpstatus) {
- case Gidle:
- status = runtime·gostringnocopy((byte*)"idle");
- break;
- case Grunnable:
- status = runtime·gostringnocopy((byte*)"runnable");
- break;
- case Grunning:
- status = runtime·gostringnocopy((byte*)"running");
- break;
- case Gsyscall:
- status = runtime·gostringnocopy((byte*)"syscall");
- break;
- case Gwaiting:
- if(gp->waitreason.str != nil)
- status = gp->waitreason;
- else
- status = runtime·gostringnocopy((byte*)"waiting");
- break;
- case Gscan:
- status = runtime·gostringnocopy((byte*)"scan");
- break;
- case Gscanrunnable:
- status = runtime·gostringnocopy((byte*)"scanrunnable");
- break;
- case Gscanrunning:
- status = runtime·gostringnocopy((byte*)"scanrunning");
- break;
- case Gscansyscall:
- status = runtime·gostringnocopy((byte*)"scansyscall");
- break;
- case Gscanenqueue:
- status = runtime·gostringnocopy((byte*)"scanenqueue");
- break;
- case Gscanwaiting:
- if(gp->waitreason.str != nil)
- status = gp->waitreason;
- else
- status = runtime·gostringnocopy((byte*)"scanwaiting");
- break;
- case Gcopystack:
- status = runtime·gostringnocopy((byte*)"copystack");
- break;
- default:
- status = runtime·gostringnocopy((byte*)"???");
- break;
- }
-
- // approx time the G is blocked, in minutes
- waitfor = 0;
- gpstatus = gpstatus&~Gscan; // drop the scan bit
- if((gpstatus == Gwaiting || gpstatus == Gsyscall) && gp->waitsince != 0)
- waitfor = (runtime·nanotime() - gp->waitsince) / (60LL*1000*1000*1000);
-
- runtime·printf("goroutine %D [%S", gp->goid, status);
- if(waitfor >= 1)
- runtime·printf(", %D minutes", waitfor);
- if(gp->lockedm != nil)
- runtime·printf(", locked to thread");
- runtime·printf("]:\n");
-}
-
static void
dumpgstatus(G* gp)
{
runtime·printf("runtime: gp=%p, goid=%D, gp->atomicstatus=%d\n", gp, gp->goid, runtime·readgstatus(gp));
}
-void
-runtime·tracebackothers(G *me)
-{
- G *gp;
- int32 traceback;
- uintptr i;
- uint32 status;
-
- traceback = runtime·gotraceback(nil);
-
- // Show the current goroutine first, if we haven't already.
- if((gp = g->m->curg) != nil && gp != me) {
- runtime·printf("\n");
- runtime·goroutineheader(gp);
- runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, gp);
- }
-
- runtime·lock(&allglock);
- for(i = 0; i < runtime·allglen; i++) {
- gp = runtime·allg[i];
- if(gp == me || gp == g->m->curg || runtime·readgstatus(gp) == Gdead)
- continue;
- if(gp->issystem && traceback < 2)
- continue;
- runtime·printf("\n");
- runtime·goroutineheader(gp);
- status = runtime·readgstatus(gp);
- if((status&~Gscan) == Grunning){
- runtime·printf("\tgoroutine running on other thread; stack unavailable\n");
- runtime·printcreatedby(gp);
- } else
- runtime·traceback(~(uintptr)0, ~(uintptr)0, 0, gp);
- }
- runtime·unlock(&allglock);
-}
-
static void
checkmcount(void)
{
}
}
-extern void runtime·morestack(void);
-uintptr runtime·externalthreadhandlerp;
-
-// Does f mark the top of a goroutine stack?
-bool
-runtime·topofstack(Func *f)
-{
- return f->entry == (uintptr)runtime·goexit ||
- f->entry == (uintptr)runtime·mstart ||
- f->entry == (uintptr)runtime·mcall ||
- f->entry == (uintptr)runtime·onM ||
- f->entry == (uintptr)runtime·morestack ||
- f->entry == (uintptr)runtime·lessstack ||
- f->entry == (uintptr)_rt0_go ||
- (runtime·externalthreadhandlerp != 0 && f->entry == runtime·externalthreadhandlerp);
-}
-
void
runtime·setmaxthreads_m(void)
{
INT $3
TEXT main(SB),NOSPLIT,$0
- JMP _rt0_go(SB)
+ JMP runtime·rt0_go(SB)
JMP AX
TEXT main(SB),NOSPLIT,$-8
- MOVQ $_rt0_go(SB), AX
+ MOVQ $runtime·rt0_go(SB), AX
JMP AX
INT $3
TEXT main(SB),NOSPLIT,$0
- JMP _rt0_go(SB)
+ JMP runtime·rt0_go(SB)
JMP AX
TEXT main(SB),NOSPLIT,$-8
- MOVQ $_rt0_go(SB), AX
+ MOVQ $runtime·rt0_go(SB), AX
JMP AX
INT $3
TEXT main(SB),NOSPLIT,$0
- JMP _rt0_go(SB)
+ JMP runtime·rt0_go(SB)
JMP AX
TEXT main(SB),NOSPLIT,$-8
- MOVQ $_rt0_go(SB), AX
+ MOVQ $runtime·rt0_go(SB), AX
JMP AX
MOVW (R13), R0 // argc
MOVW $4(R13), R1 // argv
MOVM.DB.W [R0-R1], (R13)
- B _rt0_go(SB)
+ B runtime·rt0_go(SB)
TEXT main(SB),NOSPLIT,$-4
MOVM.DB.W [R0-R1], (R13)
- MOVW $_rt0_go(SB), R4
+ MOVW $runtime·rt0_go(SB), R4
B (R4)
INT $3
TEXT main(SB),NOSPLIT,$0
- JMP _rt0_go(SB)
+ JMP runtime·rt0_go(SB)
TEXT _fallback_vdso(SB),NOSPLIT,$0
INT $0x80
JMP AX
TEXT main(SB),NOSPLIT,$-8
- MOVQ $_rt0_go(SB), AX
+ MOVQ $runtime·rt0_go(SB), AX
JMP AX
SUB $4, R13 // fake a stack frame for runtime·setup_auxv
BL runtime·setup_auxv(SB)
ADD $4, R13
- B _rt0_go(SB)
+ B runtime·rt0_go(SB)
TEXT bad_abi<>(SB),NOSPLIT,$-4
// give diagnosis and exit
INT $3
TEXT main(SB),NOSPLIT,$0
- JMP _rt0_go(SB)
+ JMP runtime·rt0_go(SB)
// Uncomment for fake time like on Go Playground.
//MOVQ $1257894000000000000, AX
//MOVQ AX, runtime·timens(SB)
- JMP _rt0_go(SB)
+ JMP runtime·rt0_go(SB)
B main(SB)
TEXT main(SB),NOSPLIT,$0
- B _rt0_go(SB)
+ B runtime·rt0_go(SB)
INT $3
TEXT main(SB),NOSPLIT,$0
- JMP _rt0_go(SB)
+ JMP runtime·rt0_go(SB)
JMP AX
TEXT main(SB),NOSPLIT,$-8
- MOVQ $_rt0_go(SB), AX
+ MOVQ $runtime·rt0_go(SB), AX
JMP AX
MOVW (R13), R0 // argc
MOVW $4(R13), R1 // argv
MOVM.DB.W [R0-R1], (R13)
- B _rt0_go(SB)
+ B runtime·rt0_go(SB)
INT $3
TEXT main(SB),NOSPLIT,$0
- JMP _rt0_go(SB)
+ JMP runtime·rt0_go(SB)
JMP AX
TEXT main(SB),NOSPLIT,$-8
- MOVQ $_rt0_go(SB), AX
+ MOVQ $runtime·rt0_go(SB), AX
JMP AX
MOVL AX, 0(SP)
LEAL inargv+0(FP), AX
MOVL AX, 4(SP)
- CALL _rt0_go(SB)
+ CALL runtime·rt0_go(SB)
DATA runtime·isplan9(SB)/4, $1
GLOBL runtime·isplan9(SB), $4
MOVL $1, _nprivates(SB)
MOVL inargc-8(FP), DI
LEAQ inargv+0(FP), SI
- MOVQ $_rt0_go(SB), AX
+ MOVQ $runtime·rt0_go(SB), AX
JMP AX
DATA runtime·isplan9(SB)/4, $1
JMP AX
TEXT main(SB),NOSPLIT,$-8
- MOVQ $_rt0_go(SB), AX
+ MOVQ $runtime·rt0_go(SB), AX
JMP AX
DATA runtime·issolaris(SB)/4, $1
JMP main(SB)
TEXT main(SB),NOSPLIT,$0
- JMP _rt0_go(SB)
+ JMP runtime·rt0_go(SB)
DATA runtime·iswindows(SB)/4, $1
JMP AX
TEXT main(SB),NOSPLIT,$-8
- MOVQ $_rt0_go(SB), AX
+ MOVQ $runtime·rt0_go(SB), AX
JMP AX
DATA runtime·iswindows(SB)/4, $1
void runtime·netpollunlock(PollDesc*);
void runtime·crash(void);
void runtime·parsedebugvars(void);
-void _rt0_go(void);
void* runtime·funcdata(Func*, int32);
void runtime·setmaxthreads_m(void);
G* runtime·timejump(void);
func entersyscallblock()
func exitsyscall()
-func goroutineheader(gp *g)
-func tracebackothers(gp *g)
-
func cgocallback(fn, frame unsafe.Pointer, framesize uintptr)
func gogo(buf *gobuf)
func gosave(buf *gobuf)
func funcspdelta(*_func, uintptr) int32 // symtab.c
func funcarglen(*_func, uintptr) int32 // symtab.c
const _ArgsSizeUnknown = -0x80000000 // funcdata.h
-func topofstack(*_func) bool // proc.c
// jmpdeferPC is the PC at the beginning of the jmpdefer assembly function.
// The traceback needs to recognize it on link register architectures.
-var jmpdeferPC uintptr
-
-func init() {
- f := jmpdefer
- jmpdeferPC = **(**uintptr)(unsafe.Pointer(&f))
-}
+var jmpdeferPC = funcPC(jmpdefer)
// System-specific hook. See traceback_windows.go
var systraceback func(*_func, *stkframe, *g, bool, func(*stkframe, unsafe.Pointer) bool, unsafe.Pointer) (changed, aborted bool)
func gcallers(gp *g, skip int, pcbuf *uintptr, m int) int {
return gentraceback(^uintptr(0), ^uintptr(0), 0, gp, skip, pcbuf, m, nil, nil, false)
}
+
+var gStatusStrings = [...]string{
+ _Gidle: "idle",
+ _Grunnable: "runnable",
+ _Grunning: "running",
+ _Gsyscall: "syscall",
+ _Gwaiting: "waiting",
+ _Gdead: "dead",
+ _Genqueue: "enqueue",
+ _Gcopystack: "copystack",
+}
+
+var gScanStatusStrings = [...]string{
+ 0: "scan",
+ _Grunnable: "scanrunnable",
+ _Grunning: "scanrunning",
+ _Gsyscall: "scansyscall",
+ _Gwaiting: "scanwaiting",
+ _Gdead: "scandead",
+ _Genqueue: "scanenqueue",
+}
+
+func goroutineheader(gp *g) {
+ gpstatus := readgstatus(gp)
+
+ // Basic string status
+ var status string
+ if 0 <= gpstatus && gpstatus < uint32(len(gStatusStrings)) {
+ status = gStatusStrings[gpstatus]
+ } else if gpstatus&_Gscan != 0 && 0 <= gpstatus&^_Gscan && gpstatus&^_Gscan < uint32(len(gStatusStrings)) {
+ status = gStatusStrings[gpstatus&^_Gscan]
+ } else {
+ status = "???"
+ }
+
+ // Override.
+ if (gpstatus == _Gwaiting || gpstatus == _Gscanwaiting) && gp.waitreason != "" {
+ status = gp.waitreason
+ }
+
+ // approx time the G is blocked, in minutes
+ var waitfor int64
+ gpstatus &^= _Gscan // drop the scan bit
+ if (gpstatus == _Gwaiting || gpstatus == _Gsyscall) && gp.waitsince != 0 {
+ waitfor = (nanotime() - gp.waitsince) / 60e9
+ }
+ print("goroutine ", gp.goid, " [", status)
+ if waitfor >= 1 {
+ print(", ", waitfor, " minutes")
+ }
+ if gp.lockedm != nil {
+ print(", locked to thread")
+ }
+ print("]:\n")
+}
+
+func tracebackothers(me *g) {
+ level := gotraceback(nil)
+
+ // Show the current goroutine first, if we haven't already.
+ g := getg()
+ gp := g.m.curg
+ if gp != nil && gp != me {
+ print("\n")
+ goroutineheader(gp)
+ traceback(^uintptr(0), ^uintptr(0), 0, gp)
+ }
+
+ lock(&allglock)
+ for _, gp := range allgs {
+ if gp == me || gp == g.m.curg || readgstatus(gp) == _Gdead || gp.issystem && level < 2 {
+ continue
+ }
+ print("\n")
+ goroutineheader(gp)
+ if readgstatus(gp)&^_Gscan == _Grunning {
+ print("\tgoroutine running on other thread; stack unavailable\n")
+ printcreatedby(gp)
+ } else {
+ traceback(^uintptr(0), ^uintptr(0), 0, gp)
+ }
+ }
+ unlock(&allglock)
+}
+
+func goexit()
+func mstart()
+func morestack()
+func rt0_go()
+
+var (
+ goexitPC = funcPC(goexit)
+ mstartPC = funcPC(mstart)
+ mcallPC = funcPC(mcall)
+ onMPC = funcPC(onM)
+ morestackPC = funcPC(morestack)
+ lessstackPC = funcPC(lessstack)
+ rt0_goPC = funcPC(rt0_go)
+
+ externalthreadhandlerp uintptr // initialized elsewhere
+)
+
+// Does f mark the top of a goroutine stack?
+func topofstack(f *_func) bool {
+ pc := f.entry
+ return pc == goexitPC ||
+ pc == mstartPC ||
+ pc == mcallPC ||
+ pc == onMPC ||
+ pc == morestackPC ||
+ pc == lessstackPC ||
+ pc == rt0_goPC ||
+ externalthreadhandlerp != 0 && pc == externalthreadhandlerp
+}
var sigtramp struct{} // assembly function
func init() {
- f := sigtramp
- sigtrampPC = **(**uintptr)(unsafe.Pointer(&f))
+ sigtrampPC = funcPC(sigtramp)
systraceback = traceback_windows
}