Zach Wasserman created THRIFT-4243:
--------------------------------------
Summary: Go TSimpleServer race on wait in Stop() method
Key: THRIFT-4243
URL: https://issues.apache.org/jira/browse/THRIFT-4243
Project: Thrift
Issue Type: Bug
Components: Go - Library
Reporter: Zach Wasserman
Synchronization issues with the use of {{sync.WaitGroup}} in the
{{TSimpleServer}} implementation set off the race detector. Note the docs
(https://godoc.org/sync#WaitGroup.Add) specify "calls with a positive delta
that occur when the counter is zero must happen before a Wait".
The following unit test demonstrates the issue:
{code}
package thrift
import (
"testing"
"time"
)
type mockProcessor struct {
ProcessFunc func(in, out TProtocol) (bool, TException)
}
func (m *mockProcessor) Process(in, out TProtocol) (bool, TException) {
return m.ProcessFunc(in, out)
}
type mockServerTransport struct {
ListenFunc func() error
AcceptFunc func() (TTransport, error)
CloseFunc func() error
InterruptFunc func() error
}
func (m *mockServerTransport) Listen() error {
return m.ListenFunc()
}
func (m *mockServerTransport) Accept() (TTransport, error) {
return m.AcceptFunc()
}
func (m *mockServerTransport) Close() error {
return m.CloseFunc()
}
func (m *mockServerTransport) Interrupt() error {
return m.InterruptFunc()
}
type mockTTransport struct {
TTransport
}
func (m *mockTTransport) Close() error {
return nil
}
func TestWaitRace(t *testing.T) {
proc := &mockProcessor{
ProcessFunc: func(in, out TProtocol) (bool, TException) {
return false, nil
},
}
trans := &mockServerTransport{
ListenFunc: func() error {
return nil
},
AcceptFunc: func() (TTransport, error) {
return &mockTTransport{}, nil
},
CloseFunc: func() error {
return nil
},
InterruptFunc: func() error {
return nil
},
}
serv := NewTSimpleServer2(proc, trans)
go serv.Serve()
time.Sleep(1)
serv.Stop()
}
{code}
When run with the race detector, this test produces the following output:
{code}
go test -race -v -run TestWaitRace -count 1
=== RUN TestWaitRace
==================
WARNING: DATA RACE
Write at 0x00c4200849f4 by goroutine 6:
internal/race.Write()
/usr/local/Cellar/go/1.8/libexec/src/internal/race/race.go:41 +0x38
sync.(*WaitGroup).Wait()
/usr/local/Cellar/go/1.8/libexec/src/sync/waitgroup.go:129 +0x14b
git.apache.org/thrift.git/lib/go/thrift.(*TSimpleServer).Stop.func1()
/Users/zwass/dev/go/src/git.apache.org/thrift.git/lib/go/thrift/simple_server.go:164
+0x9b
sync.(*Once).Do()
/usr/local/Cellar/go/1.8/libexec/src/sync/once.go:44 +0xe1
git.apache.org/thrift.git/lib/go/thrift.(*TSimpleServer).Stop()
/Users/zwass/dev/go/src/git.apache.org/thrift.git/lib/go/thrift/simple_server.go:166
+0x8c
git.apache.org/thrift.git/lib/go/thrift.TestWaitRace()
/Users/zwass/dev/go/src/git.apache.org/thrift.git/lib/go/thrift/simple_server_test.go:134
+0x1be
testing.tRunner()
/usr/local/Cellar/go/1.8/libexec/src/testing/testing.go:657 +0x107
Previous read at 0x00c4200849f4 by goroutine 7:
internal/race.Read()
/usr/local/Cellar/go/1.8/libexec/src/internal/race/race.go:37 +0x38
sync.(*WaitGroup).Add()
/usr/local/Cellar/go/1.8/libexec/src/sync/waitgroup.go:71 +0x26b
git.apache.org/thrift.git/lib/go/thrift.(*TSimpleServer).AcceptLoop()
/Users/zwass/dev/go/src/git.apache.org/thrift.git/lib/go/thrift/simple_server.go:139
+0xa6
git.apache.org/thrift.git/lib/go/thrift.(*TSimpleServer).Serve()
/Users/zwass/dev/go/src/git.apache.org/thrift.git/lib/go/thrift/simple_server.go:154
+0x86
Goroutine 6 (running) created at:
testing.(*T).Run()
/usr/local/Cellar/go/1.8/libexec/src/testing/testing.go:697 +0x543
testing.runTests.func1()
/usr/local/Cellar/go/1.8/libexec/src/testing/testing.go:882 +0xaa
testing.tRunner()
/usr/local/Cellar/go/1.8/libexec/src/testing/testing.go:657 +0x107
testing.runTests()
/usr/local/Cellar/go/1.8/libexec/src/testing/testing.go:888 +0x4e0
testing.(*M).Run()
/usr/local/Cellar/go/1.8/libexec/src/testing/testing.go:822 +0x1c3
main.main()
git.apache.org/thrift.git/lib/go/thrift/_test/_testmain.go:266 +0x20f
Goroutine 7 (running) created at:
git.apache.org/thrift.git/lib/go/thrift.TestWaitRace()
/Users/zwass/dev/go/src/git.apache.org/thrift.git/lib/go/thrift/simple_server_test.go:132
+0x1a3
testing.tRunner()
/usr/local/Cellar/go/1.8/libexec/src/testing/testing.go:657 +0x107
==================
--- FAIL: TestWaitRace (0.15s)
testing.go:610: race detected during execution of test
panic: sync: WaitGroup is reused before previous Wait has returned [recovered]
panic: sync: WaitGroup is reused before previous Wait has returned
goroutine 5 [running]:
testing.tRunner.func1(0xc42006aea0)
/usr/local/Cellar/go/1.8/libexec/src/testing/testing.go:622 +0x55f
panic(0x14aea60, 0xc4201896a0)
/usr/local/Cellar/go/1.8/libexec/src/runtime/panic.go:489 +0x2f0
sync.(*WaitGroup).Wait(0xc4200849e8)
/usr/local/Cellar/go/1.8/libexec/src/sync/waitgroup.go:133 +0x138
git.apache.org/thrift.git/lib/go/thrift.(*TSimpleServer).Stop.func1()
/Users/zwass/dev/go/src/git.apache.org/thrift.git/lib/go/thrift/simple_server.go:164
+0x9c
sync.(*Once).Do(0x174ce68, 0xc42002bf00)
/usr/local/Cellar/go/1.8/libexec/src/sync/once.go:44 +0xe2
git.apache.org/thrift.git/lib/go/thrift.(*TSimpleServer).Stop(0xc420084980,
0x153af90, 0xc420084980)
/Users/zwass/dev/go/src/git.apache.org/thrift.git/lib/go/thrift/simple_server.go:166
+0x8d
git.apache.org/thrift.git/lib/go/thrift.TestWaitRace(0xc42006aea0)
/Users/zwass/dev/go/src/git.apache.org/thrift.git/lib/go/thrift/simple_server_test.go:134
+0x1bf
testing.tRunner(0xc42006aea0, 0x153b2b0)
/usr/local/Cellar/go/1.8/libexec/src/testing/testing.go:657 +0x108
created by testing.(*T).Run
/usr/local/Cellar/go/1.8/libexec/src/testing/testing.go:697 +0x544
exit status 2
FAIL git.apache.org/thrift.git/lib/go/thrift 0.190s
{code}
--
This message was sent by Atlassian JIRA
(v6.4.14#64029)