-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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: iter: relax Pull to not panic because of thread locking state #67694
Comments
Just out of curiosity, will the next init be called on the main thread, or a different thread? If init is called on a different thread, wouldn't this break some existing libraries that assume init must be called on the main thread? |
The next init will run on a different thread. I assume few packages require the main thread during initialization, and packages that do should add a check for the main thread. Some packages call |
I thought some OS APIs must be called from the main thread (= the thread that is for init/main), but I might misunderstand. I'll look for an example. Another thing I came up with is the opposite pattern:
For example, if an OpenGL context is initialized for the current thread at 1, and the main function calls GL functions, the application no longer works due to 2. |
Absolutely, and in your example the "next init" that expect the main thread would fail, either immediately because of an is-main-thread check or because calls to its main-thread native API fails. My point is that it's already the case the two or more packages all requiring the main thread needs some kind of coordination to work together. The
I consider it unlikely, or at least bad design, to actually use the main thread during initialization.
In your stated example, yes. However, a well-designed OpenGL package would not call |
locking the main thread in init is also needed to avoid tripping Linux kernel namespace leak checks, when the initial thread get only later locked and then tainted. Without initial locking the initial thread cannot be destroyed, but permanently wedged, to use Go's runtime terminology. Locking the initial thread ensures that when later needing locking for namespace switches will happen on non-initial go routines and this on threads than can be thrown away, the reason being that this happens, for instance as part of an http handler goroutine. |
What makes me personally uncomfortable with the semantics you suggest is the goroutine executing I also don't see how that's preferable to something like |
Proposal Details
iter.Pull
snapshots the thread lock count and locked thread, if any. Callingnext
,stop
oryield
with a different snapshot panics. This proposal is about lifting that restriction.Adapted from my longer explanation at #65889 (comment), the proposal is to replace the panic behaviour with cooperative scheduling:
Let the locked thread (if any) and its lock count follow goroutine switches between caller and iterator, making
next
,stop
andyield
act as cooperative scheduling points. That is, the thread (and lock count) enteringnext
,stop
oryield
is the same thread (and lock count) that resumes execution from the return of its counterpart. For example, callingnext
from (locked) thread T will seeyield
return (locked) on thread T and vice versa.Notable consequences:
LockOSThread
is called by either caller or iterator, the execution trace has that thread locked from then on.Other than making
iter.Pull
more widely useful by eliminating panics, this proposal elegantly fixes #64755 and #64777 by thread stealing. For example:The text was updated successfully, but these errors were encountered: