From 07cb48c31fbe1c2ee6d4996b882b296e162e4464 Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Tue, 25 Jun 2013 20:27:19 +0400 Subject: [PATCH] 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() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 --- src/pkg/sync/waitgroup.go | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/pkg/sync/waitgroup.go b/src/pkg/sync/waitgroup.go index 2a0a94f40a..22681115cb 100644 --- a/src/pkg/sync/waitgroup.go +++ b/src/pkg/sync/waitgroup.go @@ -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) } -- 2.48.1