...
Run Format

Source file src/pkg/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		for {
    52			old := m.state
    53			new := old | mutexLocked
    54			if old&mutexLocked != 0 {
    55				new = old + 1<<mutexWaiterShift
    56			}
    57			if awoke {
    58				// The goroutine has been woken from sleep,
    59				// so we need to reset the flag in either case.
    60				new &^= mutexWoken
    61			}
    62			if atomic.CompareAndSwapInt32(&m.state, old, new) {
    63				if old&mutexLocked == 0 {
    64					break
    65				}
    66				runtime_Semacquire(&m.sema)
    67				awoke = true
    68			}
    69		}
    70	
    71		if raceenabled {
    72			raceAcquire(unsafe.Pointer(m))
    73		}
    74	}
    75	
    76	// Unlock unlocks m.
    77	// It is a run-time error if m is not locked on entry to Unlock.
    78	//
    79	// A locked Mutex is not associated with a particular goroutine.
    80	// It is allowed for one goroutine to lock a Mutex and then
    81	// arrange for another goroutine to unlock it.
    82	func (m *Mutex) Unlock() {
    83		if raceenabled {
    84			_ = m.state
    85			raceRelease(unsafe.Pointer(m))
    86		}
    87	
    88		// Fast path: drop lock bit.
    89		new := atomic.AddInt32(&m.state, -mutexLocked)
    90		if (new+mutexLocked)&mutexLocked == 0 {
    91			panic("sync: unlock of unlocked mutex")
    92		}
    93	
    94		old := new
    95		for {
    96			// If there are no waiters or a goroutine has already
    97			// been woken or grabbed the lock, no need to wake anyone.
    98			if old>>mutexWaiterShift == 0 || old&(mutexLocked|mutexWoken) != 0 {
    99				return
   100			}
   101			// Grab the right to wake someone.
   102			new = (old - 1<<mutexWaiterShift) | mutexWoken
   103			if atomic.CompareAndSwapInt32(&m.state, old, new) {
   104				runtime_Semrelease(&m.sema)
   105				return
   106			}
   107			old = m.state
   108		}
   109	}
   110	

View as plain text