Skip to content
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/mainthread: add mainthread.Do for mediating access to the main thread #70089

Open
eliasnaur opened this issue Oct 29, 2024 · 7 comments
Labels
Milestone

Comments

@eliasnaur
Copy link
Contributor

Proposal Details

This is #64777 (comment) in proposal form. It is a reduced and compatible variant of #64777 (comment).

I propose to add a new package, mainthread, with a single function, Do, that allows Go programs to execute a function on the main thread.

// Package mainthread mediates access to the program's main thread.
//
// Most Go programs do not need to run on specific threads 
// and can ignore this package, but some C libraries, often GUI-related libraries,
// only work when invoked from the program's main thread.
//
// [Do] runs a function on the main thread. No other code can run on the main thread
// until that function returns.
//
// Each package's initialization functions always run on the main thread,
// as if by successive calls to Do(init).
//
// For compatibility with earlier versions of Go, if an init function calls [runtime.LockOSThread], 
// then package main's func main also runs on the main thread, as if by Do(main).
package mainthread // imported as "runtime/mainthread"

// Do calls f on the main thread.
// Nothing else runs on the main thread until f returns.
// If f calls Do, the nested call panics.
//
// Package initialization functions run as if by Do(init).
// If an init function calls [runtime.LockOSThread], then package main's func main
// runs as if by Do(main), until the thread is unlocked using [runtime.UnlockOSThread].
//
// Do panics if the Go runtime is not in control of the main thread, such as in build modes
// c-shared and c-archive.
func Do(f func())

The larger proposal (#64777 (comment)) adds Yield and Waiting to support sharing the main thread in a Go program. However, the Go runtime doesn't always have control over the main thread, most notably in c-shared or c-archive mode on platforms such as Android. In those cases, the platform facility for mediating main thread access are strictly superior to mainthread.Do. See #64777 (comment) for a detailed analysis and assumptions.

In short, I believe it's better to accept this simpler proposal to only allow Go programs access to the main thread when the Go runtime has control over it, and let other cases be handled by platform API.

I hope this can be implemented in Go 1.24.

@gopherbot gopherbot added this to the Proposal milestone Oct 29, 2024
@gabyhelp
Copy link

Related Issues and Documentation

(Emoji vote if this was helpful or unhelpful; more detailed feedback welcome in this discussion.)

@apparentlymart
Copy link

(I see that earlier versions of this proposal were already discussed at length elsewhere and I did try to catch up on it first, but I apologize if I'm asking a question that's redundant from earlier discussions.)

If this function will panic when called from an environment where the Go runtime does not "own" the main thread, is it justified to also offer a function to test whether a call to this function is possible? That could, for example, allow a caller to choose to treat "I'm running in the wrong mode" as an error to be handled gracefully, rather than as an exception to be handled by panicking.

package mainthread

// CanDo returns true if and only if a subsequent call to [Do] would not panic.
func CanDo() bool

(Another variation of this would be for Do itself to return an error, but the usability of not having to worry about error handling when you know you're running in a context where this should work seems nice... this concern of detecting whether it will succeed seems specific to library developers that want their library to degrade gracefully in c-shared/c-archive/etc build modes.)

@Jorropo
Copy link
Member

Jorropo commented Oct 29, 2024

I hope this can be implemented in Go 1.24.

Just so you know, the current merge window closes 21 11, this would be a quick turn around time. There is the option of getting exceptions but theses are rare and usually limited to very low dangerous community impact.

@qiulaidongfeng
Copy link
Member

Does this API mean that if the main package imports a package that calls runtime.LockOSThread in init (for event loop in main thread) ,
like fyne did, calls to mainthread.Do by other packages will block permanently?

If so, that means we may need to modify existing valid code when using the mainthread package, which I don't think is backward-compatible,see #64777 (comment).
Fyne Info:
On Windows:
call LockOSThread in https://github.com/fyne-io/fyne/blob/7d813563712924b381ced18c04869c059e2cb4c6/internal/driver/glfw/loop.go#L35
event loop in https://github.com/fyne-io/fyne/blob/7d813563712924b381ced18c04869c059e2cb4c6/internal/driver/glfw/loop.go#L107

@eliasnaur
Copy link
Contributor Author

@qiulaidongfeng I believe your comment is addressed by #64777 (comment). In short, LockOSThread during init does not compose automatically with mainthread.Do, because they both act on a single resource, the main thread. There is no backwards compatibility issue, however, because this proposal doesn't affect the behaviour of LockOSThread during init.

@eliasnaur
Copy link
Contributor Author

@apparentlymart the original proposal says to panic in c-shared/c-archive mode, but I'm not against CanDo or the like.

@gopherbot
Copy link
Contributor

Change https://go.dev/cl/628815 mentions this issue: runtime/mainthread: new package

@ianlancetaylor ianlancetaylor moved this to Incoming in Proposals Nov 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Incoming
Development

No branches or pull requests

6 participants