faiface / pixel

A hand-crafted 2D game library in Go
MIT License
4.46k stars 245 forks source link

Run pixelgl.Run(run) on a different thread #264

Closed Alevsk closed 3 years ago

Alevsk commented 3 years ago

Hi, it is possible to run pixelgl.Run(run) in the background?, meaning not as part of the main thread? I have a REST api and I would like to use this library to generate some images whenever someone hits a particular endpoint, however im getting this error if I try to call the code from a function different that main.

2020-10-25 23:13:09.404 instagram-stories[24907:466987] *** Assertion failure in +[NSUndoManager _endTopLevelGroupings], /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/Foundation/Foundation-1677.104/Foundation/Misc.subproj/NSUndoManager.m:363
2020-10-25 23:13:09.404 instagram-stories[24907:466987] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: '+[NSUndoManager(NSInternal) _endTopLevelGroupings] is only safe to invoke on the main thread.'
*** First throw call stack:
(
    0   CoreFoundation                      0x00007fff349fcb57 __exceptionPreprocess + 250
    1   libobjc.A.dylib                     0x00007fff6d8485bf objc_exception_throw + 48
    2   CoreFoundation                      0x00007fff34a25d08 +[NSException raise:format:arguments:] + 88
    3   Foundation                          0x00007fff37117e9d -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 191
    4   Foundation                          0x00007fff370545ee +[NSUndoManager(NSPrivate) _endTopLevelGroupings] + 440
    5   AppKit                              0x00007fff31be165c -[NSApplication run] + 864
    6   instagram-stories                   0x00000000045f957d _glfwPlatformCreateWindow + 77
    7   instagram-stories                   0x00000000045f27e5 glfwCreateWindow + 485
    8   instagram-stories                   0x00000000045ff47b _cgo_78603e0816ec_Cfunc_glfwCreateWindow + 43
    9   instagram-stories                   0x0000000004068090 runtime.asmcgocall + 112
)
libc++abi.dylib: terminating with uncaught exception of type NSException
SIGABRT: abort
PC=0x7fff6eb3833a m=5 sigcode=0

goroutine 0 [idle]:
runtime: unknown pc 0x7fff6eb3833a
stack: frame={sp:0x70000ccc10c8, fp:0x0} stack=[0x70000cc43350,0x70000ccc2f50)
000070000ccc0fc8:  0000000000000080  0000000000000080
000070000ccc0fd8:  000070000ccc1420  0000000000000000
000070000ccc0fe8:  00000000050be000  000070000ccc1020
000070000ccc0ff8:  000070000ccc1030  0000000000000080
000070000ccc1008:  0000000000000000  0000000032aaaba2
000070000ccc1018:  0000000000000000  0000000000000000
000070000ccc1028:  000070000ccc1160  0000000000000000
000070000ccc1038:  0000000032aaaba2  0000000000000000
000070000ccc1048:  0000000000000000  0000000000000000
000070000ccc1058:  0000000000000000  0000000000000000
000070000ccc1068:  0000000000000000  0000000000000000
000070000ccc1078:  0000000000000003  0000000000000000
000070000ccc1088:  0000000000000000  00007fff9513be58
000070000ccc1098:  00007fff95138628  00007fff6ea79065
000070000ccc10a8:  0000000000000000  000070000ccc10f0
000070000ccc10b8:  00007fff6ea7b8ed  0000000000000000
000070000ccc10c8: <00007fff6ebf4e60  0000000000000003
000070000ccc10d8:  000070000ccc1270  000070000ccc1110
000070000ccc10e8:  00007fff95138620  000070000ccc1130
000070000ccc10f8:  00007fff6eabf808  91d5b9bc42600011
000070000ccc1108:  000070000ccc1230  00007000fffff9df
000070000ccc1118:  ffffffff00000008  000070000ccc1230
000070000ccc1128:  00007fff6bd21301  000070000ccc1260
000070000ccc1138:  00007fff6bd1e458  0000003000000018
000070000ccc1148:  000070000ccc1270  000070000ccc1180
000070000ccc1158:  0000000000000000  0000003000000018
000070000ccc1168:  000070000ccc1270  000070000ccc1180
000070000ccc1178:  0000000000000000  0000000000000000
000070000ccc1188:  00007fff6bd2135c  00007fff34d6feff
000070000ccc1198:  00007fff6d860530  00007fff34d6ff0a
000070000ccc11a8:  ffffffffffffffc9  0000000000000000
000070000ccc11b8:  0000000000000000  0000000000000000
runtime: unknown pc 0x7fff6eb3833a
stack: frame={sp:0x70000ccc10c8, fp:0x0} stack=[0x70000cc43350,0x70000ccc2f50)
000070000ccc0fc8:  0000000000000080  0000000000000080
000070000ccc0fd8:  000070000ccc1420  0000000000000000
000070000ccc0fe8:  00000000050be000  000070000ccc1020
000070000ccc0ff8:  000070000ccc1030  0000000000000080
000070000ccc1008:  0000000000000000  0000000032aaaba2
000070000ccc1018:  0000000000000000  0000000000000000
000070000ccc1028:  000070000ccc1160  0000000000000000
000070000ccc1038:  0000000032aaaba2  0000000000000000
000070000ccc1048:  0000000000000000  0000000000000000
000070000ccc1058:  0000000000000000  0000000000000000
000070000ccc1068:  0000000000000000  0000000000000000
000070000ccc1078:  0000000000000003  0000000000000000
000070000ccc1088:  0000000000000000  00007fff9513be58
000070000ccc1098:  00007fff95138628  00007fff6ea79065
000070000ccc10a8:  0000000000000000  000070000ccc10f0
000070000ccc10b8:  00007fff6ea7b8ed  0000000000000000
000070000ccc10c8: <00007fff6ebf4e60  0000000000000003
000070000ccc10d8:  000070000ccc1270  000070000ccc1110
000070000ccc10e8:  00007fff95138620  000070000ccc1130
000070000ccc10f8:  00007fff6eabf808  91d5b9bc42600011
000070000ccc1108:  000070000ccc1230  00007000fffff9df
000070000ccc1118:  ffffffff00000008  000070000ccc1230
000070000ccc1128:  00007fff6bd21301  000070000ccc1260
000070000ccc1138:  00007fff6bd1e458  0000003000000018
000070000ccc1148:  000070000ccc1270  000070000ccc1180
000070000ccc1158:  0000000000000000  0000003000000018
000070000ccc1168:  000070000ccc1270  000070000ccc1180
000070000ccc1178:  0000000000000000  0000000000000000
000070000ccc1188:  00007fff6bd2135c  00007fff34d6feff
000070000ccc1198:  00007fff6d860530  00007fff34d6ff0a
000070000ccc11a8:  ffffffffffffffc9  0000000000000000
000070000ccc11b8:  0000000000000000  0000000000000000

goroutine 40 [syscall]:
runtime.cgocall(0x45ff450, 0xc000749540, 0x4012c08)
    /usr/local/go/src/runtime/cgocall.go:133 +0x5b fp=0xc000749510 sp=0xc0007494d8 pc=0x400928b
github.com/go-gl/glfw/v3.3/glfw._Cfunc_glfwCreateWindow(0x78000000438, 0x57137a0, 0x0, 0x0, 0x0)
    _cgo_gotypes.go:630 +0x4e fp=0xc000749540 sp=0xc000749510 pc=0x45a40ce
github.com/go-gl/glfw/v3.3/glfw.CreateWindow.func2(0x438, 0x780, 0x57137a0, 0x0, 0x0, 0xc0007495b8)
    /Users/alevsk/go/pkg/mod/github.com/go-gl/glfw/v3.3/glfw@v0.0.0-20191125211704-12ad95a8df72/window.go:348 +0x99 fp=0xc000749578 sp=0xc000749540 pc=0x45b03f9
github.com/go-gl/glfw/v3.3/glfw.CreateWindow(0x438, 0x780, 0x4778998, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0)
    /Users/alevsk/go/pkg/mod/github.com/go-gl/glfw/v3.3/glfw@v0.0.0-20191125211704-12ad95a8df72/window.go:348 +0xe0 fp=0xc0007495f0 sp=0xc000749578 pc=0x45accc0
github.com/faiface/pixel/pixelgl.NewWindow.func1(0xc0007496c8, 0xc0007496d0)
    /Users/alevsk/go/pkg/mod/github.com/faiface/pixel@v0.10.0/pixelgl/window.go:144 +0x3bf fp=0xc000749688 sp=0xc0007495f0 pc=0x45bbf3f
github.com/faiface/mainthread.CallErr.func1()
    /Users/alevsk/go/pkg/mod/github.com/faiface/mainthread@v0.0.0-20171120011319-8b78f0a41ae3/mainthread.go:74 +0x32 fp=0xc0007496c0 sp=0xc000749688 pc=0x457b3e2
github.com/faiface/mainthread.Run(0x47a8f88)
    /Users/alevsk/go/pkg/mod/github.com/faiface/mainthread@v0.0.0-20171120011319-8b78f0a41ae3/mainthread.go:44 +0xbd fp=0xc000749760 sp=0xc0007496c0 pc=0x457af9d
github.com/faiface/pixel/pixelgl.Run(0x47a8f88)
    /Users/alevsk/go/pkg/mod/github.com/faiface/pixel@v0.10.0/pixelgl/run.go:32 +0x64 fp=0xc0007497b0 sp=0xc000749760 pc=0x45b8b94
github.com/Alevsk/instagram-stories/restapi.createStory(0xc000498130, 0x5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/restapi/user_stories.go:29 +0x175 fp=0xc0007497f8 sp=0xc0007497b0 pc=0x45ddbd5
github.com/Alevsk/instagram-stories/restapi.createStoryResponse(...)
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/restapi/user_stories.go:34
github.com/Alevsk/instagram-stories/restapi.registerStoriesHandler.func1(0xc000730200, 0xc000280030, 0xc00011cf01, 0xc0003e0070)
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/restapi/user_stories.go:18 +0x5f fp=0xc000749868 sp=0xc0007497f8 pc=0x45de80f
github.com/Alevsk/instagram-stories/restapi/operations/user_api.StoryCreateHandlerFunc.Handle(0x47a8ff0, 0xc000730200, 0xc000280030, 0x486c2c0, 0xc0003e0070)
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/restapi/operations/user_api/story_create.go:19 +0x3a fp=0xc000749898 sp=0xc000749868 pc=0x45061ba
github.com/Alevsk/instagram-stories/restapi/operations/user_api.(*StoryCreate).ServeHTTP(0xc0004717c0, 0x487b520, 0xc000740000, 0xc000730200)
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/restapi/operations/user_api/story_create.go:54 +0x16d fp=0xc000749910 sp=0xc000749898 pc=0x450634d
github.com/go-openapi/runtime/middleware.NewOperationExecutor.func1(0x487b520, 0xc000740000, 0xc000730200)
    /Users/alevsk/go/pkg/mod/github.com/go-openapi/runtime@v0.19.23/middleware/operation.go:28 +0x75 fp=0xc000749948 sp=0xc000749910 pc=0x4503fb5
net/http.HandlerFunc.ServeHTTP(0xc00050d8c0, 0x487b520, 0xc000740000, 0xc000730200)
    /usr/local/go/src/net/http/server.go:2041 +0x44 fp=0xc000749970 sp=0xc000749948 pc=0x4315184
github.com/go-openapi/runtime/middleware.NewRouter.func1(0x487b520, 0xc000740000, 0xc000730000)
    /Users/alevsk/go/pkg/mod/github.com/go-openapi/runtime@v0.19.23/middleware/router.go:77 +0x356 fp=0xc000749a40 sp=0xc000749970 pc=0x4504766
net/http.HandlerFunc.ServeHTTP(0xc00041f660, 0x487b520, 0xc000740000, 0xc000730000)
    /usr/local/go/src/net/http/server.go:2041 +0x44 fp=0xc000749a68 sp=0xc000749a40 pc=0x4315184
github.com/go-openapi/runtime/middleware.SwaggerUI.func1(0x487b520, 0xc000740000, 0xc000730000)
    /Users/alevsk/go/pkg/mod/github.com/go-openapi/runtime@v0.19.23/middleware/swaggerui.go:90 +0x286 fp=0xc000749b10 sp=0xc000749a68 pc=0x4504d36
net/http.HandlerFunc.ServeHTTP(0xc00015fc80, 0x487b520, 0xc000740000, 0xc000730000)
    /usr/local/go/src/net/http/server.go:2041 +0x44 fp=0xc000749b38 sp=0xc000749b10 pc=0x4315184
github.com/go-openapi/runtime/middleware.Spec.func1(0x487b520, 0xc000740000, 0xc000730000)
    /Users/alevsk/go/pkg/mod/github.com/go-openapi/runtime@v0.19.23/middleware/spec.go:46 +0x188 fp=0xc000749bc0 sp=0xc000749b38 pc=0x4504908
net/http.HandlerFunc.ServeHTTP(0xc00015fcc0, 0x487b520, 0xc000740000, 0xc000730000)
    /usr/local/go/src/net/http/server.go:2041 +0x44 fp=0xc000749be8 sp=0xc000749bc0 pc=0x4315184
net/http.serverHandler.ServeHTTP(0xc0001482a0, 0x487b520, 0xc000740000, 0xc000730000)
    /usr/local/go/src/net/http/server.go:2836 +0xa3 fp=0xc000749c18 sp=0xc000749be8 pc=0x4318513
net/http.(*conn).serve(0xc0001e6000, 0x487d020, 0xc0003f0400)
    /usr/local/go/src/net/http/server.go:1924 +0x86c fp=0xc000749fc8 sp=0xc000749c18 pc=0x4313f7c
runtime.goexit()
    /usr/local/go/src/runtime/asm_amd64.s:1373 +0x1 fp=0xc000749fd0 sp=0xc000749fc8 pc=0x4068931
created by net/http.(*Server).Serve
    /usr/local/go/src/net/http/server.go:2962 +0x35c

goroutine 1 [semacquire, locked to thread]:
sync.runtime_Semacquire(0xc0001e0954)
    /usr/local/go/src/runtime/sema.go:56 +0x42
sync.(*WaitGroup).Wait(0xc0001e0954)
    /usr/local/go/src/sync/waitgroup.go:130 +0x64
github.com/Alevsk/instagram-stories/restapi.(*Server).Serve(0xc0000b06e0, 0x486dae0, 0xc00015fcc0)
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/restapi/server.go:328 +0x264
main.startServer(0xc0001289c0, 0x0, 0x0)
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/cmd/instagram-stories/server.go:70 +0x49e
github.com/minio/cli.HandleAction(0x467aa80, 0x47a9838, 0xc0001289c0, 0xc000124800, 0x0)
    /Users/alevsk/go/pkg/mod/github.com/minio/cli@v1.22.0/app.go:498 +0xc8
github.com/minio/cli.Command.Run(0x4774172, 0x6, 0x0, 0x0, 0x4cf2a00, 0x1, 0x1, 0x478c585, 0x1f, 0x0, ...)
    /Users/alevsk/go/pkg/mod/github.com/minio/cli@v1.22.0/command.go:225 +0x9e8
github.com/minio/cli.(*App).Run(0xc000128000, 0xc000132000, 0x2, 0x2, 0x0, 0x0)
    /Users/alevsk/go/pkg/mod/github.com/minio/cli@v1.22.0/app.go:261 +0x741
main.main()
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/cmd/instagram-stories/main.go:114 +0xa7

goroutine 9 [syscall]:
os/signal.signal_recv(0x0)
    /usr/local/go/src/runtime/sigqueue.go:144 +0x96
os/signal.loop()
    /usr/local/go/src/os/signal/signal_unix.go:23 +0x22
created by os/signal.Notify.func1
    /usr/local/go/src/os/signal/signal.go:127 +0x44

goroutine 11 [chan receive]:
github.com/Alevsk/instagram-stories/restapi.handleInterrupt.func1()
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/restapi/server.go:495 +0x58
sync.(*Once).doSlow(0xc0001e0a70, 0xc000507fb0)
    /usr/local/go/src/sync/once.go:66 +0xec
sync.(*Once).Do(...)
    /usr/local/go/src/sync/once.go:57
github.com/Alevsk/instagram-stories/restapi.handleInterrupt(0xc0001e0a70, 0xc0000b06e0)
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/restapi/server.go:494 +0x63
created by github.com/Alevsk/instagram-stories/restapi.(*Server).Serve
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/restapi/server.go:173 +0x140

goroutine 12 [IO wait]:
internal/poll.runtime_pollWait(0x5679f18, 0x72, 0x0)
    /usr/local/go/src/runtime/netpoll.go:203 +0x55
internal/poll.(*pollDesc).wait(0xc000521118, 0x72, 0x0, 0x0, 0x4773824)
    /usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x45
internal/poll.(*pollDesc).waitRead(...)
    /usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Accept(0xc000521100, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
    /usr/local/go/src/internal/poll/fd_unix.go:384 +0x1d4
net.(*netFD).accept(0xc000521100, 0x9389a6206f4371df, 0x27ab6f4371df, 0x100000001)
    /usr/local/go/src/net/fd_unix.go:238 +0x42
net.(*TCPListener).accept(0xc00038e640, 0x5f9668f5, 0xc00006adf0, 0x408a286)
    /usr/local/go/src/net/tcpsock_posix.go:139 +0x32
net.(*TCPListener).Accept(0xc00038e640, 0xc00006ae40, 0x18, 0xc000583380, 0x43189bc)
    /usr/local/go/src/net/tcpsock.go:261 +0x64
net/http.(*Server).Serve(0xc0001482a0, 0x487b260, 0xc00038e640, 0x0, 0x0)
    /usr/local/go/src/net/http/server.go:2930 +0x25d
github.com/Alevsk/instagram-stories/restapi.(*Server).Serve.func2(0xc0001e0954, 0xc0001482a0, 0xc0000b06e0, 0x487b260, 0xc00038e640)
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/restapi/server.go:222 +0x74
created by github.com/Alevsk/instagram-stories/restapi.(*Server).Serve
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/restapi/server.go:220 +0xfb6

goroutine 13 [chan receive]:
github.com/Alevsk/instagram-stories/restapi.(*Server).handleShutdown(0xc0000b06e0, 0xc0001e0954, 0xc00038e660)
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/restapi/server.go:416 +0x89
created by github.com/Alevsk/instagram-stories/restapi.(*Server).Serve
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/restapi/server.go:326 +0x253

goroutine 26 [IO wait]:
internal/poll.runtime_pollWait(0x5679e38, 0x72, 0xffffffffffffffff)
    /usr/local/go/src/runtime/netpoll.go:203 +0x55
internal/poll.(*pollDesc).wait(0xc000466198, 0x72, 0x0, 0x1, 0xffffffffffffffff)
    /usr/local/go/src/internal/poll/fd_poll_runtime.go:87 +0x45
internal/poll.(*pollDesc).waitRead(...)
    /usr/local/go/src/internal/poll/fd_poll_runtime.go:92
internal/poll.(*FD).Read(0xc000466180, 0xc0001c6791, 0x1, 0x1, 0x0, 0x0, 0x0)
    /usr/local/go/src/internal/poll/fd_unix.go:169 +0x201
net.(*netFD).Read(0xc000466180, 0xc0001c6791, 0x1, 0x1, 0x0, 0x0, 0x0)
    /usr/local/go/src/net/fd_unix.go:202 +0x4f
net.(*conn).Read(0xc000010038, 0xc0001c6791, 0x1, 0x1, 0x0, 0x0, 0x0)
    /usr/local/go/src/net/net.go:184 +0x8e
net/http.(*connReader).backgroundRead(0xc0001c6780)
    /usr/local/go/src/net/http/server.go:689 +0x58
created by net/http.(*connReader).startBackgroundRead
    /usr/local/go/src/net/http/server.go:685 +0xd0

goroutine 27 [chan receive]:
github.com/faiface/mainthread.CallErr(0xc00042e280, 0xc00042e280, 0xc0000718f7)
    /Users/alevsk/go/pkg/mod/github.com/faiface/mainthread@v0.0.0-20171120011319-8b78f0a41ae3/mainthread.go:76 +0xcb
github.com/faiface/pixel/pixelgl.NewWindow(0x4778998, 0xc, 0x0, 0x0, 0x0, 0x0, 0x0, 0x4090e00000000000, 0x409e000000000000, 0x0, ...)
    /Users/alevsk/go/pkg/mod/github.com/faiface/pixel@v0.10.0/pixelgl/window.go:119 +0x15c
github.com/Alevsk/instagram-stories/internal/image-generator.Run()
    /Users/alevsk/go/src/github.com/Alevsk/instagram-stories/internal/image-generator/image.go:221 +0x2c9
github.com/faiface/mainthread.Run.func1(0x47a8f88, 0xc00073a060)
    /Users/alevsk/go/pkg/mod/github.com/faiface/mainthread@v0.0.0-20171120011319-8b78f0a41ae3/mainthread.go:37 +0x27
created by github.com/faiface/mainthread.Run
    /Users/alevsk/go/pkg/mod/github.com/faiface/mainthread@v0.0.0-20171120011319-8b78f0a41ae3/mainthread.go:36 +0xb1

rax    0x0
rbx    0x70000ccc3000
rcx    0x70000ccc10c8
rdx    0x0
rdi    0xa03
rsi    0x6
rbp    0x70000ccc10f0
rsp    0x70000ccc10c8
r8     0x70000ccc0f90
r9     0x70000ccc1160
r10    0x70000ccc3000
r11    0x246
r12    0xa03
r13    0x3000000008
r14    0x6
r15    0x16
rip    0x7fff6eb3833a
rflags 0x246
cs     0x7
fs     0x0
gs     0x0

I was looking at faiface/pixel/run.go the suggestion is to interact with PixelGL concurrently, is that the only solution right now?

Thanks.

Asday commented 3 years ago

That's just how it is with OpenGL.

My suggestion would be to create your context in a long-running goroutine, then send jobs to that through a channel. I'm not super familiar with pixel, but it looks like you may need to split the work done by pixelgl.Run() into parts, some to run from your main(), some to run in your long-running goroutine.

Alevsk commented 3 years ago

ong-running goroutin

will do, thanks for the suggestion