Commit 28b51184 authored by Austin Clements's avatar Austin Clements

runtime: rename m.gcing to m.preemptoff and make it a string

m.gcing has become overloaded to mean "don't preempt this g" in
general.  Once the garbage collector is preemptible, the one thing it
*won't* mean is that we're in the garbage collector.

So, rename gcing to "preemptoff" and make it a string giving a reason
that preemption is disabled.  gcing was never set to anything but 0 or
1, so we don't have to worry about there being a stack of reasons.

Change-Id: I4337c29e8e942e7aa4f106fc29597e1b5de4ef46
Reviewed-on: https://go-review.googlesource.com/3660Reviewed-by: default avatarRuss Cox <rsc@golang.org>
parent f95becad
...@@ -24,13 +24,13 @@ func GOMAXPROCS(n int) int { ...@@ -24,13 +24,13 @@ func GOMAXPROCS(n int) int {
semacquire(&worldsema, false) semacquire(&worldsema, false)
gp := getg() gp := getg()
gp.m.gcing = 1 gp.m.preemptoff = "GOMAXPROCS"
systemstack(stoptheworld) systemstack(stoptheworld)
// newprocs will be processed by starttheworld // newprocs will be processed by starttheworld
newprocs = int32(n) newprocs = int32(n)
gp.m.gcing = 0 gp.m.preemptoff = ""
semrelease(&worldsema) semrelease(&worldsema)
systemstack(starttheworld) systemstack(starttheworld)
return ret return ret
......
...@@ -180,7 +180,7 @@ func notetsleep_internal(n *note, ns int64) bool { ...@@ -180,7 +180,7 @@ func notetsleep_internal(n *note, ns int64) bool {
func notetsleep(n *note, ns int64) bool { func notetsleep(n *note, ns int64) bool {
gp := getg() gp := getg()
if gp != gp.m.g0 && gp.m.gcing == 0 { if gp != gp.m.g0 && gp.m.preemptoff != "" {
throw("notetsleep not on g0") throw("notetsleep not on g0")
} }
......
...@@ -240,7 +240,7 @@ func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool { ...@@ -240,7 +240,7 @@ func notetsleep_internal(n *note, ns int64, gp *g, deadline int64) bool {
func notetsleep(n *note, ns int64) bool { func notetsleep(n *note, ns int64) bool {
gp := getg() gp := getg()
if gp != gp.m.g0 && gp.m.gcing == 0 { if gp != gp.m.g0 && gp.m.preemptoff != "" {
throw("notetsleep not on g0") throw("notetsleep not on g0")
} }
if gp.m.waitsema == 0 { if gp.m.waitsema == 0 {
......
...@@ -362,7 +362,7 @@ func gcwork(force int32) { ...@@ -362,7 +362,7 @@ func gcwork(force int32) {
// Ok, we're doing it! Stop everybody else // Ok, we're doing it! Stop everybody else
mp := acquirem() mp := acquirem()
mp.gcing = 1 mp.preemptoff = "gcing"
releasem(mp) releasem(mp)
gctimer.count++ gctimer.count++
if force == 0 { if force == 0 {
...@@ -443,7 +443,7 @@ func gcwork(force int32) { ...@@ -443,7 +443,7 @@ func gcwork(force int32) {
} }
// all done // all done
mp.gcing = 0 mp.preemptoff = ""
if force == 0 { if force == 0 {
gctimer.cycle.sweep = nanotime() gctimer.cycle.sweep = nanotime()
......
...@@ -81,14 +81,14 @@ func ReadMemStats(m *MemStats) { ...@@ -81,14 +81,14 @@ func ReadMemStats(m *MemStats) {
// a pending garbage collection already calling it. // a pending garbage collection already calling it.
semacquire(&worldsema, false) semacquire(&worldsema, false)
gp := getg() gp := getg()
gp.m.gcing = 1 gp.m.preemptoff = "read mem stats"
systemstack(stoptheworld) systemstack(stoptheworld)
systemstack(func() { systemstack(func() {
readmemstats_m(m) readmemstats_m(m)
}) })
gp.m.gcing = 0 gp.m.preemptoff = ""
gp.m.locks++ gp.m.locks++
semrelease(&worldsema) semrelease(&worldsema)
systemstack(starttheworld) systemstack(starttheworld)
...@@ -99,14 +99,14 @@ func ReadMemStats(m *MemStats) { ...@@ -99,14 +99,14 @@ func ReadMemStats(m *MemStats) {
func runtime_debug_WriteHeapDump(fd uintptr) { func runtime_debug_WriteHeapDump(fd uintptr) {
semacquire(&worldsema, false) semacquire(&worldsema, false)
gp := getg() gp := getg()
gp.m.gcing = 1 gp.m.preemptoff = "write heap dump"
systemstack(stoptheworld) systemstack(stoptheworld)
systemstack(func() { systemstack(func() {
writeheapdump_m(fd) writeheapdump_m(fd)
}) })
gp.m.gcing = 0 gp.m.preemptoff = ""
gp.m.locks++ gp.m.locks++
semrelease(&worldsema) semrelease(&worldsema)
systemstack(starttheworld) systemstack(starttheworld)
......
...@@ -143,12 +143,12 @@ var gcpercent int32 ...@@ -143,12 +143,12 @@ var gcpercent int32
// The procedure is: // The procedure is:
// //
// semacquire(&worldsema); // semacquire(&worldsema);
// m.gcing = 1; // m.preemptoff = "reason";
// stoptheworld(); // stoptheworld();
// //
// ... do stuff ... // ... do stuff ...
// //
// m.gcing = 0; // m.preemptoff = "";
// semrelease(&worldsema); // semrelease(&worldsema);
// starttheworld(); // starttheworld();
// //
......
...@@ -522,7 +522,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) { ...@@ -522,7 +522,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
if n <= len(p) { if n <= len(p) {
gp := getg() gp := getg()
semacquire(&worldsema, false) semacquire(&worldsema, false)
gp.m.gcing = 1 gp.m.preemptoff = "profile"
systemstack(stoptheworld) systemstack(stoptheworld)
n = NumGoroutine() n = NumGoroutine()
...@@ -544,7 +544,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) { ...@@ -544,7 +544,7 @@ func GoroutineProfile(p []StackRecord) (n int, ok bool) {
} }
} }
gp.m.gcing = 0 gp.m.preemptoff = ""
semrelease(&worldsema) semrelease(&worldsema)
systemstack(starttheworld) systemstack(starttheworld)
} }
...@@ -567,7 +567,7 @@ func Stack(buf []byte, all bool) int { ...@@ -567,7 +567,7 @@ func Stack(buf []byte, all bool) int {
if all { if all {
semacquire(&worldsema, false) semacquire(&worldsema, false)
gp := getg() gp := getg()
gp.m.gcing = 1 gp.m.preemptoff = "stack trace"
systemstack(stoptheworld) systemstack(stoptheworld)
} }
...@@ -591,7 +591,7 @@ func Stack(buf []byte, all bool) int { ...@@ -591,7 +591,7 @@ func Stack(buf []byte, all bool) int {
if all { if all {
gp := getg() gp := getg()
gp.m.gcing = 0 gp.m.preemptoff = ""
semrelease(&worldsema) semrelease(&worldsema)
systemstack(starttheworld) systemstack(starttheworld)
} }
......
...@@ -353,11 +353,14 @@ func gopanic(e interface{}) { ...@@ -353,11 +353,14 @@ func gopanic(e interface{}) {
print("\n") print("\n")
throw("panic during malloc") throw("panic during malloc")
} }
if gp.m.gcing != 0 { if gp.m.preemptoff != "" {
print("panic: ") print("panic: ")
printany(e) printany(e)
print("\n") print("\n")
throw("panic during gc") print("preempt off reason: ")
print(gp.m.preemptoff)
print("\n")
throw("panic during preemptoff")
} }
if gp.m.locks != 0 { if gp.m.locks != 0 {
print("panic: ") print("panic: ")
......
...@@ -135,7 +135,7 @@ func canpanic(gp *g) bool { ...@@ -135,7 +135,7 @@ func canpanic(gp *g) bool {
if gp == nil || gp != _m_.curg { if gp == nil || gp != _m_.curg {
return false return false
} }
if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.gcing != 0 || _m_.dying != 0 { if _m_.locks-_m_.softfloat != 0 || _m_.mallocing != 0 || _m_.throwing != 0 || _m_.preemptoff != "" || _m_.dying != 0 {
return false return false
} }
status := readgstatus(gp) status := readgstatus(gp)
......
...@@ -2462,7 +2462,7 @@ func sigprof(pc *uint8, sp *uint8, lr *uint8, gp *g, mp *m) { ...@@ -2462,7 +2462,7 @@ func sigprof(pc *uint8, sp *uint8, lr *uint8, gp *g, mp *m) {
pc = (*uint8)(unsafe.Pointer(uintptr(funcPC(_ExternalCode) + _PCQuantum))) pc = (*uint8)(unsafe.Pointer(uintptr(funcPC(_ExternalCode) + _PCQuantum)))
} }
stk[0] = uintptr(unsafe.Pointer(pc)) stk[0] = uintptr(unsafe.Pointer(pc))
if mp.gcing != 0 || mp.helpgc != 0 { if mp.preemptoff != "" || mp.helpgc != 0 {
stk[1] = funcPC(_GC) + _PCQuantum stk[1] = funcPC(_GC) + _PCQuantum
} else { } else {
stk[1] = funcPC(_System) + _PCQuantum stk[1] = funcPC(_System) + _PCQuantum
...@@ -3021,7 +3021,7 @@ func schedtrace(detailed bool) { ...@@ -3021,7 +3021,7 @@ func schedtrace(detailed bool) {
if lockedg != nil { if lockedg != nil {
id3 = lockedg.goid id3 = lockedg.goid
} }
print(" M", mp.id, ": p=", id1, " curg=", id2, " mallocing=", mp.mallocing, " throwing=", mp.throwing, " gcing=", mp.gcing, ""+" locks=", mp.locks, " dying=", mp.dying, " helpgc=", mp.helpgc, " spinning=", mp.spinning, " blocked=", getg().m.blocked, " lockedg=", id3, "\n") print(" M", mp.id, ": p=", id1, " curg=", id2, " mallocing=", mp.mallocing, " throwing=", mp.throwing, " preemptoff=", mp.preemptoff, ""+" locks=", mp.locks, " dying=", mp.dying, " helpgc=", mp.helpgc, " spinning=", mp.spinning, " blocked=", getg().m.blocked, " lockedg=", id3, "\n")
} }
lock(&allglock) lock(&allglock)
......
...@@ -244,7 +244,7 @@ type m struct { ...@@ -244,7 +244,7 @@ type m struct {
id int32 id int32
mallocing int32 mallocing int32
throwing int32 throwing int32
gcing int32 preemptoff string // if != "", keep curg running on this m
locks int32 locks int32
softfloat int32 softfloat int32
dying int32 dying int32
......
...@@ -208,7 +208,7 @@ func stackalloc(n uint32) stack { ...@@ -208,7 +208,7 @@ func stackalloc(n uint32) stack {
} }
var x gclinkptr var x gclinkptr
c := thisg.m.mcache c := thisg.m.mcache
if c == nil || thisg.m.gcing != 0 || thisg.m.helpgc != 0 { if c == nil || thisg.m.preemptoff != "" || thisg.m.helpgc != 0 {
// c == nil can happen in the guts of exitsyscall or // c == nil can happen in the guts of exitsyscall or
// procresize. Just get a stack from the global pool. // procresize. Just get a stack from the global pool.
// Also don't touch stackcache during gc // Also don't touch stackcache during gc
...@@ -271,7 +271,7 @@ func stackfree(stk stack) { ...@@ -271,7 +271,7 @@ func stackfree(stk stack) {
} }
x := gclinkptr(v) x := gclinkptr(v)
c := gp.m.mcache c := gp.m.mcache
if c == nil || gp.m.gcing != 0 || gp.m.helpgc != 0 { if c == nil || gp.m.preemptoff != "" || gp.m.helpgc != 0 {
lock(&stackpoolmu) lock(&stackpoolmu)
stackpoolfree(x, order) stackpoolfree(x, order)
unlock(&stackpoolmu) unlock(&stackpoolmu)
...@@ -648,7 +648,8 @@ func newstack() { ...@@ -648,7 +648,8 @@ func newstack() {
// Be conservative about where we preempt. // Be conservative about where we preempt.
// We are interested in preempting user Go code, not runtime code. // We are interested in preempting user Go code, not runtime code.
// If we're holding locks, mallocing, or GCing, don't preempt. // If we're holding locks, mallocing, or preemption is disabled, don't
// preempt.
// This check is very early in newstack so that even the status change // This check is very early in newstack so that even the status change
// from Grunning to Gwaiting and back doesn't happen in this case. // from Grunning to Gwaiting and back doesn't happen in this case.
// That status change by itself can be viewed as a small preemption, // That status change by itself can be viewed as a small preemption,
...@@ -658,7 +659,7 @@ func newstack() { ...@@ -658,7 +659,7 @@ func newstack() {
// it needs a lock held by the goroutine), that small preemption turns // it needs a lock held by the goroutine), that small preemption turns
// into a real deadlock. // into a real deadlock.
if preempt { if preempt {
if thisg.m.locks != 0 || thisg.m.mallocing != 0 || thisg.m.gcing != 0 || thisg.m.p.status != _Prunning { if thisg.m.locks != 0 || thisg.m.mallocing != 0 || thisg.m.preemptoff != "" || thisg.m.p.status != _Prunning {
// Let the goroutine keep running for now. // Let the goroutine keep running for now.
// gp->preempt is set, so it will be preempted next time. // gp->preempt is set, so it will be preempted next time.
gp.stackguard0 = gp.stack.lo + _StackGuard gp.stackguard0 = gp.stack.lo + _StackGuard
......
...@@ -121,7 +121,7 @@ func StartTrace() error { ...@@ -121,7 +121,7 @@ func StartTrace() error {
// of all goroutines at the beginning of the trace. // of all goroutines at the beginning of the trace.
semacquire(&worldsema, false) semacquire(&worldsema, false)
_g_ := getg() _g_ := getg()
_g_.m.gcing = 1 _g_.m.preemptoff = "start tracing"
systemstack(stoptheworld) systemstack(stoptheworld)
// We are in stop-the-world, but syscalls can finish and write to trace concurrently. // We are in stop-the-world, but syscalls can finish and write to trace concurrently.
...@@ -133,7 +133,7 @@ func StartTrace() error { ...@@ -133,7 +133,7 @@ func StartTrace() error {
if trace.enabled || trace.shutdown { if trace.enabled || trace.shutdown {
unlock(&trace.bufLock) unlock(&trace.bufLock)
_g_.m.gcing = 0 _g_.m.preemptoff = ""
semrelease(&worldsema) semrelease(&worldsema)
systemstack(starttheworld) systemstack(starttheworld)
return errorString("tracing is already enabled") return errorString("tracing is already enabled")
...@@ -162,7 +162,7 @@ func StartTrace() error { ...@@ -162,7 +162,7 @@ func StartTrace() error {
unlock(&trace.bufLock) unlock(&trace.bufLock)
_g_.m.gcing = 0 _g_.m.preemptoff = ""
semrelease(&worldsema) semrelease(&worldsema)
systemstack(starttheworld) systemstack(starttheworld)
return nil return nil
...@@ -175,7 +175,7 @@ func StopTrace() { ...@@ -175,7 +175,7 @@ func StopTrace() {
// and also to avoid races with traceEvent. // and also to avoid races with traceEvent.
semacquire(&worldsema, false) semacquire(&worldsema, false)
_g_ := getg() _g_ := getg()
_g_.m.gcing = 1 _g_.m.preemptoff = "stop tracing"
systemstack(stoptheworld) systemstack(stoptheworld)
// See the comment in StartTrace. // See the comment in StartTrace.
...@@ -183,7 +183,7 @@ func StopTrace() { ...@@ -183,7 +183,7 @@ func StopTrace() {
if !trace.enabled { if !trace.enabled {
unlock(&trace.bufLock) unlock(&trace.bufLock)
_g_.m.gcing = 0 _g_.m.preemptoff = ""
semrelease(&worldsema) semrelease(&worldsema)
systemstack(starttheworld) systemstack(starttheworld)
return return
...@@ -224,7 +224,7 @@ func StopTrace() { ...@@ -224,7 +224,7 @@ func StopTrace() {
unlock(&trace.bufLock) unlock(&trace.bufLock)
_g_.m.gcing = 0 _g_.m.preemptoff = ""
semrelease(&worldsema) semrelease(&worldsema)
systemstack(starttheworld) systemstack(starttheworld)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment