2008-12-04 13:51:36 -07:00
|
|
|
// Copyright 2009 The Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
2011-04-19 17:57:05 -06:00
|
|
|
// Package sync provides basic synchronization primitives such as mutual
|
|
|
|
// exclusion locks. Other than the Once and WaitGroup types, most are intended
|
|
|
|
// for use by low-level library routines. Higher-level synchronization is
|
|
|
|
// better done via channels and communication.
|
allow copy of struct containing unexported fields
An experiment: allow structs to be copied even if they
contain unexported fields. This gives packages the
ability to return opaque values in their APIs, like reflect
does for reflect.Value but without the kludgy hacks reflect
resorts to.
In general, we trust programmers not to do silly things
like *x = *y on a package's struct pointers, just as we trust
programmers not to do unicode.Letter = unicode.Digit,
but packages that want a harder guarantee can introduce
an extra level of indirection, like in the changes to os.File
in this CL or by using an interface type.
All in one CL so that it can be rolled back more easily if
we decide this is a bad idea.
Originally discussed in March 2011.
https://groups.google.com/group/golang-dev/t/3f5d30938c7c45ef
R=golang-dev, adg, dvyukov, r, bradfitz, jan.mercl, gri
CC=golang-dev
https://golang.org/cl/5372095
2011-11-15 10:20:59 -07:00
|
|
|
//
|
|
|
|
// Values containing the types defined in this package should not be copied.
|
2008-12-04 13:51:36 -07:00
|
|
|
package sync
|
|
|
|
|
2012-10-07 12:07:03 -06:00
|
|
|
import (
|
2015-09-23 02:03:54 -06:00
|
|
|
"internal/race"
|
2012-10-07 12:07:03 -06:00
|
|
|
"sync/atomic"
|
|
|
|
"unsafe"
|
|
|
|
)
|
2008-12-04 13:51:36 -07:00
|
|
|
|
2009-05-22 23:43:57 -06:00
|
|
|
// A Mutex is a mutual exclusion lock.
|
|
|
|
// Mutexes can be created as part of other structures;
|
|
|
|
// the zero value for a Mutex is an unlocked mutex.
|
2009-01-20 15:40:40 -07:00
|
|
|
type Mutex struct {
|
2011-06-30 09:13:29 -06:00
|
|
|
state int32
|
|
|
|
sema uint32
|
2008-12-04 13:51:36 -07:00
|
|
|
}
|
|
|
|
|
2011-02-16 12:11:07 -07:00
|
|
|
// A Locker represents an object that can be locked and unlocked.
|
|
|
|
type Locker interface {
|
|
|
|
Lock()
|
|
|
|
Unlock()
|
|
|
|
}
|
|
|
|
|
2011-06-30 09:13:29 -06:00
|
|
|
const (
|
|
|
|
mutexLocked = 1 << iota // mutex is locked
|
|
|
|
mutexWoken
|
|
|
|
mutexWaiterShift = iota
|
|
|
|
)
|
|
|
|
|
2009-05-22 23:43:57 -06:00
|
|
|
// Lock locks m.
|
|
|
|
// If the lock is already in use, the calling goroutine
|
|
|
|
// blocks until the mutex is available.
|
2008-12-04 13:51:36 -07:00
|
|
|
func (m *Mutex) Lock() {
|
2011-06-30 09:13:29 -06:00
|
|
|
// Fast path: grab unlocked mutex.
|
|
|
|
if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
|
2015-09-23 02:03:54 -06:00
|
|
|
if race.Enabled {
|
|
|
|
race.Acquire(unsafe.Pointer(m))
|
2012-10-07 12:07:03 -06:00
|
|
|
}
|
2009-11-09 13:07:39 -07:00
|
|
|
return
|
2008-12-04 13:51:36 -07:00
|
|
|
}
|
2011-06-30 09:13:29 -06:00
|
|
|
|
|
|
|
awoke := false
|
2015-02-20 01:50:56 -07:00
|
|
|
iter := 0
|
2011-06-30 09:13:29 -06:00
|
|
|
for {
|
|
|
|
old := m.state
|
|
|
|
new := old | mutexLocked
|
|
|
|
if old&mutexLocked != 0 {
|
2015-02-20 01:50:56 -07:00
|
|
|
if runtime_canSpin(iter) {
|
|
|
|
// Active spinning makes sense.
|
|
|
|
// Try to set mutexWoken flag to inform Unlock
|
|
|
|
// to not wake other blocked goroutines.
|
|
|
|
if !awoke && old&mutexWoken == 0 && old>>mutexWaiterShift != 0 &&
|
|
|
|
atomic.CompareAndSwapInt32(&m.state, old, old|mutexWoken) {
|
|
|
|
awoke = true
|
|
|
|
}
|
|
|
|
runtime_doSpin()
|
|
|
|
iter++
|
|
|
|
continue
|
|
|
|
}
|
2011-06-30 09:13:29 -06:00
|
|
|
new = old + 1<<mutexWaiterShift
|
|
|
|
}
|
|
|
|
if awoke {
|
|
|
|
// The goroutine has been woken from sleep,
|
|
|
|
// so we need to reset the flag in either case.
|
2015-02-20 01:50:56 -07:00
|
|
|
if new&mutexWoken == 0 {
|
|
|
|
panic("sync: inconsistent mutex state")
|
|
|
|
}
|
2011-06-30 09:13:29 -06:00
|
|
|
new &^= mutexWoken
|
|
|
|
}
|
|
|
|
if atomic.CompareAndSwapInt32(&m.state, old, new) {
|
|
|
|
if old&mutexLocked == 0 {
|
|
|
|
break
|
|
|
|
}
|
2012-02-18 22:11:44 -07:00
|
|
|
runtime_Semacquire(&m.sema)
|
2011-06-30 09:13:29 -06:00
|
|
|
awoke = true
|
2015-02-20 01:50:56 -07:00
|
|
|
iter = 0
|
2011-06-30 09:13:29 -06:00
|
|
|
}
|
|
|
|
}
|
2012-10-07 12:07:03 -06:00
|
|
|
|
2015-09-23 02:03:54 -06:00
|
|
|
if race.Enabled {
|
|
|
|
race.Acquire(unsafe.Pointer(m))
|
2012-10-07 12:07:03 -06:00
|
|
|
}
|
2008-12-04 13:51:36 -07:00
|
|
|
}
|
|
|
|
|
2009-03-04 22:30:07 -07:00
|
|
|
// Unlock unlocks m.
|
|
|
|
// It is a run-time error if m is not locked on entry to Unlock.
|
|
|
|
//
|
|
|
|
// A locked Mutex is not associated with a particular goroutine.
|
|
|
|
// It is allowed for one goroutine to lock a Mutex and then
|
|
|
|
// arrange for another goroutine to unlock it.
|
2008-12-04 13:51:36 -07:00
|
|
|
func (m *Mutex) Unlock() {
|
2015-09-23 02:03:54 -06:00
|
|
|
if race.Enabled {
|
2013-04-08 15:46:54 -06:00
|
|
|
_ = m.state
|
2015-09-23 02:03:54 -06:00
|
|
|
race.Release(unsafe.Pointer(m))
|
2012-10-07 12:07:03 -06:00
|
|
|
}
|
|
|
|
|
2011-06-30 09:13:29 -06:00
|
|
|
// Fast path: drop lock bit.
|
|
|
|
new := atomic.AddInt32(&m.state, -mutexLocked)
|
|
|
|
if (new+mutexLocked)&mutexLocked == 0 {
|
2011-02-11 15:47:17 -07:00
|
|
|
panic("sync: unlock of unlocked mutex")
|
2008-12-04 13:51:36 -07:00
|
|
|
}
|
2011-06-30 09:13:29 -06:00
|
|
|
|
|
|
|
old := new
|
|
|
|
for {
|
|
|
|
// If there are no waiters or a goroutine has already
|
|
|
|
// been woken or grabbed the lock, no need to wake anyone.
|
|
|
|
if old>>mutexWaiterShift == 0 || old&(mutexLocked|mutexWoken) != 0 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
// Grab the right to wake someone.
|
|
|
|
new = (old - 1<<mutexWaiterShift) | mutexWoken
|
|
|
|
if atomic.CompareAndSwapInt32(&m.state, old, new) {
|
2012-02-18 22:11:44 -07:00
|
|
|
runtime_Semrelease(&m.sema)
|
2011-06-30 09:13:29 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
old = m.state
|
|
|
|
}
|
2008-12-04 13:51:36 -07:00
|
|
|
}
|