-
Notifications
You must be signed in to change notification settings - Fork 17.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: runtime: pair LockOSThread, UnlockOSThread calls #20458
Comments
This seems like a backwards-incompatible change and likely not worth fixing. It's easy to spawn a new goroutine instead. /cc @aclements @randall77 |
To be clear, I'm more concerned that func (r *SomeReceiver) SomeCWrapperMethod() {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
…
} With the current implementation, that's a bug waiting to happen: it assumes that the caller is never running on a locked thread. Some samples: In contrast, the correct uses are almost always redundant: go func() {
runtime.LockOSThread()
defer runtime.UnlockOSThread()
someCFunction()
}() Every use I have seen is either redundant or paired. (And about the only correct, non-redundant paired uses I have been able to find are within the Go runtime itself.) It's true that the change I propose is not strictly backward-compatible, but as far as I can tell it would bring the standard library in line with the semantics that user code is already written to expect. |
This seems like something that could be statically checked. Although it is a correctness issue it probably isn't common enough to warrant inclusion in vet. Could be a useful addition to @dominikh's staticcheck though. |
See also #20395 - one possible solution to both issues is to make Unlock a noop. |
@iand The property you would want to check statically is that the methods that call |
All you need to check is that LockOSThread is only called from within goroutines created by the same package. The examples above are not "safe sometimes". They're just unsafe. |
Here's a great illustration of a program that hit this issue in the wild: |
It's certainly true that there's a lot of incorrect code that this would make correct, much in the same way that the monotonic time change fixed a lot of incorrect timing code. Suppose we do change this, and we do it on day 1 of the Go 1.10 cycle and find out what breaks. Does that make sense? Objections? |
We discussed this in the compiler/runtime meeting and decided this seems reasonable. I'll prep a CL. |
CL https://golang.org/cl/45752 mentions this issue. |
Currently, there is a single bit for LockOSThread, so two calls to LockOSThread followed by one call to UnlockOSThread will unlock the thread. There's evidence (golang#20458) that this is almost never what people want or expect and it makes these APIs very hard to use correctly or reliably. Change this so LockOSThread/UnlockOSThread can be nested and the calling goroutine will not be unwired until UnlockOSThread has been called as many times as LockOSThread has. This should fix the vast majority of incorrect uses while having no effect on the vast majority of correct uses. Fixes golang#20458. Change-Id: I1464e5e9a0ea4208fbb83638ee9847f929a2bacb Reviewed-on: https://go-review.googlesource.com/45752 Run-TryBot: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
#20395 (comment) reminded me once again of the awkwardness of
runtime.UnlockOSThread
.As currently documented,
UnlockOSThread
is not safe for use in any library code: a library that callsLockOSThread
has no way to know whether the caller also calledLockOSThread
(and hence expects the thread to remain locked). In practice,UnlockOSThread
is only safe to use within the package that spawned the goroutine to be locked.UnlockOSThread
could be made safe for use in libraries with one simple change: after N calls toLockOSThread
, do not actually unlock the thread until the Nth call toUnlockOSThread
. This would make the API a bit easier to use correctly and eliminate a potential source of subtle concurrency bugs.The text was updated successfully, but these errors were encountered: