tractordev / toolkit-go

MIT License
5 stars 4 forks source link

Linux: Unload() when called in goroutine get SIGABRT #7

Closed gysddn closed 1 month ago

gysddn commented 1 month ago

Unload works when it's used in the same thread, but when I try to test in a goroutine crashes.

The test case:

package main

import (
    "time"

    "tractor.dev/toolkit-go/desktop"
    "tractor.dev/toolkit-go/desktop/app"
    "tractor.dev/toolkit-go/desktop/window"
)

func close_after_delay(win *window.Window) {
    time.Sleep(4  * time.Second)
    win.Unload()
}

func main() {
    desktop.Start(func() {
        app.Run(app.Options{}, func() {
            w := window.New(window.Options{
                URL:   "https://google.com",
                Title: "Hello",
                Size: desktop.Size{
                    Width:  1000,
                    Height: 1000,
                },
                Visible:     true,
                Resizable:   true,
                Center:      true,
                Transparent: true,
            })
            w.Reload()
            w.SetTitle("Test")
            go close_after_delay(w)
        })

    })

}

The output:

Overriding existing handler for signal 10. Set JSC_SIGNAL_FOR_GC if you want WebKit to use a different signal
SIGABRT: abort
PC=0x77c22eaa53f4 m=6 sigcode=18446744073709551610
signal arrived during cgo execution

goroutine 18 gp=0xc000190000 m=6 mp=0xc000100008 [syscall]:
runtime.cgocall(0x4aa440, 0xc00006e748)
    /usr/lib/go/src/runtime/cgocall.go:167 +0x4b fp=0xc00006e720 sp=0xc00006e6e8 pc=0x46694b
tractor.dev/toolkit-go/desktop/linux._Cfunc_gtk_widget_destroy(0x2001b760)
    _cgo_gotypes.go:1285 +0x3f fp=0xc00006e748 sp=0xc00006e720 pc=0x4a1b5f
tractor.dev/toolkit-go/desktop/linux.(*Webview).Destroy.func1(0xc00006e770?)
    /home/gysddn/repos/toolkit-go/desktop/linux/linux.go:396 +0x34 fp=0xc00006e780 sp=0xc00006e748 pc=0x4a4cb4
tractor.dev/toolkit-go/desktop/linux.(*Webview).Destroy(0xc000180008)
    /home/gysddn/repos/toolkit-go/desktop/linux/linux.go:396 +0x1e fp=0xc00006e798 sp=0xc00006e780 pc=0x4a4c3e
tractor.dev/toolkit-go/desktop/window.(*Window).Unload(0xc000180000)
    /home/gysddn/repos/toolkit-go/desktop/window/window_linux.go:135 +0x3e fp=0xc00006e7b0 sp=0xc00006e798 pc=0x4a903e
main.close_after_delay(0xc000180000)
    /home/gysddn/test/go/main.go:13 +0x27 fp=0xc00006e7c8 sp=0xc00006e7b0 pc=0x4a9a47
main.main.func1.1.gowrap1()
    /home/gysddn/test/go/main.go:33 +0x25 fp=0xc00006e7e0 sp=0xc00006e7c8 pc=0x4a9ca5
runtime.goexit({})
    /usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc00006e7e8 sp=0xc00006e7e0 pc=0x472401
created by main.main.func1.1 in goroutine 1
    /home/gysddn/test/go/main.go:33 +0x10b

goroutine 1 gp=0xc0000061c0 m=nil [sleep, locked to thread]:
runtime.gopark(0x1b51e5a01cff?, 0x40bf9e?, 0xe0?, 0xe0?, 0xc00008df00?)
    /usr/lib/go/src/runtime/proc.go:424 +0xce fp=0xc00008deb8 sp=0xc00008de98 pc=0x46b78e
time.Sleep(0xf4240)
    /usr/lib/go/src/runtime/time.go:285 +0xf2 fp=0xc00008def0 sp=0xc00008deb8 pc=0x46e532
tractor.dev/toolkit-go/desktop.start()
    /home/gysddn/repos/toolkit-go/desktop/run_linux.go:21 +0x66 fp=0xc00008df18 sp=0xc00008def0 pc=0x4a6a06
tractor.dev/toolkit-go/desktop.Start(0x4db288)
    /home/gysddn/repos/toolkit-go/desktop/run.go:33 +0x48 fp=0xc00008df38 sp=0xc00008df18 pc=0x4a6928
main.main()
    /home/gysddn/test/go/main.go:17 +0x1a fp=0xc00008df50 sp=0xc00008df38 pc=0x4a9a7a
runtime.main()
    /usr/lib/go/src/runtime/proc.go:272 +0x28b fp=0xc00008dfe0 sp=0xc00008df50 pc=0x43ae2b
runtime.goexit({})
    /usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc00008dfe8 sp=0xc00008dfe0 pc=0x472401

goroutine 2 gp=0xc000006c40 m=nil [force gc (idle)]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
    /usr/lib/go/src/runtime/proc.go:424 +0xce fp=0xc000072fa8 sp=0xc000072f88 pc=0x46b78e
runtime.goparkunlock(...)
    /usr/lib/go/src/runtime/proc.go:430
runtime.forcegchelper()
    /usr/lib/go/src/runtime/proc.go:337 +0xb3 fp=0xc000072fe0 sp=0xc000072fa8 pc=0x43b173
runtime.goexit({})
    /usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc000072fe8 sp=0xc000072fe0 pc=0x472401
created by runtime.init.7 in goroutine 1
    /usr/lib/go/src/runtime/proc.go:325 +0x1a

goroutine 3 gp=0xc000007180 m=nil [GC sweep wait]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
    /usr/lib/go/src/runtime/proc.go:424 +0xce fp=0xc000073780 sp=0xc000073760 pc=0x46b78e
runtime.goparkunlock(...)
    /usr/lib/go/src/runtime/proc.go:430
runtime.bgsweep(0xc000026080)
    /usr/lib/go/src/runtime/mgcsweep.go:277 +0x94 fp=0xc0000737c8 sp=0xc000073780 pc=0x426ad4
runtime.gcenable.gowrap1()
    /usr/lib/go/src/runtime/mgc.go:203 +0x25 fp=0xc0000737e0 sp=0xc0000737c8 pc=0x41b465
runtime.goexit({})
    /usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc0000737e8 sp=0xc0000737e0 pc=0x472401
created by runtime.gcenable in goroutine 1
    /usr/lib/go/src/runtime/mgc.go:203 +0x66

goroutine 4 gp=0xc000007340 m=nil [GC scavenge wait]:
runtime.gopark(0xc000026080?, 0x4f8518?, 0x1?, 0x0?, 0xc000007340?)
    /usr/lib/go/src/runtime/proc.go:424 +0xce fp=0xc000073f78 sp=0xc000073f58 pc=0x46b78e
runtime.goparkunlock(...)
    /usr/lib/go/src/runtime/proc.go:430
runtime.(*scavengerState).park(0x58e620)
    /usr/lib/go/src/runtime/mgcscavenge.go:425 +0x49 fp=0xc000073fa8 sp=0xc000073f78 pc=0x424509
runtime.bgscavenge(0xc000026080)
    /usr/lib/go/src/runtime/mgcscavenge.go:653 +0x3c fp=0xc000073fc8 sp=0xc000073fa8 pc=0x424a7c
runtime.gcenable.gowrap2()
    /usr/lib/go/src/runtime/mgc.go:204 +0x25 fp=0xc000073fe0 sp=0xc000073fc8 pc=0x41b405
runtime.goexit({})
    /usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc000073fe8 sp=0xc000073fe0 pc=0x472401
created by runtime.gcenable in goroutine 1
    /usr/lib/go/src/runtime/mgc.go:204 +0xa5

goroutine 5 gp=0xc000007c00 m=nil [finalizer wait]:
runtime.gopark(0x0?, 0x0?, 0x0?, 0x0?, 0x0?)
    /usr/lib/go/src/runtime/proc.go:424 +0xce fp=0xc000074620 sp=0xc000074600 pc=0x46b78e
runtime.runfinq()
    /usr/lib/go/src/runtime/mfinal.go:193 +0x107 fp=0xc0000747e0 sp=0xc000074620 pc=0x41a4e7
runtime.goexit({})
    /usr/lib/go/src/runtime/asm_amd64.s:1700 +0x1 fp=0xc0000747e8 sp=0xc0000747e0 pc=0x472401
created by runtime.createfing in goroutine 1
    /usr/lib/go/src/runtime/mfinal.go:163 +0x3d

rax    0x0
rbx    0x71172
rcx    0x77c22eaa53f4
rdx    0x6
rdi    0x7116a
rsi    0x71172
rbp    0x77c1c5ffeec0
rsp    0x77c1c5ffee80
r8     0x1
r9     0x77c191430f68
r10    0x8
r11    0x246
r12    0x77c1c60006c0
r13    0x77c1be04c400
r14    0x6
r15    0x77c1be004680
rip    0x77c22eaa53f4
rflags 0x246
cs     0x33
fs     0x0
gs     0x0
exit status 2

Happens both on main and purego branches.

progrium commented 1 month ago

Yep, it's probably a similar rule as MacOS where you can't manipulate GUI objects outside the main thread. Unload() should be called inside of a desktop.Dispatch if called from a goroutine.

gysddn commented 1 month ago

Oh, I see. That makes sense 👍🏻 I did update my example with desktop.Dispatchand that did the trick.

Sure enough, it is stated here as well: https://github.com/linuxmint/gtk/blob/master/gdk/gdk.c#L470