summaryrefslogtreecommitdiffhomepage
path: root/pkg/amutex/amutex_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'pkg/amutex/amutex_test.go')
-rw-r--r--pkg/amutex/amutex_test.go98
1 files changed, 98 insertions, 0 deletions
diff --git a/pkg/amutex/amutex_test.go b/pkg/amutex/amutex_test.go
new file mode 100644
index 000000000..8a3952f2a
--- /dev/null
+++ b/pkg/amutex/amutex_test.go
@@ -0,0 +1,98 @@
+// Copyright 2018 The gVisor Authors.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package amutex
+
+import (
+ "testing"
+ "time"
+
+ "gvisor.dev/gvisor/pkg/sync"
+)
+
+type sleeper struct {
+ ch chan struct{}
+}
+
+func (s *sleeper) SleepStart() <-chan struct{} {
+ return s.ch
+}
+
+func (*sleeper) SleepFinish(bool) {
+}
+
+func (s *sleeper) Interrupted() bool {
+ return len(s.ch) != 0
+}
+
+func TestMutualExclusion(t *testing.T) {
+ var m AbortableMutex
+ m.Init()
+
+ // Test mutual exclusion by running "gr" goroutines concurrently, and
+ // have each one increment a counter "iters" times within the critical
+ // section established by the mutex.
+ //
+ // If at the end of the counter is not gr * iters, then we know that
+ // goroutines ran concurrently within the critical section.
+ //
+ // If one of the goroutines doesn't complete, it's likely a bug that
+ // causes it to wait forever.
+ const gr = 1000
+ const iters = 100000
+ v := 0
+ var wg sync.WaitGroup
+ for i := 0; i < gr; i++ {
+ wg.Add(1)
+ go func() {
+ for j := 0; j < iters; j++ {
+ m.Lock(nil)
+ v++
+ m.Unlock()
+ }
+ wg.Done()
+ }()
+ }
+
+ wg.Wait()
+
+ if v != gr*iters {
+ t.Fatalf("Bad count: got %v, want %v", v, gr*iters)
+ }
+}
+
+func TestAbortWait(t *testing.T) {
+ var s sleeper
+ var m AbortableMutex
+ m.Init()
+
+ // Lock the mutex.
+ m.Lock(&s)
+
+ // Lock again, but this time cancel after 500ms.
+ s.ch = make(chan struct{}, 1)
+ go func() {
+ time.Sleep(500 * time.Millisecond)
+ s.ch <- struct{}{}
+ }()
+ if v := m.Lock(&s); v {
+ t.Fatalf("Lock succeeded when it should have failed")
+ }
+
+ // Lock again, but cancel right away.
+ s.ch <- struct{}{}
+ if v := m.Lock(&s); v {
+ t.Fatalf("Lock succeeded when it should have failed")
+ }
+}