TMutex based on sync.Mutex.

Updates #231

PiperOrigin-RevId: 290854399
This commit is contained in:
Ian Gudger
2020-01-21 18:49:28 -08:00
committed by gVisor bot
parent a944fcd946
commit 1effdc091b
3 changed files with 122 additions and 0 deletions
+2
View File
@@ -38,6 +38,7 @@ go_library(
"race_unsafe.go",
"seqcount.go",
"syncutil.go",
"tmutex_unsafe.go",
],
importpath = "gvisor.dev/gvisor/pkg/sync",
)
@@ -48,6 +49,7 @@ go_test(
srcs = [
"downgradable_rwmutex_test.go",
"seqcount_test.go",
"tmutex_test.go",
],
embed = [":sync"],
)
+71
View File
@@ -0,0 +1,71 @@
// Copyright 2019 The gVisor Authors.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package sync
import (
"sync"
"testing"
"unsafe"
)
// TestStructSize verifies that syncMutex's size hasn't drifted from the
// standard library's version.
//
// The correctness of this package relies on these remaining in sync.
func TestStructSize(t *testing.T) {
const (
got = unsafe.Sizeof(syncMutex{})
want = unsafe.Sizeof(sync.Mutex{})
)
if got != want {
t.Errorf("got sizeof(syncMutex) = %d, want = sizeof(sync.Mutex) = %d", got, want)
}
}
// TestFieldValues verifies that the semantics of syncMutex.state from the
// standard library's implementation.
//
// The correctness of this package relies on these remaining in sync.
func TestFieldValues(t *testing.T) {
var m TMutex
m.Lock()
if got := *m.state(); got != mutexLocked {
t.Errorf("got locked sync.Mutex.state = %d, want = %d", got, mutexLocked)
}
m.Unlock()
if got := *m.state(); got != mutexUnlocked {
t.Errorf("got unlocked sync.Mutex.state = %d, want = %d", got, mutexUnlocked)
}
}
func TestDoubleTryLock(t *testing.T) {
var m TMutex
if !m.TryLock() {
t.Fatal("failed to aquire lock")
}
if m.TryLock() {
t.Fatal("unexpectedly succeeded in aquiring locked mutex")
}
}
func TestTryLockAfterLock(t *testing.T) {
var m TMutex
m.Lock()
if m.TryLock() {
t.Fatal("unexpectedly succeeded in aquiring locked mutex")
}
}
func TestTryLockUnlock(t *testing.T) {
var m TMutex
if !m.TryLock() {
t.Fatal("failed to aquire lock")
}
m.Unlock()
if !m.TryLock() {
t.Fatal("failed to aquire lock after unlock")
}
}
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2019 The gVisor Authors.
//
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.13
// +build !go1.15
// When updating the build constraint (above), check that syncMutex matches the
// standard library sync.Mutex definition.
package sync
import (
"sync"
"sync/atomic"
"unsafe"
)
// TMutex is a try lock.
type TMutex struct {
sync.Mutex
}
type syncMutex struct {
state int32
sema uint32
}
func (m *TMutex) state() *int32 {
return &(*syncMutex)(unsafe.Pointer(&m.Mutex)).state
}
const (
mutexUnlocked = 0
mutexLocked = 1
)
// TryLock tries to aquire the mutex. It returns true if it succeeds and false
// otherwise. TryLock does not block.
func (m *TMutex) TryLock() bool {
if atomic.CompareAndSwapInt32(m.state(), mutexUnlocked, mutexLocked) {
if RaceEnabled {
RaceAcquire(unsafe.Pointer(&m.Mutex))
}
return true
}
return false
}