github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/amutex/amutex_test.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package amutex 16 17 import ( 18 "testing" 19 "time" 20 21 "github.com/SagerNet/gvisor/pkg/sync" 22 ) 23 24 type sleeper struct { 25 ch chan struct{} 26 } 27 28 func (s *sleeper) SleepStart() <-chan struct{} { 29 return s.ch 30 } 31 32 func (*sleeper) SleepFinish(bool) { 33 } 34 35 func (s *sleeper) Interrupted() bool { 36 return len(s.ch) != 0 37 } 38 39 func TestMutualExclusion(t *testing.T) { 40 var m AbortableMutex 41 m.Init() 42 43 // Test mutual exclusion by running "gr" goroutines concurrently, and 44 // have each one increment a counter "iters" times within the critical 45 // section established by the mutex. 46 // 47 // If at the end of the counter is not gr * iters, then we know that 48 // goroutines ran concurrently within the critical section. 49 // 50 // If one of the goroutines doesn't complete, it's likely a bug that 51 // causes it to wait forever. 52 const gr = 1000 53 const iters = 100000 54 v := 0 55 var wg sync.WaitGroup 56 for i := 0; i < gr; i++ { 57 wg.Add(1) 58 go func() { 59 for j := 0; j < iters; j++ { 60 m.Lock(nil) 61 v++ 62 m.Unlock() 63 } 64 wg.Done() 65 }() 66 } 67 68 wg.Wait() 69 70 if v != gr*iters { 71 t.Fatalf("Bad count: got %v, want %v", v, gr*iters) 72 } 73 } 74 75 func TestAbortWait(t *testing.T) { 76 var s sleeper 77 var m AbortableMutex 78 m.Init() 79 80 // Lock the mutex. 81 m.Lock(&s) 82 83 // Lock again, but this time cancel after 500ms. 84 s.ch = make(chan struct{}, 1) 85 go func() { 86 time.Sleep(500 * time.Millisecond) 87 s.ch <- struct{}{} 88 }() 89 if v := m.Lock(&s); v { 90 t.Fatalf("Lock succeeded when it should have failed") 91 } 92 93 // Lock again, but cancel right away. 94 s.ch <- struct{}{} 95 if v := m.Lock(&s); v { 96 t.Fatalf("Lock succeeded when it should have failed") 97 } 98 }