mirror of
https://github.com/kaspanet/kaspad.git
synced 2025-03-30 15:08:33 +00:00

* [NOD-447] Fix deadlocks and hanging goroutines * [NOD-447] Add tests * [NOD-447] Add unpatch to spawnPatch * [NOD-447] Don't send to releaseWait if waitingCounter is zero * [NOD-447] Change waitingCounter to boolean and rename to isReleaseWaitWaiting, change checkIfRunningSpawnsAreLeft to return only one function, and lock critical code related to wg.isReleaseWaitWaiting * [NOD-447] Rename txConfirmations -> txConfirmationsNoLock, txConfirmationsWithLock -> txConfirmations * [NOD-447] Add documentation and delete redundant spawn * [NOD-447] Fix comments * [NOD-447] Fix comments
80 lines
2.5 KiB
Go
80 lines
2.5 KiB
Go
package locks
|
|
|
|
import (
|
|
"sync"
|
|
)
|
|
|
|
// PriorityMutex is a read-write mutex with an additional low
|
|
// priority lock. It's implemented with the following
|
|
// components:
|
|
// * Data mutex: The actual lock on the data structure. Its
|
|
// type is sync.RWMutex for its high priority read lock.
|
|
// * High priority waiting group: A waiting group that is being
|
|
// incremented every time a high priority lock (read or write)
|
|
// is acquired, and decremented every time a high priority lock is
|
|
// unlocked. Low priority locks can start being held only
|
|
// when the waiting group is empty.
|
|
// * Low priority mutex: This mutex ensures that when the
|
|
// waiting group is empty, only one low priority lock
|
|
// will be able to lock the data mutex.
|
|
|
|
// PriorityMutex implements a lock with three priorities:
|
|
// * High priority write lock - locks the mutex with the highest priority.
|
|
// * High priority read lock - locks the mutex with lower priority than
|
|
// the high priority write lock. Can be held concurrently with other
|
|
// with other read locks.
|
|
// * Low priority write lock - locks the mutex with lower priority then
|
|
// the read lock.
|
|
type PriorityMutex struct {
|
|
dataMutex sync.RWMutex
|
|
highPriorityWaiting *waitGroup
|
|
lowPriorityMutex sync.Mutex
|
|
}
|
|
|
|
// NewPriorityMutex returns a new priority mutex
|
|
func NewPriorityMutex() *PriorityMutex {
|
|
lock := PriorityMutex{
|
|
highPriorityWaiting: newWaitGroup(),
|
|
}
|
|
return &lock
|
|
}
|
|
|
|
// LowPriorityWriteLock acquires a low-priority write lock.
|
|
func (mtx *PriorityMutex) LowPriorityWriteLock() {
|
|
mtx.lowPriorityMutex.Lock()
|
|
mtx.highPriorityWaiting.wait()
|
|
mtx.dataMutex.Lock()
|
|
}
|
|
|
|
// LowPriorityWriteUnlock unlocks the low-priority write lock
|
|
func (mtx *PriorityMutex) LowPriorityWriteUnlock() {
|
|
mtx.dataMutex.Unlock()
|
|
mtx.lowPriorityMutex.Unlock()
|
|
}
|
|
|
|
// HighPriorityWriteLock acquires a high-priority write lock.
|
|
func (mtx *PriorityMutex) HighPriorityWriteLock() {
|
|
mtx.highPriorityWaiting.add(1)
|
|
mtx.dataMutex.Lock()
|
|
}
|
|
|
|
// HighPriorityWriteUnlock unlocks the high-priority write lock
|
|
func (mtx *PriorityMutex) HighPriorityWriteUnlock() {
|
|
mtx.dataMutex.Unlock()
|
|
mtx.highPriorityWaiting.done()
|
|
}
|
|
|
|
// HighPriorityReadLock acquires a high-priority read
|
|
// lock.
|
|
func (mtx *PriorityMutex) HighPriorityReadLock() {
|
|
mtx.highPriorityWaiting.add(1)
|
|
mtx.dataMutex.RLock()
|
|
}
|
|
|
|
// HighPriorityReadUnlock unlocks the high-priority read
|
|
// lock
|
|
func (mtx *PriorityMutex) HighPriorityReadUnlock() {
|
|
mtx.highPriorityWaiting.done()
|
|
mtx.dataMutex.RUnlock()
|
|
}
|