181 строка
		
	
	
	
		
			3,5 КиБ
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			181 строка
		
	
	
	
		
			3,5 КиБ
		
	
	
	
		
			Go
		
	
	
	
	
	
package sync
 | 
						|
 | 
						|
import (
 | 
						|
	"internal/task"
 | 
						|
	_ "unsafe"
 | 
						|
)
 | 
						|
 | 
						|
type Mutex struct {
 | 
						|
	locked  bool
 | 
						|
	blocked task.Stack
 | 
						|
}
 | 
						|
 | 
						|
//go:linkname scheduleTask runtime.runqueuePushBack
 | 
						|
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
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type RWMutex struct {
 | 
						|
	// waitingWriters are all of the tasks waiting for write locks.
 | 
						|
	waitingWriters task.Stack
 | 
						|
 | 
						|
	// waitingReaders are all of the tasks waiting for a read lock.
 | 
						|
	waitingReaders task.Stack
 | 
						|
 | 
						|
	// state is the current state of the RWMutex.
 | 
						|
	// Iff the mutex is completely unlocked, it contains rwMutexStateUnlocked (aka 0).
 | 
						|
	// Iff the mutex is write-locked, it contains rwMutexStateWLocked.
 | 
						|
	// While the mutex is read-locked, it contains the current number of readers.
 | 
						|
	state uint32
 | 
						|
}
 | 
						|
 | 
						|
const (
 | 
						|
	rwMutexStateUnlocked = uint32(0)
 | 
						|
	rwMutexStateWLocked  = ^uint32(0)
 | 
						|
	rwMutexMaxReaders    = rwMutexStateWLocked - 1
 | 
						|
)
 | 
						|
 | 
						|
func (rw *RWMutex) Lock() {
 | 
						|
	if rw.state == 0 {
 | 
						|
		// The mutex is completely unlocked.
 | 
						|
		// Lock without waiting.
 | 
						|
		rw.state = rwMutexStateWLocked
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	// Wait for the lock to be released.
 | 
						|
	rw.waitingWriters.Push(task.Current())
 | 
						|
	task.Pause()
 | 
						|
}
 | 
						|
 | 
						|
func (rw *RWMutex) Unlock() {
 | 
						|
	switch rw.state {
 | 
						|
	case rwMutexStateWLocked:
 | 
						|
		// This is correct.
 | 
						|
 | 
						|
	case rwMutexStateUnlocked:
 | 
						|
		// The mutex is already unlocked.
 | 
						|
		panic("sync: unlock of unlocked RWMutex")
 | 
						|
 | 
						|
	default:
 | 
						|
		// The mutex is read-locked instead of write-locked.
 | 
						|
		panic("sync: write-unlock of read-locked RWMutex")
 | 
						|
	}
 | 
						|
 | 
						|
	switch {
 | 
						|
	case rw.maybeUnblockReaders():
 | 
						|
		// Switched over to read mode.
 | 
						|
 | 
						|
	case rw.maybeUnblockWriter():
 | 
						|
		// Transferred to another writer.
 | 
						|
 | 
						|
	default:
 | 
						|
		// Nothing is waiting for the lock.
 | 
						|
		rw.state = rwMutexStateUnlocked
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (rw *RWMutex) RLock() {
 | 
						|
	if rw.state == rwMutexStateWLocked {
 | 
						|
		// Wait for the write lock to be released.
 | 
						|
		rw.waitingReaders.Push(task.Current())
 | 
						|
		task.Pause()
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	if rw.state == rwMutexMaxReaders {
 | 
						|
		panic("sync: too many readers on RWMutex")
 | 
						|
	}
 | 
						|
 | 
						|
	// Increase the reader count.
 | 
						|
	rw.state++
 | 
						|
}
 | 
						|
 | 
						|
func (rw *RWMutex) RUnlock() {
 | 
						|
	switch rw.state {
 | 
						|
	case rwMutexStateUnlocked:
 | 
						|
		// The mutex is already unlocked.
 | 
						|
		panic("sync: unlock of unlocked RWMutex")
 | 
						|
 | 
						|
	case rwMutexStateWLocked:
 | 
						|
		// The mutex is write-locked instead of read-locked.
 | 
						|
		panic("sync: read-unlock of write-locked RWMutex")
 | 
						|
	}
 | 
						|
 | 
						|
	rw.state--
 | 
						|
 | 
						|
	if rw.state == rwMutexStateUnlocked {
 | 
						|
		// This was the last reader.
 | 
						|
		// Try to unblock a writer.
 | 
						|
		rw.maybeUnblockWriter()
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func (rw *RWMutex) maybeUnblockReaders() bool {
 | 
						|
	var n uint32
 | 
						|
	for {
 | 
						|
		t := rw.waitingReaders.Pop()
 | 
						|
		if t == nil {
 | 
						|
			break
 | 
						|
		}
 | 
						|
 | 
						|
		n++
 | 
						|
		scheduleTask(t)
 | 
						|
	}
 | 
						|
	if n == 0 {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	rw.state = n
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
func (rw *RWMutex) maybeUnblockWriter() bool {
 | 
						|
	t := rw.waitingWriters.Pop()
 | 
						|
	if t == nil {
 | 
						|
		return false
 | 
						|
	}
 | 
						|
 | 
						|
	rw.state = rwMutexStateWLocked
 | 
						|
	scheduleTask(t)
 | 
						|
 | 
						|
	return true
 | 
						|
}
 | 
						|
 | 
						|
type Locker interface {
 | 
						|
	Lock()
 | 
						|
	Unlock()
 | 
						|
}
 | 
						|
 | 
						|
// RLocker returns a Locker interface that implements
 | 
						|
// the Lock and Unlock methods by calling rw.RLock and rw.RUnlock.
 | 
						|
func (rw *RWMutex) RLocker() Locker {
 | 
						|
	return (*rlocker)(rw)
 | 
						|
}
 | 
						|
 | 
						|
type rlocker RWMutex
 | 
						|
 | 
						|
func (r *rlocker) Lock()   { (*RWMutex)(r).RLock() }
 | 
						|
func (r *rlocker) Unlock() { (*RWMutex)(r).RUnlock() }
 |