mirror of
https://github.com/golang/go
synced 2024-11-22 00:14:42 -07:00
runtime: run goroutines during init
Fixes #583. Fixes #1776. Fixes #2001. Fixes #2112. R=golang-dev, bradfitz, r, gri CC=golang-dev https://golang.org/cl/5265044
This commit is contained in:
parent
eb3aba24b5
commit
d1bafffa4b
@ -5109,12 +5109,6 @@ unspecified results if <code>A</code>'s initializer calls a function defined
|
|||||||
in another package that refers to <code>B</code>.
|
in another package that refers to <code>B</code>.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Initialization code may contain "go" statements, but the functions
|
|
||||||
they invoke do not begin execution until initialization of the entire
|
|
||||||
program is complete. Therefore, all initialization code is run in a single
|
|
||||||
goroutine.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
An <code>init</code> function cannot be referred to from anywhere
|
An <code>init</code> function cannot be referred to from anywhere
|
||||||
in a program. In particular, <code>init</code> cannot be called explicitly,
|
in a program. In particular, <code>init</code> cannot be called explicitly,
|
||||||
nor can a pointer to <code>init</code> be assigned to a function variable.
|
nor can a pointer to <code>init</code> be assigned to a function variable.
|
||||||
|
@ -92,7 +92,6 @@ ok:
|
|||||||
|
|
||||||
TEXT runtime·mainstart(SB),7,$0
|
TEXT runtime·mainstart(SB),7,$0
|
||||||
CALL main·init(SB)
|
CALL main·init(SB)
|
||||||
CALL runtime·initdone(SB)
|
|
||||||
CALL main·main(SB)
|
CALL main·main(SB)
|
||||||
PUSHL $0
|
PUSHL $0
|
||||||
CALL runtime·exit(SB)
|
CALL runtime·exit(SB)
|
||||||
|
@ -74,7 +74,6 @@ ok:
|
|||||||
|
|
||||||
TEXT runtime·mainstart(SB),7,$0
|
TEXT runtime·mainstart(SB),7,$0
|
||||||
CALL main·init(SB)
|
CALL main·init(SB)
|
||||||
CALL runtime·initdone(SB)
|
|
||||||
CALL main·main(SB)
|
CALL main·main(SB)
|
||||||
PUSHQ $0
|
PUSHQ $0
|
||||||
CALL runtime·exit(SB)
|
CALL runtime·exit(SB)
|
||||||
|
@ -63,7 +63,6 @@ TEXT _rt0_arm(SB),7,$-4
|
|||||||
|
|
||||||
TEXT runtime·mainstart(SB),7,$4
|
TEXT runtime·mainstart(SB),7,$4
|
||||||
BL main·init(SB)
|
BL main·init(SB)
|
||||||
BL runtime·initdone(SB)
|
|
||||||
EOR R0, R0
|
EOR R0, R0
|
||||||
MOVW R0, 0(R13)
|
MOVW R0, 0(R13)
|
||||||
BL main·main(SB)
|
BL main·main(SB)
|
||||||
|
@ -71,7 +71,6 @@ struct Sched {
|
|||||||
|
|
||||||
volatile uint32 atomic; // atomic scheduling word (see below)
|
volatile uint32 atomic; // atomic scheduling word (see below)
|
||||||
|
|
||||||
int32 predawn; // running initialization, don't run new g's.
|
|
||||||
int32 profilehz; // cpu profiling rate
|
int32 profilehz; // cpu profiling rate
|
||||||
|
|
||||||
Note stopped; // one g can set waitstop and wait here for m's to stop
|
Note stopped; // one g can set waitstop and wait here for m's to stop
|
||||||
@ -202,8 +201,8 @@ runtime·schedinit(void)
|
|||||||
}
|
}
|
||||||
setmcpumax(runtime·gomaxprocs);
|
setmcpumax(runtime·gomaxprocs);
|
||||||
runtime·singleproc = runtime·gomaxprocs == 1;
|
runtime·singleproc = runtime·gomaxprocs == 1;
|
||||||
runtime·sched.predawn = 1;
|
|
||||||
|
|
||||||
|
mstats.enablegc = 1;
|
||||||
m->nomemprof--;
|
m->nomemprof--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,22 +226,6 @@ schedunlock(void)
|
|||||||
runtime·notewakeup(&m->havenextg);
|
runtime·notewakeup(&m->havenextg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called after main·init_function; main·main will be called on return.
|
|
||||||
void
|
|
||||||
runtime·initdone(void)
|
|
||||||
{
|
|
||||||
// Let's go.
|
|
||||||
runtime·sched.predawn = 0;
|
|
||||||
mstats.enablegc = 1;
|
|
||||||
|
|
||||||
// If main·init_function started other goroutines,
|
|
||||||
// kick off new m's to handle them, like ready
|
|
||||||
// would have, had it not been pre-dawn.
|
|
||||||
schedlock();
|
|
||||||
matchmg();
|
|
||||||
schedunlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
runtime·goexit(void)
|
runtime·goexit(void)
|
||||||
{
|
{
|
||||||
@ -467,7 +450,6 @@ readylocked(G *g)
|
|||||||
g->status = Grunnable;
|
g->status = Grunnable;
|
||||||
|
|
||||||
gput(g);
|
gput(g);
|
||||||
if(!runtime·sched.predawn)
|
|
||||||
matchmg();
|
matchmg();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -793,9 +775,6 @@ schedule(G *gp)
|
|||||||
|
|
||||||
schedlock();
|
schedlock();
|
||||||
if(gp != nil) {
|
if(gp != nil) {
|
||||||
if(runtime·sched.predawn)
|
|
||||||
runtime·throw("init rescheduling");
|
|
||||||
|
|
||||||
// Just finished running gp.
|
// Just finished running gp.
|
||||||
gp->m = nil;
|
gp->m = nil;
|
||||||
runtime·sched.grunning--;
|
runtime·sched.grunning--;
|
||||||
@ -893,9 +872,6 @@ runtime·entersyscall(void)
|
|||||||
{
|
{
|
||||||
uint32 v;
|
uint32 v;
|
||||||
|
|
||||||
if(runtime·sched.predawn)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Leave SP around for gc and traceback.
|
// Leave SP around for gc and traceback.
|
||||||
runtime·gosave(&g->sched);
|
runtime·gosave(&g->sched);
|
||||||
g->gcsp = g->sched.sp;
|
g->gcsp = g->sched.sp;
|
||||||
@ -947,9 +923,6 @@ runtime·exitsyscall(void)
|
|||||||
{
|
{
|
||||||
uint32 v;
|
uint32 v;
|
||||||
|
|
||||||
if(runtime·sched.predawn)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Fast path.
|
// Fast path.
|
||||||
// If we can do the mcpu++ bookkeeping and
|
// If we can do the mcpu++ bookkeeping and
|
||||||
// find that we still have mcpu <= mcpumax, then we can
|
// find that we still have mcpu <= mcpumax, then we can
|
||||||
@ -1513,8 +1486,6 @@ runtime·Gosched(void)
|
|||||||
void
|
void
|
||||||
runtime·LockOSThread(void)
|
runtime·LockOSThread(void)
|
||||||
{
|
{
|
||||||
if(runtime·sched.predawn)
|
|
||||||
runtime·throw("cannot wire during init");
|
|
||||||
m->lockedg = g;
|
m->lockedg = g;
|
||||||
g->lockedm = m;
|
g->lockedm = m;
|
||||||
}
|
}
|
||||||
|
44
test/init1.go
Normal file
44
test/init1.go
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// $G $D/$F.go && $L $F.$A && ./$A.out
|
||||||
|
|
||||||
|
// Copyright 2011 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Test that goroutines and garbage collection run during init.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "runtime"
|
||||||
|
|
||||||
|
var x []byte
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
c := make(chan int)
|
||||||
|
go send(c)
|
||||||
|
<-c
|
||||||
|
|
||||||
|
const chunk = 1<<20
|
||||||
|
runtime.UpdateMemStats()
|
||||||
|
sys := runtime.MemStats.Sys
|
||||||
|
b := make([]byte, chunk)
|
||||||
|
for i := range b {
|
||||||
|
b[i] = byte(i%10 + '0')
|
||||||
|
}
|
||||||
|
s := string(b)
|
||||||
|
for i := 0; i < 1000; i++ {
|
||||||
|
x = []byte(s)
|
||||||
|
}
|
||||||
|
runtime.UpdateMemStats()
|
||||||
|
sys1 := runtime.MemStats.Sys
|
||||||
|
if sys1-sys > chunk*50 {
|
||||||
|
println("allocated 1000 chunks of", chunk, "and used ", sys1-sys, "memory")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func send(c chan int) {
|
||||||
|
c <- 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user