})
}
+func TestHappensBefore(t *testing.T) {
+ var v int
+ synctest.Run(func() {
+ go func() {
+ v++ // 1
+ }()
+ // Wait creates a happens-before relationship on the above goroutine exiting.
+ synctest.Wait()
+ go func() {
+ v++ // 2
+ }()
+ })
+ // Run exiting creates a happens-before relationship on goroutines started in the bubble.
+ synctest.Run(func() {
+ v++ // 3
+ // There is a happens-before relationship between the time.AfterFunc call,
+ // and the func running.
+ time.AfterFunc(0, func() {
+ v++ // 4
+ })
+ })
+ if got, want := v, 4; got != want {
+ t.Errorf("v = %v, want %v", got, want)
+ }
+}
+
func wantPanic(t *testing.T, want string) {
if e := recover(); e != nil {
if got := fmt.Sprint(e); got != want {
sg.active++
for {
if raceenabled {
+ // Establish a happens-before relationship between a timer being created,
+ // and the timer running.
raceacquireg(gp, gp.syncGroup.raceaddr())
}
unlock(&sg.mu)
total := sg.total
unlock(&sg.mu)
+ if raceenabled {
+ // Establish a happens-before relationship between bubbled goroutines exiting
+ // and Run returning.
+ raceacquireg(gp, gp.syncGroup.raceaddr())
+ }
if total != 1 {
panic("deadlock: all goroutines in bubble are blocked")
}