aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/netpoll.go
diff options
context:
space:
mode:
authorRick Hudson <rlh@golang.org>2015-03-12 14:19:21 -0400
committerRick Hudson <rlh@golang.org>2015-03-17 17:33:21 +0000
commit41dbcc19ef09a15f464eb3931c60b04e33cf72bb (patch)
treec5b3c069f02432d9d2ecc2e6a2a4017c9d2df243 /src/runtime/netpoll.go
parentce9b512cccae86cb381ef6bcf8e554a364f88aa1 (diff)
downloadgo-41dbcc19ef09a15f464eb3931c60b04e33cf72bb.tar.gz
go-41dbcc19ef09a15f464eb3931c60b04e33cf72bb.zip
runtime: Remove write barriers during STW.
The GC assumes that there will be no asynchronous write barriers when the world is stopped. This keeps the synchronization between write barriers and the GC simple. However, currently, there are a few places in runtime code where this assumption does not hold. The GC stops the world by collecting all Ps, which stops all user Go code, but small parts of the runtime can run without a P. For example, the code that releases a P must still deschedule its G onto a runnable queue before stopping. Similarly, when a G returns from a long-running syscall, it must run code to reacquire a P. Currently, this code can contain write barriers. This can lead to the GC collecting reachable objects if something like the following sequence of events happens: 1. GC stops the world by collecting all Ps. 2. G #1 returns from a syscall (for example), tries to install a pointer to object X, and calls greyobject on X. 3. greyobject on G #1 marks X, but does not yet add it to a write buffer. At this point, X is effectively black, not grey, even though it may point to white objects. 4. GC reaches X through some other path and calls greyobject on X, but greyobject does nothing because X is already marked. 5. GC completes. 6. greyobject on G #1 adds X to a work buffer, but it's too late. 7. Objects that were reachable only through X are incorrectly collected. To fix this, we check the invariant that no asynchronous write barriers happen when the world is stopped by checking that write barriers always have a P, and modify all currently known sources of these writes to disable the write barrier. In all modified cases this is safe because the object in question will always be reachable via some other path. Some of the trace code was turned off, in particular the code that traces returning from a syscall. The GC assumes that as far as the heap is concerned the thread is stopped when it is in a syscall. Upon returning the trace code must not do any heap writes for the same reasons discussed above. Fixes #10098 Fixes #9953 Fixes #9951 Fixes #9884 May relate to #9610 #9771 Change-Id: Ic2e70b7caffa053e56156838eb8d89503e3c0c8a Reviewed-on: https://go-review.googlesource.com/7504 Reviewed-by: Austin Clements <austin@google.com>
Diffstat (limited to 'src/runtime/netpoll.go')
-rw-r--r--src/runtime/netpoll.go16
1 files changed, 10 insertions, 6 deletions
diff --git a/src/runtime/netpoll.go b/src/runtime/netpoll.go
index a131da8542..4791e5eebe 100644
--- a/src/runtime/netpoll.go
+++ b/src/runtime/netpoll.go
@@ -274,21 +274,25 @@ func net_runtime_pollUnblock(pd *pollDesc) {
}
// make pd ready, newly runnable goroutines (if any) are returned in rg/wg
+// May run during STW, so write barriers are not allowed.
+// Eliminating WB calls using setGNoWriteBarrier are safe since the gs are
+// reachable through allg.
+//go:nowritebarrier
func netpollready(gpp **g, pd *pollDesc, mode int32) {
var rg, wg *g
if mode == 'r' || mode == 'r'+'w' {
- rg = netpollunblock(pd, 'r', true)
+ setGNoWriteBarrier(&rg, netpollunblock(pd, 'r', true))
}
if mode == 'w' || mode == 'r'+'w' {
- wg = netpollunblock(pd, 'w', true)
+ setGNoWriteBarrier(&wg, netpollunblock(pd, 'w', true))
}
if rg != nil {
- rg.schedlink = *gpp
- *gpp = rg
+ setGNoWriteBarrier(&rg.schedlink, *gpp)
+ setGNoWriteBarrier(gpp, rg)
}
if wg != nil {
- wg.schedlink = *gpp
- *gpp = wg
+ setGNoWriteBarrier(&wg.schedlink, *gpp)
+ setGNoWriteBarrier(gpp, wg)
}
}