| // Copyright 2013 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package net | |
| import ( | |
| "math/rand" | |
| "runtime" | |
| "testing" | |
| "time" | |
| ) | |
| func TestMutexLock(t *testing.T) { | |
| var mu fdMutex | |
| if !mu.incref() { | |
| t.Fatal("broken") | |
| } | |
| if mu.decref() { | |
| t.Fatal("broken") | |
| } | |
| if !mu.rwlock(true) { | |
| t.Fatal("broken") | |
| } | |
| if mu.rwunlock(true) { | |
| t.Fatal("broken") | |
| } | |
| if !mu.rwlock(false) { | |
| t.Fatal("broken") | |
| } | |
| if mu.rwunlock(false) { | |
| t.Fatal("broken") | |
| } | |
| } | |
| func TestMutexClose(t *testing.T) { | |
| var mu fdMutex | |
| if !mu.increfAndClose() { | |
| t.Fatal("broken") | |
| } | |
| if mu.incref() { | |
| t.Fatal("broken") | |
| } | |
| if mu.rwlock(true) { | |
| t.Fatal("broken") | |
| } | |
| if mu.rwlock(false) { | |
| t.Fatal("broken") | |
| } | |
| if mu.increfAndClose() { | |
| t.Fatal("broken") | |
| } | |
| } | |
| func TestMutexCloseUnblock(t *testing.T) { | |
| c := make(chan bool) | |
| var mu fdMutex | |
| mu.rwlock(true) | |
| for i := 0; i < 4; i++ { | |
| go func() { | |
| if mu.rwlock(true) { | |
| t.Error("broken") | |
| return | |
| } | |
| c <- true | |
| }() | |
| } | |
| // Concurrent goroutines must not be able to read lock the mutex. | |
| time.Sleep(time.Millisecond) | |
| select { | |
| case <-c: | |
| t.Fatal("broken") | |
| default: | |
| } | |
| mu.increfAndClose() // Must unblock the readers. | |
| for i := 0; i < 4; i++ { | |
| select { | |
| case <-c: | |
| case <-time.After(10 * time.Second): | |
| t.Fatal("broken") | |
| } | |
| } | |
| if mu.decref() { | |
| t.Fatal("broken") | |
| } | |
| if !mu.rwunlock(true) { | |
| t.Fatal("broken") | |
| } | |
| } | |
| func TestMutexPanic(t *testing.T) { | |
| ensurePanics := func(f func()) { | |
| defer func() { | |
| if recover() == nil { | |
| t.Fatal("does not panic") | |
| } | |
| }() | |
| f() | |
| } | |
| var mu fdMutex | |
| ensurePanics(func() { mu.decref() }) | |
| ensurePanics(func() { mu.rwunlock(true) }) | |
| ensurePanics(func() { mu.rwunlock(false) }) | |
| ensurePanics(func() { mu.incref(); mu.decref(); mu.decref() }) | |
| ensurePanics(func() { mu.rwlock(true); mu.rwunlock(true); mu.rwunlock(true) }) | |
| ensurePanics(func() { mu.rwlock(false); mu.rwunlock(false); mu.rwunlock(false) }) | |
| // ensure that it's still not broken | |
| mu.incref() | |
| mu.decref() | |
| mu.rwlock(true) | |
| mu.rwunlock(true) | |
| mu.rwlock(false) | |
| mu.rwunlock(false) | |
| } | |
| func TestMutexStress(t *testing.T) { | |
| P := 8 | |
| N := int(1e6) | |
| if testing.Short() { | |
| P = 4 | |
| N = 1e4 | |
| } | |
| defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(P)) | |
| done := make(chan bool) | |
| var mu fdMutex | |
| var readState [2]uint64 | |
| var writeState [2]uint64 | |
| for p := 0; p < P; p++ { | |
| go func() { | |
| r := rand.New(rand.NewSource(rand.Int63())) | |
| for i := 0; i < N; i++ { | |
| switch r.Intn(3) { | |
| case 0: | |
| if !mu.incref() { | |
| t.Error("broken") | |
| return | |
| } | |
| if mu.decref() { | |
| t.Error("broken") | |
| return | |
| } | |
| case 1: | |
| if !mu.rwlock(true) { | |
| t.Error("broken") | |
| return | |
| } | |
| // Ensure that it provides mutual exclusion for readers. | |
| if readState[0] != readState[1] { | |
| t.Error("broken") | |
| return | |
| } | |
| readState[0]++ | |
| readState[1]++ | |
| if mu.rwunlock(true) { | |
| t.Error("broken") | |
| return | |
| } | |
| case 2: | |
| if !mu.rwlock(false) { | |
| t.Error("broken") | |
| return | |
| } | |
| // Ensure that it provides mutual exclusion for writers. | |
| if writeState[0] != writeState[1] { | |
| t.Error("broken") | |
| return | |
| } | |
| writeState[0]++ | |
| writeState[1]++ | |
| if mu.rwunlock(false) { | |
| t.Error("broken") | |
| return | |
| } | |
| } | |
| } | |
| done <- true | |
| }() | |
| } | |
| for p := 0; p < P; p++ { | |
| <-done | |
| } | |
| if !mu.increfAndClose() { | |
| t.Fatal("broken") | |
| } | |
| if !mu.decref() { | |
| t.Fatal("broken") | |
| } | |
| } |