1
0
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:
Russ Cox 2011-10-13 15:54:23 -04:00
parent eb3aba24b5
commit d1bafffa4b
6 changed files with 46 additions and 40 deletions

View File

@ -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.

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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
View 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() {
}