summaryrefslogtreecommitdiff
path: root/libgo/go/sync/cond_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/sync/cond_test.go')
-rw-r--r--libgo/go/sync/cond_test.go63
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()