-
Notifications
You must be signed in to change notification settings - Fork 17.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
runtime: allow futex OSes to use sema-based mutex
Implement sema{create,sleep,wakeup} in terms of the futex syscall when available. Split the lock2/unlock2 implementations out of lock_sema.go and lock_futex.go (which they shared with runtime.note) to allow swapping in new implementations of those. Let futex-based platforms use the semaphore-based mutex implementation. Control that via the new "spinbitmutex" GOEXPERMENT value, disabled by default. This lays the groundwork for a "spinbit" mutex implementation; it does not include the new mutex implementation. For #68578. Change-Id: I091289c85124212a87abec7079ecbd9e610b4270 Reviewed-on: https://go-review.googlesource.com/c/go/+/622996 Reviewed-by: Michael Knyszek <[email protected]> Reviewed-by: Cherry Mui <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
- Loading branch information
Showing
13 changed files
with
347 additions
and
251 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
// Copyright 2011 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. | ||
|
||
//go:build (dragonfly || freebsd || linux) && !goexperiment.spinbitmutex | ||
|
||
package runtime | ||
|
||
import ( | ||
"internal/runtime/atomic" | ||
) | ||
|
||
// This implementation depends on OS-specific implementations of | ||
// | ||
// futexsleep(addr *uint32, val uint32, ns int64) | ||
// Atomically, | ||
// if *addr == val { sleep } | ||
// Might be woken up spuriously; that's allowed. | ||
// Don't sleep longer than ns; ns < 0 means forever. | ||
// | ||
// futexwakeup(addr *uint32, cnt uint32) | ||
// If any procs are sleeping on addr, wake up at most cnt. | ||
|
||
const ( | ||
mutex_unlocked = 0 | ||
mutex_locked = 1 | ||
mutex_sleeping = 2 | ||
|
||
active_spin = 4 | ||
active_spin_cnt = 30 | ||
passive_spin = 1 | ||
) | ||
|
||
// Possible lock states are mutex_unlocked, mutex_locked and mutex_sleeping. | ||
// mutex_sleeping means that there is presumably at least one sleeping thread. | ||
// Note that there can be spinning threads during all states - they do not | ||
// affect mutex's state. | ||
|
||
type mWaitList struct{} | ||
|
||
func mutexContended(l *mutex) bool { | ||
return atomic.Load(key32(&l.key)) > mutex_locked | ||
} | ||
|
||
func lock(l *mutex) { | ||
lockWithRank(l, getLockRank(l)) | ||
} | ||
|
||
func lock2(l *mutex) { | ||
gp := getg() | ||
|
||
if gp.m.locks < 0 { | ||
throw("runtime·lock: lock count") | ||
} | ||
gp.m.locks++ | ||
|
||
// Speculative grab for lock. | ||
v := atomic.Xchg(key32(&l.key), mutex_locked) | ||
if v == mutex_unlocked { | ||
return | ||
} | ||
|
||
// wait is either MUTEX_LOCKED or MUTEX_SLEEPING | ||
// depending on whether there is a thread sleeping | ||
// on this mutex. If we ever change l->key from | ||
// MUTEX_SLEEPING to some other value, we must be | ||
// careful to change it back to MUTEX_SLEEPING before | ||
// returning, to ensure that the sleeping thread gets | ||
// its wakeup call. | ||
wait := v | ||
|
||
timer := &lockTimer{lock: l} | ||
timer.begin() | ||
// On uniprocessors, no point spinning. | ||
// On multiprocessors, spin for ACTIVE_SPIN attempts. | ||
spin := 0 | ||
if ncpu > 1 { | ||
spin = active_spin | ||
} | ||
for { | ||
// Try for lock, spinning. | ||
for i := 0; i < spin; i++ { | ||
for l.key == mutex_unlocked { | ||
if atomic.Cas(key32(&l.key), mutex_unlocked, wait) { | ||
timer.end() | ||
return | ||
} | ||
} | ||
procyield(active_spin_cnt) | ||
} | ||
|
||
// Try for lock, rescheduling. | ||
for i := 0; i < passive_spin; i++ { | ||
for l.key == mutex_unlocked { | ||
if atomic.Cas(key32(&l.key), mutex_unlocked, wait) { | ||
timer.end() | ||
return | ||
} | ||
} | ||
osyield() | ||
} | ||
|
||
// Sleep. | ||
v = atomic.Xchg(key32(&l.key), mutex_sleeping) | ||
if v == mutex_unlocked { | ||
timer.end() | ||
return | ||
} | ||
wait = mutex_sleeping | ||
futexsleep(key32(&l.key), mutex_sleeping, -1) | ||
} | ||
} | ||
|
||
func unlock(l *mutex) { | ||
unlockWithRank(l) | ||
} | ||
|
||
func unlock2(l *mutex) { | ||
v := atomic.Xchg(key32(&l.key), mutex_unlocked) | ||
if v == mutex_unlocked { | ||
throw("unlock of unlocked lock") | ||
} | ||
if v == mutex_sleeping { | ||
futexwakeup(key32(&l.key), 1) | ||
} | ||
|
||
gp := getg() | ||
gp.m.mLockProfile.recordUnlock(l) | ||
gp.m.locks-- | ||
if gp.m.locks < 0 { | ||
throw("runtime·unlock: lock count") | ||
} | ||
if gp.m.locks == 0 && gp.preempt { // restore the preemption request in case we've cleared it in newstack | ||
gp.stackguard0 = stackPreempt | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.