...
Run Format

Source file src/sync/mutex.go

     1	// Copyright 2009 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// Package sync provides basic synchronization primitives such as mutual
     6	// exclusion locks.  Other than the Once and WaitGroup types, most are intended
     7	// for use by low-level library routines.  Higher-level synchronization is
     8	// better done via channels and communication.
     9	//
    10	// Values containing the types defined in this package should not be copied.
    11	package sync
    12	
    13	import (
    14		"sync/atomic"
    15		"unsafe"
    16	)
    17	
    18	// A Mutex is a mutual exclusion lock.
    19	// Mutexes can be created as part of other structures;
    20	// the zero value for a Mutex is an unlocked mutex.
    21	type Mutex struct {
    22		state int32
    23		sema  uint32
    24	}
    25	
    26	// A Locker represents an object that can be locked and unlocked.
    27	type Locker interface {
    28		Lock()
    29		Unlock()
    30	}
    31	
    32	const (
    33		mutexLocked = 1 << iota // mutex is locked
    34		mutexWoken
    35		mutexWaiterShift = iota
    36	)
    37	
    38	// Lock locks m.
    39	// If the lock is already in use, the calling goroutine
    40	// blocks until the mutex is available.
    41	func (m *Mutex) Lock() {
    42		// Fast path: grab unlocked mutex.
    43		if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
    44			if raceenabled {
    45				raceAcquire(unsafe.Pointer(m))
    46			}
    47			return
    48		}
    49	
    50		awoke := false
    51		iter := 0
    52		for {
    53			old := m.state
    54			new := old | mutexLocked
    55			if old&mutexLocked != 0 {
    56				if runtime_canSpin(iter) {
    57					// Active spinning makes sense.
    58					// Try to set mutexWoken flag to inform Unlock
    59					// to not wake other blocked goroutines.
    60					if !awoke && old&mutexWoken == 0 && old>>mutexWaiterShift != 0 &&
    61						atomic.CompareAndSwapInt32(&m.state, old, old|mutexWoken) {
    62						awoke = true
    63					}
    64					runtime_doSpin()
    65					iter++
    66					continue
    67				}
    68				new = old + 1<<mutexWaiterShift
    69			}
    70			if awoke {
    71				// The goroutine has been woken from sleep,
    72				// so we need to reset the flag in either case.
    73				if new&mutexWoken == 0 {
    74					panic("sync: inconsistent mutex state")
    75				}
    76				new &^= mutexWoken
    77			}
    78			if atomic.CompareAndSwapInt32(&m.state, old, new) {
    79				if old&mutexLocked == 0 {
    80					break
    81				}
    82				runtime_Semacquire(&m.sema)
    83				awoke = true
    84				iter = 0
    85			}
    86		}
    87	
    88		if raceenabled {
    89			raceAcquire(unsafe.Pointer(m))
    90		}
    91	}
    92	
    93	// Unlock unlocks m.
    94	// It is a run-time error if m is not locked on entry to Unlock.
    95	//
    96	// A locked Mutex is not associated with a particular goroutine.
    97	// It is allowed for one goroutine to lock a Mutex and then
    98	// arrange for another goroutine to unlock it.
    99	func (m *Mutex) Unlock() {
   100		if raceenabled {
   101			_ = m.state
   102			raceRelease(unsafe.Pointer(m))
   103		}
   104	
   105		// Fast path: drop lock bit.
   106		new := atomic.AddInt32(&m.state, -mutexLocked)
   107		if (new+mutexLocked)&mutexLocked == 0 {
   108			panic("sync: unlock of unlocked mutex")
   109		}
   110	
   111		old := new
   112		for {
   113			// If there are no waiters or a goroutine has already
   114			// been woken or grabbed the lock, no need to wake anyone.
   115			if old>>mutexWaiterShift == 0 || old&(mutexLocked|mutexWoken) != 0 {
   116				return
   117			}
   118			// Grab the right to wake someone.
   119			new = (old - 1<<mutexWaiterShift) | mutexWoken
   120			if atomic.CompareAndSwapInt32(&m.state, old, new) {
   121				runtime_Semrelease(&m.sema)
   122				return
   123			}
   124			old = m.state
   125		}
   126	}
   127	

View as plain text