diff --git a/cmd/worker/main.go b/cmd/worker/main.go index 162c311e..e625fd4f 100644 --- a/cmd/worker/main.go +++ b/cmd/worker/main.go @@ -41,5 +41,5 @@ func run() { } func main() { - thread.MainWrapMaybe(run) + thread.Wrap(run) } diff --git a/go.mod b/go.mod index 48dc13dd..14f3bc7a 100644 --- a/go.mod +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum index 6f7fdd20..d99c4e79 100644 --- a/go.sum +++ b/go.sum @@ -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= diff --git a/pkg/emulator/graphics/sdl.go b/pkg/emulator/graphics/sdl.go index 7a67d63b..1f17cd1a 100644 --- a/pkg/emulator/graphics/sdl.go +++ b/pkg/emulator/graphics/sdl.go @@ -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()) } diff --git a/pkg/emulator/libretro/nanoarch/nanoarch.go b/pkg/emulator/libretro/nanoarch/nanoarch.go index 14afeef5..26e61b28 100644 --- a/pkg/emulator/libretro/nanoarch/nanoarch.go +++ b/pkg/emulator/libretro/nanoarch/nanoarch.go @@ -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() }) diff --git a/pkg/thread/mainthread_darwin.go b/pkg/thread/mainthread_darwin.go new file mode 100644 index 00000000..7f817b20 --- /dev/null +++ b/pkg/thread/mainthread_darwin.go @@ -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 +} diff --git a/pkg/thread/mainthread_darwin_test.go b/pkg/thread/mainthread_darwin_test.go new file mode 100644 index 00000000..bab4a92c --- /dev/null +++ b/pkg/thread/mainthread_darwin_test.go @@ -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) + } +} diff --git a/pkg/thread/thread.go b/pkg/thread/thread.go index 5b1c3e34..10de34cc 100644 --- a/pkg/thread/thread.go +++ b/pkg/thread/thread.go @@ -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() } diff --git a/pkg/thread/thread_darwin.go b/pkg/thread/thread_darwin.go new file mode 100644 index 00000000..bee4f73e --- /dev/null +++ b/pkg/thread/thread_darwin.go @@ -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) } diff --git a/pkg/worker/room/room_test.go b/pkg/worker/room/room_test.go index a004b840..9abd4576 100644 --- a/pkg/worker/room/room_test.go +++ b/pkg/worker/room/room_test.go @@ -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) { diff --git a/pkg/worker/worker.go b/pkg/worker/worker.go index 85553e01..c5d443ae 100644 --- a/pkg/worker/worker.go +++ b/pkg/worker/worker.go @@ -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")) }