Commit 2bcbe6a4 authored by Cherry Zhang's avatar Cherry Zhang

runtime: add a test for getg with thread switch

With gccgo, if we generate getg inlined, the backend may cache
the address of the TLS variable, which will become invalid after
a thread switch.

Currently there is no known bug for this. But if we didn't
implement this carefully, we may get subtle bugs. This CL adds a
test that will fail loudly if this is wrong. (See also
https://go.googlesource.com/gofrontend/+/refs/heads/master/libgo/runtime/proc.c#333
and an incorrect attempt CL 185337.)

Note: at least on Linux/AMD64, even with an incorrect
implementation, this only fails if the test is compiled with
-fPIC, which is not the default setting for gccgo test suite. So
some manual work is needed. Maybe we could extend the test suite
to run the runtime test with more settings (e.g. PIC and static).

Change-Id: I459a3b4c31f09b9785c0eca19b7756f80e8ef54c
Reviewed-on: https://go-review.googlesource.com/c/go/+/186357
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: 's avatarThan McIntosh <thanm@google.com>
Reviewed-by: 's avatarIan Lance Taylor <iant@golang.org>
parent 6bf2767c
......@@ -681,3 +681,37 @@ func (t *Treap) CheckInvariants() {
t.mTreap.treap.walkTreap(checkTreapNode)
t.mTreap.treap.validateInvariants()
}
func RunGetgThreadSwitchTest() {
// Test that getg works correctly with thread switch.
// With gccgo, if we generate getg inlined, the backend
// may cache the address of the TLS variable, which
// will become invalid after a thread switch. This test
// checks that the bad caching doesn't happen.
ch := make(chan int)
go func(ch chan int) {
ch <- 5
LockOSThread()
}(ch)
g1 := getg()
// Block on a receive. This is likely to get us a thread
// switch. If we yield to the sender goroutine, it will
// lock the thread, forcing us to resume on a different
// thread.
<-ch
g2 := getg()
if g1 != g2 {
panic("g1 != g2")
}
// Also test getg after some control flow, as the
// backend is sensitive to control flow.
g3 := getg()
if g1 != g3 {
panic("g1 != g3")
}
}
......@@ -977,3 +977,7 @@ func TestPreemptionAfterSyscall(t *testing.T) {
})
}
}
func TestGetgThreadSwitch(t *testing.T) {
runtime.RunGetgThreadSwitchTest()
}
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