diff --git a/src/internal/task/mutex-cooperative.go b/src/internal/task/mutex-cooperative.go new file mode 100644 index 000000000..e40966bed --- /dev/null +++ b/src/internal/task/mutex-cooperative.go @@ -0,0 +1,43 @@ +package task + +type Mutex struct { + locked bool + blocked Stack +} + +func (m *Mutex) Lock() { + if m.locked { + // Push self onto stack of blocked tasks, and wait to be resumed. + m.blocked.Push(Current()) + Pause() + return + } + + m.locked = true +} + +func (m *Mutex) Unlock() { + if !m.locked { + panic("sync: unlock of unlocked Mutex") + } + + // Wake up a blocked task, if applicable. + if t := m.blocked.Pop(); t != nil { + scheduleTask(t) + } else { + m.locked = false + } +} + +// TryLock tries to lock m and reports whether it succeeded. +// +// 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. +func (m *Mutex) TryLock() bool { + if m.locked { + return false + } + m.Lock() + return true +} diff --git a/src/sync/cond.go b/src/sync/cond.go index fb5f22492..139d8e022 100644 --- a/src/sync/cond.go +++ b/src/sync/cond.go @@ -89,3 +89,6 @@ func (c *Cond) Wait() { // signal. task.Pause() } + +//go:linkname scheduleTask runtime.scheduleTask +func scheduleTask(*task.Task) diff --git a/src/sync/mutex.go b/src/sync/mutex.go index b62b9fafd..08c674d7e 100644 --- a/src/sync/mutex.go +++ b/src/sync/mutex.go @@ -2,53 +2,9 @@ package sync import ( "internal/task" - _ "unsafe" ) -type Mutex struct { - locked bool - blocked task.Stack -} - -//go:linkname scheduleTask runtime.scheduleTask -func scheduleTask(*task.Task) - -func (m *Mutex) Lock() { - if m.locked { - // Push self onto stack of blocked tasks, and wait to be resumed. - m.blocked.Push(task.Current()) - task.Pause() - return - } - - m.locked = true -} - -func (m *Mutex) Unlock() { - if !m.locked { - panic("sync: unlock of unlocked Mutex") - } - - // Wake up a blocked task, if applicable. - if t := m.blocked.Pop(); t != nil { - scheduleTask(t) - } else { - m.locked = false - } -} - -// TryLock tries to lock m and reports whether it succeeded. -// -// 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. -func (m *Mutex) TryLock() bool { - if m.locked { - return false - } - m.Lock() - return true -} +type Mutex = task.Mutex type RWMutex struct { // waitingWriters are all of the tasks waiting for write locks.