Commit 07cb48c3 authored by Dmitriy Vyukov's avatar Dmitriy Vyukov

sync: fix race instrumentation of WaitGroup

Currently more than 1 gorutine can execute raceWrite() in Wait()
in the following scenario:
1. goroutine 1 executes first check of wg.counter, sees that it's == 0
2. goroutine 2 executes first check of wg.counter, sees that it's == 0
3. goroutine 2 locks the mutex, sees that he is the first waiter and executes raceWrite()
4. goroutine 2 block on the semaphore
5. goroutine 3 executes Done() and unblocks goroutine 2
6. goroutine 1 lock the mutex, sees that he is the first waiter and executes raceWrite()

It produces the following false report:
WARNING: DATA RACE
Write by goroutine 35:
  sync.raceWrite()
      src/pkg/sync/race.go:41 +0x33
  sync.(*WaitGroup).Wait()
      src/pkg/sync/waitgroup.go:103 +0xae
  command-line-arguments_test.TestNoRaceWaitGroupMultipleWait2()
      src/pkg/runtime/race/testdata/waitgroup_test.go:156 +0x19a
  testing.tRunner()
      src/pkg/testing/testing.go:361 +0x108

Previous write by goroutine 36:
  sync.raceWrite()
      src/pkg/sync/race.go:41 +0x33
  sync.(*WaitGroup).Wait()
      src/pkg/sync/waitgroup.go:103 +0xae
  command-line-arguments_test.func·012()
      src/pkg/runtime/race/testdata/waitgroup_test.go:148 +0x4d

R=golang-dev, r
CC=golang-dev
https://golang.org/cl/10424043
parent 3d513faa
......@@ -95,13 +95,6 @@ func (wg *WaitGroup) Wait() {
}
wg.m.Lock()
w := atomic.AddInt32(&wg.waiters, 1)
if raceenabled && w == 1 {
// Wait's must be synchronized with the first Add.
// Need to model this is as a write to race with the read in Add.
// As the consequence, can do the write only for the first waiter,
// otherwise concurrent Wait's will race with each other.
raceWrite(unsafe.Pointer(&wg.sema))
}
// This code is racing with the unlocked path in Add above.
// The code above modifies counter and then reads waiters.
// We must modify waiters and then read counter (the opposite order)
......@@ -119,6 +112,13 @@ func (wg *WaitGroup) Wait() {
}
return
}
if raceenabled && w == 1 {
// Wait must be synchronized with the first Add.
// Need to model this is as a write to race with the read in Add.
// As a consequence, can do the write only for the first waiter,
// otherwise concurrent Waits will race with each other.
raceWrite(unsafe.Pointer(&wg.sema))
}
if wg.sema == nil {
wg.sema = new(uint32)
}
......
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