diff options
| author | Josh Bleecher Snyder <josh@tailscale.com> | 2022-03-16 17:02:16 -0700 |
|---|---|---|
| committer | Josh Bleecher Snyder <josharian@gmail.com> | 2022-03-17 10:57:41 -0700 |
| commit | 997b19545bbf8e5f548eaa87df2f8b87c77e9b4b (patch) | |
| tree | 26e130a347d81400baca999aba814fd518fc3c09 /syncs | |
| parent | ead16b24ec64ef1c82956011f119c500ae360d07 (diff) | |
| download | tailscale-997b19545bbf8e5f548eaa87df2f8b87c77e9b4b.tar.xz tailscale-997b19545bbf8e5f548eaa87df2f8b87c77e9b4b.zip | |
syncs: use TryLock and TryRLock instead of unsafe
The docs say:
Note that while correct uses of TryLock do exist, they are rare,
and use of TryLock is often a sign of a deeper problem in a particular use of mutexes.
Rare code! Or bad code! Who can tell!
Signed-off-by: Josh Bleecher Snyder <josh@tailscale.com>
Diffstat (limited to 'syncs')
| -rw-r--r-- | syncs/locked.go | 44 |
1 files changed, 9 insertions, 35 deletions
diff --git a/syncs/locked.go b/syncs/locked.go index f4498a800..e7b5ec311 100644 --- a/syncs/locked.go +++ b/syncs/locked.go @@ -2,58 +2,32 @@ // Use of this source code is governed by a BSD-style // 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 import ( "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. func AssertLocked(m *sync.Mutex) { - p := add(unsafe.Pointer(m), stateOffset) - if atomic.LoadInt32((*int32)(p))&mutexLocked == 0 { + if m.TryLock() { + m.Unlock() panic("mutex is not locked") } } // AssertRLocked panics if rw is not locked for reading or writing. func AssertRLocked(rw *sync.RWMutex) { - p := add(unsafe.Pointer(rw), readerCountOffset) - if atomic.LoadInt32((*int32)(p)) != 0 { - // There are readers present or writers pending, so someone has a read lock. - return + if rw.TryLock() { + rw.Unlock() + panic("mutex is not locked") } - // No readers. - AssertWLocked(rw) } // AssertWLocked panics if rw is not locked for writing. func AssertWLocked(rw *sync.RWMutex) { - m := (*sync.Mutex)(add(unsafe.Pointer(rw), mutexOffset)) - AssertLocked(m) + if rw.TryRLock() { + rw.RUnlock() + panic("mutex is not rlocked") + } } |
