...
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		"internal/race"
    15		"sync/atomic"
    16		"unsafe"
    17	)
    18	
    19	// A Mutex is a mutual exclusion lock.
    20	// Mutexes can be created as part of other structures;
    21	// the zero value for a Mutex is an unlocked mutex.
    22	type Mutex struct {
    23		state int32
    24		sema  uint32
    25	}
    26	
    27	// A Locker represents an object that can be locked and unlocked.
    28	type Locker interface {
    29		Lock()
    30		Unlock()
    31	}
    32	
    33	const (
    34		mutexLocked = 1 << iota // mutex is locked
    35		mutexWoken
    36		mutexWaiterShift = iota
    37	)
    38	
    39	// Lock locks m.
    40	// If the lock is already in use, the calling goroutine
    41	// blocks until the mutex is available.
    42	func (m *Mutex) Lock() {
    43		// Fast path: grab unlocked mutex.
    44		if atomic.CompareAndSwapInt32(&m.state, 0, mutexLocked) {
    45			if race.Enabled {
    46				race.Acquire(unsafe.Pointer(m))
    47			}
    48			return
    49		}
    50	
    51		awoke := false
    52		iter := 0
    53		for {
    54			old := m.state
    55			new := old | mutexLocked
    56			if old&mutexLocked != 0 {
    57				if runtime_canSpin(iter) {
    58					// Active spinning makes sense.
    59					// Try to set mutexWoken flag to inform Unlock
    60					// to not wake other blocked goroutines.
    61					if !awoke && old&mutexWoken == 0 && old>>mutexWaiterShift != 0 &&
    62						atomic.CompareAndSwapInt32(&m.state, old, old|mutexWoken) {
    63						awoke = true
    64					}
    65					runtime_doSpin()
    66					iter++
    67					continue
    68				}
    69				new = old + 1<<mutexWaiterShift
    70			}
    71			if awoke {
    72				// The goroutine has been woken from sleep,
    73				// so we need to reset the flag in either case.
    74				if new&mutexWoken == 0 {
    75					panic("sync: inconsistent mutex state")
    76				}
    77				new &^= mutexWoken
    78			}
    79			if atomic.CompareAndSwapInt32(&m.state, old, new) {
    80				if old&mutexLocked == 0 {
    81					break
    82				}
    83				runtime_Semacquire(&m.sema)
    84				awoke = true
    85				iter = 0
    86			}
    87		}
    88	
    89		if race.Enabled {
    90			race.Acquire(unsafe.Pointer(m))
    91		}
    92	}
    93	
    94	// Unlock unlocks m.
    95	// It is a run-time error if m is not locked on entry to Unlock.
    96	//
    97	// A locked Mutex is not associated with a particular goroutine.
    98	// It is allowed for one goroutine to lock a Mutex and then
    99	// arrange for another goroutine to unlock it.
   100	func (m *Mutex) Unlock() {
   101		if race.Enabled {
   102			_ = m.state
   103			race.Release(unsafe.Pointer(m))
   104		}
   105	
   106		// Fast path: drop lock bit.
   107		new := atomic.AddInt32(&m.state, -mutexLocked)
   108		if (new+mutexLocked)&mutexLocked == 0 {
   109			panic("sync: unlock of unlocked mutex")
   110		}
   111	
   112		old := new
   113		for {
   114			// If there are no waiters or a goroutine has already
   115			// been woken or grabbed the lock, no need to wake anyone.
   116			if old>>mutexWaiterShift == 0 || old&(mutexLocked|mutexWoken) != 0 {
   117				return
   118			}
   119			// Grab the right to wake someone.
   120			new = (old - 1<<mutexWaiterShift) | mutexWoken
   121			if atomic.CompareAndSwapInt32(&m.state, old, new) {
   122				runtime_Semrelease(&m.sema)
   123				return
   124			}
   125			old = m.state
   126		}
   127	}
   128	

View as plain text