diff options
Diffstat (limited to 'libgo/go/sync/cond_test.go')
-rw-r--r-- | libgo/go/sync/cond_test.go | 63 |
1 files changed, 61 insertions, 2 deletions
diff --git a/libgo/go/sync/cond_test.go b/libgo/go/sync/cond_test.go index 467c80621d..9019f8f102 100644 --- a/libgo/go/sync/cond_test.go +++ b/libgo/go/sync/cond_test.go @@ -8,6 +8,7 @@ import ( "runtime" "testing" + "time" ) func TestCondSignal(t *testing.T) { @@ -136,7 +137,7 @@ func TestRace(t *testing.T) { x = 1 c.Wait() if x != 2 { - t.Fatal("want 2") + t.Error("want 2") } x = 3 c.Signal() @@ -164,7 +165,7 @@ func TestRace(t *testing.T) { if x == 2 { c.Wait() if x != 3 { - t.Fatal("want 3") + t.Error("want 3") } break } @@ -183,6 +184,64 @@ func TestRace(t *testing.T) { <-done } +func TestCondSignalStealing(t *testing.T) { + for iters := 0; iters < 1000; iters++ { + var m Mutex + cond := NewCond(&m) + + // Start a waiter. + ch := make(chan struct{}) + go func() { + m.Lock() + ch <- struct{}{} + cond.Wait() + m.Unlock() + + ch <- struct{}{} + }() + + <-ch + m.Lock() + m.Unlock() + + // We know that the waiter is in the cond.Wait() call because we + // synchronized with it, then acquired/released the mutex it was + // holding when we synchronized. + // + // Start two goroutines that will race: one will broadcast on + // the cond var, the other will wait on it. + // + // The new waiter may or may not get notified, but the first one + // has to be notified. + done := false + go func() { + cond.Broadcast() + }() + + go func() { + m.Lock() + for !done { + cond.Wait() + } + m.Unlock() + }() + + // Check that the first waiter does get signaled. + select { + case <-ch: + case <-time.After(2 * time.Second): + t.Fatalf("First waiter didn't get broadcast.") + } + + // Release the second waiter in case it didn't get the + // broadcast. + m.Lock() + done = true + m.Unlock() + cond.Broadcast() + } +} + func TestCondCopy(t *testing.T) { defer func() { err := recover() |