| // 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. | |
| // The sync package provides basic synchronization primitives | |
| // such as mutual exclusion locks. These are intended for use | |
| // by low-level library routines. Higher-level synchronization | |
| // is better done via channels and communication. | |
| package sync | |
| import "runtime" | |
| func cas(val *uint32, old, new uint32) bool | |
| // 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. | |
| type Mutex struct { | |
| key uint32 | |
| sema uint32 | |
| } | |
| // Add delta to *val, and return the new *val in a thread-safe way. If multiple | |
| // goroutines call xadd on the same val concurrently, the changes will be | |
| // serialized, and all the deltas will be added in an undefined order. | |
| func xadd(val *uint32, delta int32) (new uint32) { | |
| for { | |
| v := *val | |
| nv := v + uint32(delta) | |
| if cas(val, v, nv) { | |
| return nv | |
| } | |
| } | |
| panic("unreached") | |
| } | |
| // Lock locks m. | |
| // If the lock is already in use, the calling goroutine | |
| // blocks until the mutex is available. | |
| func (m *Mutex) Lock() { | |
| if xadd(&m.key, 1) == 1 { | |
| // changed from 0 to 1; we hold lock | |
| return | |
| } | |
| runtime.Semacquire(&m.sema) | |
| } | |
| // 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. | |
| func (m *Mutex) Unlock() { | |
| if xadd(&m.key, -1) == 0 { | |
| // changed from 1 to 0; no contention | |
| return | |
| } | |
| runtime.Semrelease(&m.sema) | |
| } |