aboutsummaryrefslogtreecommitdiff
path: root/src/runtime/lockrank_on.go
AgeCommit message (Collapse)Author
2021-03-10runtime: check partial lock ranking orderMichael Pratt
To ease readability we typically keep the partial order lists sorted by rank. This isn't required for correctness, it just makes it (slightly) easier to read the lists. Currently we must notice out-of-order entries during code review, which is an error-prone process. Add a test to enforce ordering, and fix the errors that have crept in. Most of the existing errors were misordered lockRankHchan or lockRankPollDesc. While we're here, I've moved the correctness check that the partial ordering satisfies the total ordering from init to a test case. This will allow us to catch these errors without even running staticlockranking. Change-Id: I9c11abe49ea26c556439822bb6a3183129600c3b Reviewed-on: https://go-review.googlesource.com/c/go/+/300171 Trust: Michael Pratt <mpratt@google.com> Trust: Dan Scales <danscales@google.com> Run-TryBot: Michael Pratt <mpratt@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Dan Scales <danscales@google.com>
2021-03-05runtime: update paniclk orderingMichael Pratt
Now that allglock is no longer taken in throw, paniclk can move to the bottom of the lock order where it belongs. There is no fundamental reason that we really need to skip checks on paniclk in lockWithRank (despite the recursive throws that could be caused by lock rank checking, startpanic_m would still allow the crash to complete). However, the partial order of lockRankPanic should be every single lock that may be held before a throw, nil dereference, out-of-bounds access, which our partial order doesn't cover. Updates #42669 Change-Id: Ic3efaea873dc2dd9fd5b0d6ccdd5319730b29a22 Reviewed-on: https://go-review.googlesource.com/c/go/+/270862 Trust: Michael Pratt <mpratt@google.com> Run-TryBot: Michael Pratt <mpratt@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Michael Knyszek <mknyszek@google.com>
2021-02-24docs: fix spellingJohn Bampton
Change-Id: Ib689e5793d9cb372e759c4f34af71f004010c822 GitHub-Last-Rev: d63798388e5dcccb984689b0ae39b87453b97393 GitHub-Pull-Request: golang/go#44259 Reviewed-on: https://go-review.googlesource.com/c/go/+/291949 Reviewed-by: Emmanuel Odeke <emmanuel@orijtech.com> Reviewed-by: Ian Lance Taylor <iant@golang.org> Trust: Matthew Dempsky <mdempsky@google.com> Trust: Robert Griesemer <gri@golang.org>
2021-02-20all: go fmt std cmd (but revert vendor)Russ Cox
Make all our package sources use Go 1.17 gofmt format (adding //go:build lines). Part of //go:build change (#41184). See https://golang.org/design/draft-gobuild Change-Id: Ia0534360e4957e58cd9a18429c39d0e32a6addb4 Reviewed-on: https://go-review.googlesource.com/c/go/+/294430 Trust: Russ Cox <rsc@golang.org> Run-TryBot: Russ Cox <rsc@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Jason A. Donenfeld <Jason@zx2c4.com> Reviewed-by: Ian Lance Taylor <iant@golang.org>
2020-10-30runtime: tighten systemstack in lock assertionsMichael Pratt
We use systemstack on the locking path to avoid stack splits which could cause locks to be recorded out of order (see comment on lockWithRank). This concern is irrelevant on lock assertions, where we simply need to see if a lock is held and don't care if another is taken in the meantime. Thus we can simply drop these unless we actually need to crash. Updates #40677 Change-Id: I85d730913a59867753ee1ed0386f8c5efda5c432 Reviewed-on: https://go-review.googlesource.com/c/go/+/266718 Run-TryBot: Michael Pratt <mpratt@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com> Trust: Michael Pratt <mpratt@google.com>
2020-10-30runtime: add world-stopped assertionsMichael Pratt
Stopping the world is an implicit lock for many operations, so we should assert the world is stopped in functions that require it. This is enabled along with the rest of lock ranking, though it is a bit orthogonal and likely cheap enough to enable all the time should we choose. Requiring a lock _or_ world stop is common, so that can be expressed as well. Updates #40677 Change-Id: If0a58544f4251d367f73c4120c9d39974c6cd091 Reviewed-on: https://go-review.googlesource.com/c/go/+/248577 Run-TryBot: Michael Pratt <mpratt@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com> Trust: Michael Pratt <mpratt@google.com>
2020-09-25runtime: drop nosplit from primary lockrank functionsMichael Pratt
acquireLockRank and releaseLockRank are called from nosplit context, and thus must be nosplit. lockWithRank, unlockWithRank, and lockWithRankMayAcquire are called from spittable context, and thus don't strictly need to be nosplit. The stated reasoning for making these functions nosplit is to avoid re-entrant calls due to a stack split on function entry taking a lock. There are two potential issues at play here: 1. A stack split on function entry adds a new lock ordering edge before we (a) take lock l, or (b) release lock l. 2. A stack split in a child call (such as to lock2) introduces a new lock ordering edge _in the wrong order_ because e.g., in the case of lockWithRank, we've noted that l is taken, but the stack split in lock2 actually takes stack split locks _before_ l is actually locked. (1) is indeed avoided by marking these functions nosplit, but this is really just a bit of duct tape that generally has no effect overall. Any earlier call can have a stack split and introduce the same new edge. This includes lock/unlock which are not nosplit! I began this CL as a change to extend nosplit to lock and unlock to try to make this mitigation more effective, but I've realized that as long as there is a _single_ nosplit call between a lock and unlock, we can end up with the edge. There seems to be few enough cases without any calls that is does not seem worth the extra cognitive load to extend nosplit throughout all of the locking functions. (2) is a real issue which would cause incorrect ordering, but it is already handled by switching to the system stack before recording the lock ordering. Adding / removing nosplit has no effect on this issue. Change-Id: I94fbd21b2bf928dbf1bf71aabb6788fc0a012829 Reviewed-on: https://go-review.googlesource.com/c/go/+/254367 Run-TryBot: Michael Pratt <mpratt@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Dan Scales <danscales@google.com> Trust: Michael Pratt <mpratt@google.com>
2020-09-22runtime: check held locks with staticlockrankingMichael Pratt
When lock ranking is enabled, we can now assert that lock preconditions are met by checking that the caller holds required locks on function entry. This change adds the infrastructure to add assertions. Actual assertions will be added for various locks in subsequent changes. Some functions are protected by locks that are not directly accessible in the function. In that case, we can use assertRankHeld to check that any lock with the rank is held. This is less precise, but it avoids requiring passing the lock into the functions. Updates #40677 Change-Id: I843c6874867f975e90a063f087b6e2ffc147877b Reviewed-on: https://go-review.googlesource.com/c/go/+/245484 Run-TryBot: Michael Pratt <mpratt@google.com> TryBot-Result: Go Bot <gobot@golang.org> Trust: Michael Pratt <mpratt@google.com> Reviewed-by: Michael Knyszek <mknyszek@google.com>
2020-07-25runtime, sync: add copyright headers to new filesIan Lance Taylor
For #38029 Change-Id: I71de2b66c1de617d32c46d4f2c1866f9ff1756ec Reviewed-on: https://go-review.googlesource.com/c/go/+/244631 Run-TryBot: Ian Lance Taylor <iant@golang.org> Reviewed-by: Dan Scales <danscales@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
2020-05-07runtime: incorporate Gscan acquire/release into lock ranking orderDan Scales
I added routines that can acquire/release a particular rank without acquiring/releasing an associated lock. I added lockRankGscan as a rank for acquiring/releasing the Gscan bit. castogscanstatus() and casGtoPreemptScan() are acquires of the Gscan bit. casfrom_Gscanstatus() is a release of the Gscan bit. casgstatus() is like an acquire and release of the Gscan bit, since it will wait if Gscan bit is currently set. We have a cycle between hchan and Gscan. The acquisition of Gscan and then hchan only happens in syncadjustsudogs() when the G is suspended, so the main normal ordering (get hchan, then get Gscan) can't be happening. So, I added a new rank lockRankHchanLeaf that is used when acquiring hchan locks in syncadjustsudogs. This ranking is set so no other locks can be acquired except other hchan locks. Fixes #38922 Change-Id: I58ce526a74ba856cb42078f7b9901f2832e1d45c Reviewed-on: https://go-review.googlesource.com/c/go/+/228417 Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Austin Clements <austin@google.com>
2020-04-07runtime: static lock ranking for the runtime (enabled by GOEXPERIMENT)Dan Scales
I took some of the infrastructure from Austin's lock logging CR https://go-review.googlesource.com/c/go/+/192704 (with deadlock detection from the logs), and developed a setup to give static lock ranking for runtime locks. Static lock ranking establishes a documented total ordering among locks, and then reports an error if the total order is violated. This can happen if a deadlock happens (by acquiring a sequence of locks in different orders), or if just one side of a possible deadlock happens. Lock ordering deadlocks cannot happen as long as the lock ordering is followed. Along the way, I found a deadlock involving the new timer code, which Ian fixed via https://go-review.googlesource.com/c/go/+/207348, as well as two other potential deadlocks. See the constants at the top of runtime/lockrank.go to show the static lock ranking that I ended up with, along with some comments. This is great documentation of the current intended lock ordering when acquiring multiple locks in the runtime. I also added an array lockPartialOrder[] which shows and enforces the current partial ordering among locks (which is embedded within the total ordering). This is more specific about the dependencies among locks. I don't try to check the ranking within a lock class with multiple locks that can be acquired at the same time (i.e. check the ranking when multiple hchan locks are acquired). Currently, I am doing a lockInit() call to set the lock rank of most locks. Any lock that is not otherwise initialized is assumed to be a leaf lock (a very high rank lock), so that eliminates the need to do anything for a bunch of locks (including all architecture-dependent locks). For two locks, root.lock and notifyList.lock (only in the runtime/sema.go file), it is not as easy to do lock initialization, so instead, I am passing the lock rank with the lock calls. For Windows compilation, I needed to increase the StackGuard size from 896 to 928 because of the new lock-rank checking functions. Checking of the static lock ranking is enabled by setting GOEXPERIMENT=staticlockranking before doing a run. To make sure that the static lock ranking code has no overhead in memory or CPU when not enabled by GOEXPERIMENT, I changed 'go build/install' so that it defines a build tag (with the same name) whenever any experiment has been baked into the toolchain (by checking Expstring()). This allows me to avoid increasing the size of the 'mutex' type when static lock ranking is not enabled. Fixes #38029 Change-Id: I154217ff307c47051f8dae9c2a03b53081acd83a Reviewed-on: https://go-review.googlesource.com/c/go/+/207619 Reviewed-by: Dan Scales <danscales@google.com> Reviewed-by: Keith Randall <khr@golang.org> Run-TryBot: Dan Scales <danscales@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>