diff options
Diffstat (limited to 'pkg/amutex/amutex_test.go')
-rw-r--r-- | pkg/amutex/amutex_test.go | 98 |
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") + } +} |