diff options
author | Ayke van Laethem <[email protected]> | 2024-10-28 14:43:04 +0100 |
---|---|---|
committer | Ayke <[email protected]> | 2024-10-28 16:43:28 +0100 |
commit | 76d5b3d786034b5d58167a4b47ec36539bbdf55a (patch) | |
tree | aa45b6ce6a3324d800d3c83c4420d5abd2277147 | |
parent | 915132645eb29eed4de3fbf78d0e1077a8c6a8cf (diff) | |
download | tinygo-76d5b3d786034b5d58167a4b47ec36539bbdf55a.tar.gz tinygo-76d5b3d786034b5d58167a4b47ec36539bbdf55a.zip |
sync: don't use `volatile` in Mutex
Volatile loads/stors are only useful for communication with interrupts
or for memory-mapped I/O. They do not provide any sort of safety for
sync.Mutex, while making it *appear* as if it is more safe.
* `sync.Mutex` cannot be used safely inside interrupts, because any
blocking calls (including `Lock`) will cause a runtime panic.
* For multithreading, `volatile` is also the wrong choice. Atomic
operations should be used instead, and the current code would not
work for multithreaded programs anyway.
-rw-r--r-- | src/sync/mutex.go | 29 |
1 files changed, 6 insertions, 23 deletions
diff --git a/src/sync/mutex.go b/src/sync/mutex.go index 59f320d5d..3db705af0 100644 --- a/src/sync/mutex.go +++ b/src/sync/mutex.go @@ -3,12 +3,10 @@ package sync import ( "internal/task" _ "unsafe" - - "runtime/volatile" ) type Mutex struct { - state uint8 // Set to non-zero if locked. + locked bool blocked task.Stack } @@ -16,18 +14,18 @@ type Mutex struct { func scheduleTask(*task.Task) func (m *Mutex) Lock() { - if m.islocked() { + if m.locked { // Push self onto stack of blocked tasks, and wait to be resumed. m.blocked.Push(task.Current()) task.Pause() return } - m.setlock(true) + m.locked = true } func (m *Mutex) Unlock() { - if !m.islocked() { + if !m.locked { panic("sync: unlock of unlocked Mutex") } @@ -35,7 +33,7 @@ func (m *Mutex) Unlock() { if t := m.blocked.Pop(); t != nil { scheduleTask(t) } else { - m.setlock(false) + m.locked = false } } @@ -45,28 +43,13 @@ func (m *Mutex) Unlock() { // and use of TryLock is often a sign of a deeper problem // in a particular use of mutexes. func (m *Mutex) TryLock() bool { - if m.islocked() { + if m.locked { return false } m.Lock() return true } -func (m *Mutex) islocked() bool { - return volatile.LoadUint8(&m.state) != 0 -} - -func (m *Mutex) setlock(b bool) { - volatile.StoreUint8(&m.state, boolToU8(b)) -} - -func boolToU8(b bool) uint8 { - if b { - return 1 - } - return 0 -} - type RWMutex struct { // waitingWriters are all of the tasks waiting for write locks. waitingWriters task.Stack |