Main thread lock refactoring (#367)

Use slim main thread locking function for macOS instead of a lib.
This commit is contained in:
sergystepanov 2022-06-12 13:39:23 +03:00 committed by GitHub
parent af98bddb14
commit e53cf45fa7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 85 additions and 45 deletions

View file

@ -41,5 +41,5 @@ func run() {
}
func main() {
thread.MainWrapMaybe(run)
thread.Wrap(run)
}

1
go.mod
View file

@ -4,7 +4,6 @@ go 1.13
require (
github.com/cavaliercoder/grab v1.0.1-0.20201108051000-98a5bfe305ec
github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3
github.com/fsnotify/fsnotify v1.5.1
github.com/go-gl/gl v0.0.0-20211210172815-726fda9656d6
github.com/gofrs/flock v0.8.1

2
go.sum
View file

@ -60,8 +60,6 @@ github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymF
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3 h1:baVdMKlASEHrj19iqjARrPbaRisD7EuZEVJj6ZMLl1Q=
github.com/faiface/mainthread v0.0.0-20171120011319-8b78f0a41ae3/go.mod h1:VEPNJUlxl5KdWjDvz6Q1l+rJlxF2i6xqDeGuGAxa87M=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=

View file

@ -62,7 +62,7 @@ func Init(cfg Config) {
}
// In OSX 10.14+ window creation and context creation must happen in the main thread
thread.MainMaybe(createWindow)
thread.Main(createWindow)
BindContext()
@ -77,7 +77,7 @@ func Deinit() {
log.Printf("[SDL] [OpenGL] deinitialization...")
destroyFramebuffer()
// In OSX 10.14+ window deletion must happen in the main thread
thread.MainMaybe(destroyWindow)
thread.Main(destroyWindow)
sdl.Quit()
log.Printf("[SDL] [OpenGL] deinitialized (%v, %v)", sdl.GetError(), getDriverError())
}

View file

@ -594,7 +594,7 @@ func toggleMultitap() {
func nanoarchShutdown() {
if usesLibCo {
thread.MainMaybe(func() {
thread.Main(func() {
C.bridge_execute(retroUnloadGame)
C.bridge_execute(retroDeinit)
if video.isGl {
@ -603,7 +603,7 @@ func nanoarchShutdown() {
})
} else {
if video.isGl {
thread.MainMaybe(func() {
thread.Main(func() {
// running inside a go routine, lock the thread to make sure the OpenGL context stays current
runtime.LockOSThread()
graphics.BindContext()
@ -612,7 +612,7 @@ func nanoarchShutdown() {
C.bridge_retro_unload_game(retroUnloadGame)
C.bridge_retro_deinit(retroDeinit)
if video.isGl {
thread.MainMaybe(func() {
thread.Main(func() {
deinitVideo()
runtime.UnlockOSThread()
})

View file

@ -0,0 +1,45 @@
package thread
import (
"runtime"
"sync"
)
type fun struct {
fn func()
done chan struct{}
}
var dPool = sync.Pool{New: func() interface{} { return make(chan struct{}) }}
var fq = make(chan fun, runtime.GOMAXPROCS(0))
func init() {
runtime.LockOSThread()
}
// Run is a wrapper for the main function.
// Run returns when run (argument) function finishes.
func Run(run func()) {
done := make(chan struct{})
go func() {
run()
done <- struct{}{}
}()
for {
select {
case f := <-fq:
f.fn()
f.done <- struct{}{}
case <-done:
return
}
}
}
// Call queues function f on the main thread and blocks until the function f finishes.
func Call(f func()) {
done := dPool.Get().(chan struct{})
defer dPool.Put(done)
fq <- fun{fn: f, done: done}
<-done
}

View file

@ -0,0 +1,16 @@
package thread
import "testing"
func init() {
runtime.LockOSThread()
}
func TestMainThread(t *testing.T) {
value := 0
fn := func() { value = 1 }
Main(fn)
if value != 1 {
t.Errorf("wrong value %v", value)
}
}

View file

@ -1,32 +1,7 @@
// This package used for locking goroutines to
// the main OS thread.
// See: https://github.com/golang/go/wiki/LockOSThread
//go:build !darwin
// +build !darwin
package thread
import (
"runtime"
"github.com/faiface/mainthread"
)
var isMacOs = runtime.GOOS == "darwin"
// MainWrapMaybe enables functions to be executed in the main thread.
// Enabled for macOS only.
func MainWrapMaybe(f func()) {
if isMacOs {
mainthread.Run(f)
} else {
f()
}
}
// MainMaybe calls a function on the main thread.
// Enabled for macOS only.
func MainMaybe(f func()) {
if isMacOs {
mainthread.Call(f)
} else {
f()
}
}
func Wrap(f func()) { f() }
func Main(f func()) { f() }

View file

@ -0,0 +1,10 @@
// This package used for locking goroutines to
// the main OS thread.
// See: https://github.com/golang/go/wiki/LockOSThread
package thread
// Wrap enables functions to be executed in the main thread.
func Wrap(f func()) { Run(f) }
// Main calls a function on the main thread.
func Main(f func()) { Call(f) }

View file

@ -62,7 +62,7 @@ func TestMain(m *testing.M) {
flag.StringVar(&outputPath, "outputPath", "./", "Output path for generated files")
flag.BoolVar(&autoGlContext, "autoGlContext", false, "Set auto GL context choose for headless machines")
thread.MainWrapMaybe(func() { os.Exit(m.Run()) })
thread.Wrap(func() { os.Exit(m.Run()) })
}
func TestRoom(t *testing.T) {
@ -130,7 +130,7 @@ func TestRoomWithGL(t *testing.T) {
time.Sleep(2 * time.Second)
}
thread.MainMaybe(run)
thread.Main(run)
}
func TestAllEmulatorRooms(t *testing.T) {

View file

@ -17,10 +17,7 @@ func New(conf worker.Config) (services service.Group) {
mainHandler := NewHandler(conf, httpSrv.Addr)
mainHandler.Prepare()
services.Add(
httpSrv,
mainHandler,
)
services.Add(httpSrv, mainHandler)
if conf.Worker.Monitoring.IsEnabled() {
services.Add(monitoring.New(conf.Worker.Monitoring, httpSrv.GetHost(), "worker"))
}