Remove gvisor/pkg/tmutex

It isn't used.

PiperOrigin-RevId: 314775492
This commit is contained in:
Andrei Vagin
2020-06-05 11:27:39 -07:00
committed by Nicolas Lacasse
parent 51c61cb2dc
commit d61e88e342
3 changed files with 0 additions and 356 deletions
-17
View File
@@ -1,17 +0,0 @@
load("//tools:defs.bzl", "go_library", "go_test")
package(licenses = ["notice"])
go_library(
name = "tmutex",
srcs = ["tmutex.go"],
visibility = ["//:sandbox"],
)
go_test(
name = "tmutex_test",
size = "medium",
srcs = ["tmutex_test.go"],
library = ":tmutex",
deps = ["//pkg/sync"],
)
-81
View File
@@ -1,81 +0,0 @@
// 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 tmutex provides the implementation of a mutex that implements an
// efficient TryLock function in addition to Lock and Unlock.
package tmutex
import (
"sync/atomic"
)
// Mutex is a mutual exclusion primitive that implements TryLock in addition
// to Lock and Unlock.
type Mutex struct {
v int32
ch chan struct{}
}
// Init initializes the mutex.
func (m *Mutex) Init() {
m.v = 1
m.ch = make(chan struct{}, 1)
}
// Lock acquires the mutex. If it is currently held by another goroutine, Lock
// will wait until it has a chance to acquire it.
func (m *Mutex) Lock() {
// Uncontended case.
if atomic.AddInt32(&m.v, -1) == 0 {
return
}
for {
// Try to acquire the mutex again, at the same time making sure
// that m.v is negative, which indicates to the owner of the
// lock that it is contended, which will force it to try to wake
// someone up when it releases the mutex.
if v := atomic.LoadInt32(&m.v); v >= 0 && atomic.SwapInt32(&m.v, -1) == 1 {
return
}
// Wait for the mutex to be released before trying again.
<-m.ch
}
}
// TryLock attempts to acquire the mutex without blocking. If the mutex is
// currently held by another goroutine, it fails to acquire it and returns
// false.
func (m *Mutex) TryLock() bool {
v := atomic.LoadInt32(&m.v)
if v <= 0 {
return false
}
return atomic.CompareAndSwapInt32(&m.v, 1, 0)
}
// Unlock releases the mutex.
func (m *Mutex) Unlock() {
if atomic.SwapInt32(&m.v, 1) == 0 {
// There were no pending waiters.
return
}
// Wake some waiter up.
select {
case m.ch <- struct{}{}:
default:
}
}
-258
View File
@@ -1,258 +0,0 @@
// 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 tmutex
import (
"fmt"
"runtime"
"sync/atomic"
"testing"
"time"
"gvisor.dev/gvisor/pkg/sync"
)
func TestBasicLock(t *testing.T) {
var m Mutex
m.Init()
m.Lock()
// Try blocking lock the mutex from a different goroutine. This must
// not block because the mutex is held.
ch := make(chan struct{}, 1)
go func() {
m.Lock()
ch <- struct{}{}
m.Unlock()
ch <- struct{}{}
}()
select {
case <-ch:
t.Fatalf("Lock succeeded on locked mutex")
case <-time.After(100 * time.Millisecond):
}
// Unlock the mutex and make sure that the goroutine waiting on Lock()
// unblocks and succeeds.
m.Unlock()
select {
case <-ch:
case <-time.After(100 * time.Millisecond):
t.Fatalf("Lock failed to acquire unlocked mutex")
}
// Make sure we can lock and unlock again.
m.Lock()
m.Unlock()
}
func TestTryLock(t *testing.T) {
var m Mutex
m.Init()
// Try to lock. It should succeed.
if !m.TryLock() {
t.Fatalf("TryLock failed on unlocked mutex")
}
// Try to lock again, it should now fail.
if m.TryLock() {
t.Fatalf("TryLock succeeded on locked mutex")
}
// Try blocking lock the mutex from a different goroutine. This must
// not block because the mutex is held.
ch := make(chan struct{}, 1)
go func() {
m.Lock()
ch <- struct{}{}
m.Unlock()
}()
select {
case <-ch:
t.Fatalf("Lock succeeded on locked mutex")
case <-time.After(100 * time.Millisecond):
}
// Unlock the mutex and make sure that the goroutine waiting on Lock()
// unblocks and succeeds.
m.Unlock()
select {
case <-ch:
case <-time.After(100 * time.Millisecond):
t.Fatalf("Lock failed to acquire unlocked mutex")
}
}
func TestMutualExclusion(t *testing.T) {
var m Mutex
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 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 to 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()
v++
m.Unlock()
}
wg.Done()
}()
}
wg.Wait()
if v != gr*iters {
t.Fatalf("Bad count: got %v, want %v", v, gr*iters)
}
}
func TestMutualExclusionWithTryLock(t *testing.T) {
var m Mutex
m.Init()
// Similar to the previous, with the addition of some goroutines that
// only increment the count if TryLock succeeds.
const gr = 1000
const iters = 100000
total := int64(gr * iters)
var tryTotal int64
v := int64(0)
var wg sync.WaitGroup
for i := 0; i < gr; i++ {
wg.Add(2)
go func() {
for j := 0; j < iters; j++ {
m.Lock()
v++
m.Unlock()
}
wg.Done()
}()
go func() {
local := int64(0)
for j := 0; j < iters; j++ {
if m.TryLock() {
v++
m.Unlock()
local++
}
}
atomic.AddInt64(&tryTotal, local)
wg.Done()
}()
}
wg.Wait()
t.Logf("tryTotal = %d", tryTotal)
total += tryTotal
if v != total {
t.Fatalf("Bad count: got %v, want %v", v, total)
}
}
// BenchmarkTmutex is equivalent to TestMutualExclusion, with the following
// differences:
//
// - The number of goroutines is variable, with the maximum value depending on
// GOMAXPROCS.
//
// - The number of iterations per benchmark is controlled by the benchmarking
// framework.
//
// - Care is taken to ensure that all goroutines participating in the benchmark
// have been created before the benchmark begins.
func BenchmarkTmutex(b *testing.B) {
for n, max := 1, 4*runtime.GOMAXPROCS(0); n > 0 && n <= max; n *= 2 {
b.Run(fmt.Sprintf("%d", n), func(b *testing.B) {
var m Mutex
m.Init()
var ready sync.WaitGroup
begin := make(chan struct{})
var end sync.WaitGroup
for i := 0; i < n; i++ {
ready.Add(1)
end.Add(1)
go func() {
ready.Done()
<-begin
for j := 0; j < b.N; j++ {
m.Lock()
m.Unlock()
}
end.Done()
}()
}
ready.Wait()
b.ResetTimer()
close(begin)
end.Wait()
})
}
}
// BenchmarkSyncMutex is equivalent to BenchmarkTmutex, but uses sync.Mutex as
// a comparison point.
func BenchmarkSyncMutex(b *testing.B) {
for n, max := 1, 4*runtime.GOMAXPROCS(0); n > 0 && n <= max; n *= 2 {
b.Run(fmt.Sprintf("%d", n), func(b *testing.B) {
var m sync.Mutex
var ready sync.WaitGroup
begin := make(chan struct{})
var end sync.WaitGroup
for i := 0; i < n; i++ {
ready.Add(1)
end.Add(1)
go func() {
ready.Done()
<-begin
for j := 0; j < b.N; j++ {
m.Lock()
m.Unlock()
}
end.Done()
}()
}
ready.Wait()
b.ResetTimer()
close(begin)
end.Wait()
})
}
}