@ -2,58 +2,32 @@
// Use of this source code is governed by a BSD-style
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// license that can be found in the LICENSE file.
//go:build go1.13 && !go1.19
// +build go1.13,!go1.19
// This file makes assumptions about the inner workings of sync.Mutex and sync.RWMutex.
// This includes not just their memory layout but their invariants and functionality.
// To prevent accidents, it is limited to a known good subset of Go versions.
package syncs
package syncs
import (
import (
"sync"
"sync"
"sync/atomic"
"unsafe"
)
const (
mutexLocked = 1
// sync.Mutex field offsets
stateOffset = 0
// sync.RWMutext field offsets
mutexOffset = 0
readerCountOffset = 16
)
)
// add returns a pointer with value p + off.
func add ( p unsafe . Pointer , off uintptr ) unsafe . Pointer {
return unsafe . Pointer ( uintptr ( p ) + off )
}
// AssertLocked panics if m is not locked.
// AssertLocked panics if m is not locked.
func AssertLocked ( m * sync . Mutex ) {
func AssertLocked ( m * sync . Mutex ) {
p := add ( unsafe . Pointer ( m ) , stateOffset )
if m . TryLock ( ) {
if atomic . LoadInt32 ( ( * int32 ) ( p ) ) & mutexLocked == 0 {
m . Unlock ( )
panic ( "mutex is not locked" )
panic ( "mutex is not locked" )
}
}
}
}
// AssertRLocked panics if rw is not locked for reading or writing.
// AssertRLocked panics if rw is not locked for reading or writing.
func AssertRLocked ( rw * sync . RWMutex ) {
func AssertRLocked ( rw * sync . RWMutex ) {
p := add ( unsafe . Pointer ( rw ) , readerCountOffset )
if rw . TryLock ( ) {
if atomic . LoadInt32 ( ( * int32 ) ( p ) ) != 0 {
rw . Unlock ( )
// There are readers present or writers pending, so someone has a read lock.
panic ( "mutex is not locked" )
return
}
}
// No readers.
AssertWLocked ( rw )
}
}
// AssertWLocked panics if rw is not locked for writing.
// AssertWLocked panics if rw is not locked for writing.
func AssertWLocked ( rw * sync . RWMutex ) {
func AssertWLocked ( rw * sync . RWMutex ) {
m := ( * sync . Mutex ) ( add ( unsafe . Pointer ( rw ) , mutexOffset ) )
if rw . TryRLock ( ) {
AssertLocked ( m )
rw . RUnlock ( )
panic ( "mutex is not rlocked" )
}
}
}