We only guarantee that the main goroutine runs on the
main OS thread for initialization. Programs that wish to
preserve that property for main.main can call runtime.LockOSThread.
This is what programs used to do before we unleashed
goroutines during init, so it is both a simple fix and keeps
existing programs working.
R=iant, r, dave, dvyukov
CC=golang-dev
https://golang.org/cl/
5309070
CALL runtime·schedinit(SB)
// create a new goroutine to start program
- PUSHL $runtime·mainstart(SB) // entry
+ PUSHL $runtime·main(SB) // entry
PUSHL $0 // arg size
CALL runtime·newproc(SB)
POPL AX
INT $3
RET
-TEXT runtime·mainstart(SB),7,$0
- CALL main·init(SB)
- CALL main·main(SB)
- PUSHL $0
- CALL runtime·exit(SB)
- POPL AX
- INT $3
- RET
-
TEXT runtime·breakpoint(SB),7,$0
INT $3
RET
CALL runtime·schedinit(SB)
// create a new goroutine to start program
- PUSHQ $runtime·mainstart(SB) // entry
+ PUSHQ $runtime·main(SB) // entry
PUSHQ $0 // arg size
CALL runtime·newproc(SB)
POPQ AX
CALL runtime·notok(SB) // never returns
RET
-TEXT runtime·mainstart(SB),7,$0
- CALL main·init(SB)
- CALL main·main(SB)
- PUSHQ $0
- CALL runtime·exit(SB)
- POPQ AX
- CALL runtime·notok(SB)
- RET
-
TEXT runtime·breakpoint(SB),7,$0
BYTE $0xcc
RET
BL runtime·schedinit(SB)
// create a new goroutine to start program
- MOVW $runtime·mainstart(SB), R0
+ MOVW $runtime·main(SB), R0
MOVW.W R0, -4(R13)
MOVW $8, R0
MOVW.W R0, -4(R13)
MOVW R0, (R1) // fail hard
B runtime·_dep_dummy(SB) // Never reached
-
-TEXT runtime·mainstart(SB),7,$4
- BL main·init(SB)
- EOR R0, R0
- MOVW R0, 0(R13)
- BL main·main(SB)
- MOVW $0, R0
- MOVW R0, 4(SP)
- BL runtime·exit(SB)
- MOVW $1234, R0
- MOVW $1001, R1
- MOVW R0, (R1) // fail hard
- RET
-
// TODO(kaib): remove these once i actually understand how the linker removes symbols
// pull in dummy dependencies
TEXT runtime·_dep_dummy(SB),7,$0
// LockOSThread wires the calling goroutine to its current operating system thread.
// Until the calling goroutine exits or calls UnlockOSThread, it will always
// execute in that thread, and no other goroutine can.
-// LockOSThread cannot be used during init functions.
func LockOSThread()
// UnlockOSThread unwires the calling goroutine from its fixed operating system thread.
volatile uint32 atomic; // atomic scheduling word (see below)
int32 profilehz; // cpu profiling rate
+
+ bool init; // running initialization
+ bool lockmain; // init called runtime.LockOSThread
Note stopped; // one g can set waitstop and wait here for m's to stop
};
// make & queue new G
// call runtime·mstart
//
-// The new G does:
-//
-// call main·init_function
-// call initdone
-// call main·main
+// The new G calls runtime·main.
void
runtime·schedinit(void)
{
m->nomemprof--;
}
+extern void main·init(void);
+extern void main·main(void);
+
+// The main goroutine.
+void
+runtime·main(void)
+{
+ // Lock the main goroutine onto this, the main OS thread,
+ // during initialization. Most programs won't care, but a few
+ // do require certain calls to be made by the main thread.
+ // Those can arrange for main.main to run in the main thread
+ // by calling runtime.LockOSThread during initialization
+ // to preserve the lock.
+ runtime·LockOSThread();
+ runtime·sched.init = true;
+ main·init();
+ runtime·sched.init = false;
+ if(!runtime·sched.lockmain)
+ runtime·UnlockOSThread();
+
+ main·main();
+ runtime·exit(0);
+ for(;;)
+ *(int32*)runtime·main = 0;
+}
+
// Lock the scheduler.
static void
schedlock(void)
runtime·gosched();
}
-void
-runtime·LockOSThread(void)
-{
- m->lockedg = g;
- g->lockedm = m;
-}
-
// delete when scheduler is stronger
int32
runtime·gomaxprocsfunc(int32 n)
return ret;
}
+void
+runtime·LockOSThread(void)
+{
+ if(m == &runtime·m0 && runtime·sched.init) {
+ runtime·sched.lockmain = true;
+ return;
+ }
+ m->lockedg = g;
+ g->lockedm = m;
+}
+
void
runtime·UnlockOSThread(void)
{
+ if(m == &runtime·m0 && runtime·sched.init) {
+ runtime·sched.lockmain = false;
+ return;
+ }
m->lockedg = nil;
g->lockedm = nil;
}
int32 runtime·gomaxprocsfunc(int32 n);
void runtime·procyield(uint32);
void runtime·osyield(void);
+void runtime·LockOSThread(void);
+void runtime·UnlockOSThread(void);
void runtime·mapassign(MapType*, Hmap*, byte*, byte*);
void runtime·mapaccess(MapType*, Hmap*, byte*, byte*, bool*);