summaryrefslogtreecommitdiff
path: root/src/runtime
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-12-05 11:18:10 -0500
committerRuss Cox <rsc@golang.org>2014-12-05 11:18:10 -0500
commit6d3ba1914e289ed223f7bb69f34604c0e2ae5384 (patch)
tree3781a05c976360f88b736c71316dadc789e02062 /src/runtime
parentd39e7f8f9d8d330acbcfeba7e8e254b131b05f39 (diff)
parent3ebebda3a7495402239db4369d59d73749c1bfa2 (diff)
downloadgo-6d3ba1914e289ed223f7bb69f34604c0e2ae5384.tar.gz
[dev.cc] all: merge default (8d42099cdc23) into dev.ccdev.cc
TBR=austin CC=golang-codereviews https://codereview.appspot.com/178700044
Diffstat (limited to 'src/runtime')
-rw-r--r--src/runtime/proc1.go23
-rw-r--r--src/runtime/stack1.go8
2 files changed, 24 insertions, 7 deletions
diff --git a/src/runtime/proc1.go b/src/runtime/proc1.go
index 81b211d0d..aeded0e77 100644
--- a/src/runtime/proc1.go
+++ b/src/runtime/proc1.go
@@ -371,6 +371,11 @@ func casgstatus(gp *g, oldval, newval uint32) {
// loop if gp->atomicstatus is in a scan state giving
// GC time to finish and change the state to oldval.
for !cas(&gp.atomicstatus, oldval, newval) {
+ if oldval == _Gwaiting && gp.atomicstatus == _Grunnable {
+ systemstack(func() {
+ gothrow("casgstatus: waiting for Gwaiting but is Grunnable")
+ })
+ }
// Help GC if needed.
if gp.preemptscan && !gp.gcworkdone && (oldval == _Grunning || oldval == _Gsyscall) {
gp.preemptscan = false
@@ -381,6 +386,24 @@ func casgstatus(gp *g, oldval, newval uint32) {
}
}
+// casgstatus(gp, oldstatus, Gcopystack), assuming oldstatus is Gwaiting or Grunnable.
+// Returns old status. Cannot call casgstatus directly, because we are racing with an
+// async wakeup that might come in from netpoll. If we see Gwaiting from the readgstatus,
+// it might have become Grunnable by the time we get to the cas. If we called casgstatus,
+// it would loop waiting for the status to go back to Gwaiting, which it never will.
+//go:nosplit
+func casgcopystack(gp *g) uint32 {
+ for {
+ oldstatus := readgstatus(gp) &^ _Gscan
+ if oldstatus != _Gwaiting && oldstatus != _Grunnable {
+ gothrow("copystack: bad status, not Gwaiting or Grunnable")
+ }
+ if cas(&gp.atomicstatus, oldstatus, _Gcopystack) {
+ return oldstatus
+ }
+ }
+}
+
// stopg ensures that gp is stopped at a GC safe point where its stack can be scanned
// or in the context of a moving collector the pointers can be flipped from pointing
// to old object to pointing to new objects.
diff --git a/src/runtime/stack1.go b/src/runtime/stack1.go
index ad83e5895..1fd61ce1a 100644
--- a/src/runtime/stack1.go
+++ b/src/runtime/stack1.go
@@ -563,13 +563,7 @@ func copystack(gp *g, newsize uintptr) {
}
memmove(unsafe.Pointer(new.hi-used), unsafe.Pointer(old.hi-used), used)
- oldstatus := readgstatus(gp)
- oldstatus &^= _Gscan
- if oldstatus == _Gwaiting || oldstatus == _Grunnable {
- casgstatus(gp, oldstatus, _Gcopystack) // oldstatus is Gwaiting or Grunnable
- } else {
- gothrow("copystack: bad status, not Gwaiting or Grunnable")
- }
+ oldstatus := casgcopystack(gp) // cas from Gwaiting or Grunnable to Gcopystack, return old status
// Swap out old stack for new one
gp.stack = new