-822ab419bf7d1c705cdce1c12133e7a11f56be2e
+619848ccd463ac385e9912df008e7e8e6301a284
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
}
var (
- fingCreate uint32
- fingRunning bool
+ fingCreate uint32
)
func createfing() {
// This is the goroutine that runs all of the finalizers
func runfinq() {
+ setSystemGoroutine()
+
var (
ef eface
ifac iface
)
+ gp := getg()
for {
lock(&finlock)
fb := finq
finq = nil
if fb == nil {
- gp := getg()
fing = gp
fingwait = true
goparkunlock(&finlock, "finalizer wait", traceEvGoBlock, 1)
default:
throw("bad kind in runfinq")
}
- fingRunning = true
+ // This is not a system goroutine while
+ // running the actual finalizer.
+ // This matters because we want this
+ // goroutine to appear in a stack dump
+ // if the finalizer crashes.
+ // The gc toolchain handles this using
+ // a global variable fingRunning,
+ // but we don't need that.
+ gp.isSystemGoroutine = false
reflectcall(f.ft, f.fn, false, false, ¶m, nil)
- fingRunning = false
+ gp.isSystemGoroutine = true
// Drop finalizer queue heap references
// before hiding them from markroot.
}
func gcBgMarkWorker(_p_ *p) {
+ setSystemGoroutine()
+
gp := getg()
type parkInfo struct {
}
func bgsweep(c chan int) {
+ setSystemGoroutine()
+
sweep.g = getg()
lock(&sweep.lock)
}
func forcegchelper() {
+ setSystemGoroutine()
+
forcegc.g = getg()
for {
lock(&forcegc.lock)
sched.maxmcount = 10000
- tracebackinit()
mallocinit()
mcommoninit(_g_.m)
alginit() // maps must not be used before this call
newg.param = arg
newg.gopc = getcallerpc(unsafe.Pointer(&fn))
newg.startpc = fn
- if isSystemGoroutine(newg) {
- atomic.Xadd(&sched.ngsys, +1)
- }
// The stack is dirty from the argument frame, so queue it for
// scanning. Do this before setting it to runnable so we still
// own the G. If we're recycling a G, it may already be on the
return newg
}
+// setSystemGoroutine marks this goroutine as a "system goroutine".
+// In the gc toolchain this is done by comparing startpc to a list of
+// saved special PCs. In gccgo that approach does not work as startpc
+// is often a thunk that invokes the real function with arguments,
+// so the thunk address never matches the saved special PCs. Instead,
+// since there are only a limited number of "system goroutines",
+// we force each one to mark itself as special.
+func setSystemGoroutine() {
+ getg().isSystemGoroutine = true
+ atomic.Xadd(&sched.ngsys, +1)
+}
+
// Put on gfree list.
// If local list is too long, transfer a batch to the global list.
func gfput(_p_ *p, gp *g) {
scanningself bool // whether goroutine is scanning its own stack
+ isSystemGoroutine bool // whether goroutine is a "system" goroutine
+
traceback *tracebackg // stack traceback buffer
context g_ucontext_t // saved context for setcontext
// It sleeps until the next event in the timers heap.
// If addtimer inserts a new earlier event, it wakes timerproc early.
func timerproc() {
+ setSystemGoroutine()
+
timers.gp = getg()
for {
lock(&timers.lock)
import (
"runtime/internal/sys"
- "unsafe"
+ _ "unsafe" // for go:linkname
)
// For gccgo, use go:linkname to rename compiler-called functions to
//go:linkname goroutineheader runtime.goroutineheader
//go:linkname printcreatedby runtime.printcreatedby
-var (
- // initialized in tracebackinit
- runfinqPC uintptr
- bgsweepPC uintptr
- forcegchelperPC uintptr
- timerprocPC uintptr
- gcBgMarkWorkerPC uintptr
-)
-
-func tracebackinit() {
- // Go variable initialization happens late during runtime startup.
- // Instead of initializing the variables above in the declarations,
- // schedinit calls this function so that the variables are
- // initialized and available earlier in the startup sequence.
- // This doesn't use funcPC to avoid memory allocation.
- // FIXME: We should be able to use funcPC when escape analysis is on.
- f1 := runfinq
- runfinqPC = **(**uintptr)(unsafe.Pointer(&f1))
- f2 := bgsweep
- bgsweepPC = **(**uintptr)(unsafe.Pointer(&f2))
- f3 := forcegchelper
- forcegchelperPC = **(**uintptr)(unsafe.Pointer(&f3))
- f4 := timerproc
- timerprocPC = **(**uintptr)(unsafe.Pointer(&f4))
- f5 := gcBgMarkWorker
- gcBgMarkWorkerPC = **(**uintptr)(unsafe.Pointer(&f5))
-}
-
func printcreatedby(gp *g) {
// Show what created goroutine, except main goroutine (goid 1).
pc := gp.gopc
// isSystemGoroutine reports whether the goroutine g must be omitted in
// stack dumps and deadlock detector.
func isSystemGoroutine(gp *g) bool {
- // FIXME: This doesn't work reliably for gccgo because in many
- // cases the startpc field will be set to a thunk rather than
- // to one of these addresses.
- pc := gp.startpc
- return pc == runfinqPC && !fingRunning ||
- pc == bgsweepPC ||
- pc == forcegchelperPC ||
- pc == timerprocPC ||
- pc == gcBgMarkWorkerPC
+ return gp.isSystemGoroutine
}
func tracebackothers(me *g) {