Open eliasnaur opened 3 months ago
cc @golang/compiler
Thanks for filing this tracking issue. You're right that this is an unfortunate and rather hidden limitation of the current approach, though we hope that people won't run into this very often.
We do have a rough idea of how to fix this that would also probably improve the performance of cgo code. The key observation is that, while the C code needs to run on the same thread if you call back into C or return to C, the Go code itself does not. So, the idea is that we do a "half" OS thread lock on a C -> Go call. We don't actively kick the Go code off that thread, but we allow the scheduler to schedule it to other threads like usual. That way, if it very quickly returns or calls back into C, you don't pay the cost of moving threads. But if it blocks or runs for a long time in Go, the scheduler can move it around to make within-Go transitions cheap. When you transition back to C (either by returning or calling), at that point we make sure we're running on the original thread by switching back to it if we aren't already running on it.
You're right that this is an unfortunate and rather hidden limitation of the current approach, though we hope that people won't run into this very often.
FWIW, I ran into this :) As far as I can tell, both https://github.com/golang/go/issues/64755 and https://github.com/golang/go/issues/64777 can be closed in favor of an elegant range-func construction:
import "gioui.org/app" // Calls LockOSThread during init, as required by the platform.
func main() {
w := new(app.Window)
for _, e := range w.Events() {
// Respond to e, usually by redrawing window content.
}
}
even on the platforms where w.Events
starts and run a native event loop. The caveat is that the user cannot exit the loop (e.g. break
), because the native event loop is in general uncooperative: once started, it cannot be stopped nor paused[0].
The workaround is to introduce a singleton intermediate iter.Pull
iterator to suspend the native main event loop and return control to the user. Without a fix for this issue, however, yield
'ing from the native event loop to the intermediate iterator panics. The same happens if the user attempts to use their own iter.Pull
with w.Events
.
[0]: For example, the iOS UIApplicationMain
function must be called from the main thread and blocks forever.
Go version
go version devel go1.23-105ac94486 Fri May 17 21:53:50 2024 +0000 darwin/arm64
Output of
go env
in your module/workspace:What did you do?
Iterate values generated from Cgo with
iter.Pull
:What did you see happen?
What did you expect to see?
The equivalent https://github.com/golang/go/issues/65946 was closed as fixed, and the fix, https://go-review.googlesource.com/c/go/+/583675 does mention
Note that the error is at the very least confusing because there is no explicit thread locking involved (LockOSThread) in the above program. I realize using
iter.Pull
with Cgo may not be covered by "simple cases", in which case I worry about the "may" in the later mentionIn other words, I believe the above program should work in a future Go version, in which case this issue tracks the implementation.