golang-ui / nuklear

This project provides Go bindings for nuklear.h — a small ANSI C GUI library.

Home Page:https://github.com/vurtun/nuklear

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

error: signal arrived during external code execution

Loafter opened this issue · comments

I creating gui application with multiple goroute functionality. Some of goroute execute another application (exec.Command) with parsing output. At this momen application have only one goroute for rendering and dispatch event. When i try dispatch event application raise exeption
signal arrived during external code execution

github.com/golang-ui/nuklear/nk._Cfunc_nk_convert(0x307fd0, 0xe0aa70, 0x7a94930, 0x7a949b0, 0x7a958d0, 0xc000000000)
github.com/golang-ui/nuklear/nk/_obj/_cgo_gotypes.go:3065 +0x54
github.com/golang-ui/nuklear/nk.NkConvert.func1(0x307fd0, 0xe0aa70, 0x7a94930, 0x7a949b0, 0x7a958d0, 0x20000)
C:/Users/212402712/go/src/github.com/golang-ui/nuklear/nk/nk.go:155 +0x167
github.com/golang-ui/nuklear/nk.NkConvert(0x307fd0, 0xe0aa70, 0x7a94930, 0x7a949b0, 0xc04206fd18, 0xc04206fce0)
C:/Users/212402712/go/src/github.com/golang-ui/nuklear/nk/nk.go:155 +0x68
github.com/golang-ui/nuklear/nk.NkPlatformRender(0x1, 0x80000, 0x20000)
C:/Users/212402712/go/src/github.com/golang-ui/nuklear/nk/impl_glfw_gl3.go:99 +0x448

Hi, make sure the GFX goroutine (where GL initialisation, Nuklear initialisation are happening) is locked to the thread using runtime.LockOSThread()

If your loop is in the main goroutine (as in example), the following code is sufficient

func init() {
	runtime.LockOSThread()
}

If this doesn't help, I'd need the sample code to reproduce this error.

this is minimal code for reproduce this effect
please be patient, it hapen randomly. For me it take 20 times click for reproduce this effect
Windows 7 x64 go1.9
package main

package main

import (
	"github.com/go-gl/gl/v3.2-core/gl"
	"github.com/go-gl/glfw/v3.2/glfw"
	"github.com/golang-ui/nuklear/nk"
	"log"
	"os/exec"
	"runtime"
)

const (
	maxVertexBuffer  = 512 * 1024
	maxElementBuffer = 128 * 1024
)

func main() {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	winWidth := 500
	winHeight := 200
	win := initWindow(winWidth, winHeight)
	win.MakeContextCurrent()
	log.Printf("glfw: created window %dx%d", winWidth, winHeight)
	ctx := InitNK(winWidth, winHeight, win)
	initFont(ctx)
	for !win.ShouldClose() {
		glfw.WaitEvents()
		nk.NkPlatformNewFrame()
		w, h := win.GetSize()
		bounds := nk.NkRect(0, 0, float32(w), float32(h))
		update := nk.NkBegin(ctx, "Demo", bounds, nk.WindowNoScrollbar)

		if update > 0 {
			nk.NkLayoutRowDynamic(ctx, 30, 2)
			nk.NkLabel(ctx, "Test:", nk.TextCentered)
			if nk.NkButtonLabel(ctx, "Click here") > 0 {
				out, err := exec.Command("ping", "ya.ru", "-n", "2").Output()
				log.Println(string(out), err)

			}
		}
		nk.NkEnd(ctx)
		glRender(win)
	}

}

func glRender(win *glfw.Window) {
	width, height := win.GetSize()
	gl.Viewport(0, 0, int32(width), int32(height))
	gl.Clear(gl.COLOR_BUFFER_BIT)
	nk.NkPlatformRender(nk.AntiAliasingOn, maxVertexBuffer, maxElementBuffer)
	win.SwapBuffers()
}
func initFont(ctx *nk.Context) {
	atlas := nk.NewFontAtlas()
	nk.NkFontStashBegin(&atlas)
	sansFont := nk.NkFontAtlasAddDefault(atlas, 30, nil)
	nk.NkFontStashEnd()
	if sansFont != nil {
		nk.NkStyleSetFont(ctx, sansFont.Handle())
	}
}
func InitNK(winWidth int, winHeight int, win *glfw.Window) *nk.Context {
	if err := gl.Init(); err != nil {
		log.Fatal(err)
	}
	gl.Viewport(0, 0, int32(winWidth), int32(winHeight))
	ctx := nk.NkPlatformInit(win, nk.PlatformInstallCallbacks)
	return ctx
}
func initWindow(winWidth int, winHeight int) *glfw.Window {
	if err := glfw.Init(); err != nil {
		log.Fatal(err)
	}
	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 2)
	glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
	win, err := glfw.CreateWindow(winWidth, winHeight, "DICOM CD Writer GUI", nil, nil)
	if err != nil {
		log.Fatal(err)
	}
	return win
}

Any suggestions?

I don't know the root cause but probably you can avoid it by using GOGC=off.

@oov not an option in long run.. but can be harmless to use for now :(

@Loafter sorry, got some work to do. I have to boot my Windows 10 machine, because I cannot reproduce the issue on OS X. Make sure you're on HEAD master. Because in the latest commit I disabled memory-related features that caused crashes on OS X.

I'm balancing between a crash and possible memory leaks, don't want to get those leaks back.

same problem
at this time i used
Windows 10 x64
go1.9.1 windows/amd64
gcc (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 7.2.0
May be problem with posix thread model in gcc?

Exception 0xc0000005 0x8 0xc04200a2ca 0xc04200a2ca
PC=0xc04200a2ca
signal arrived during external code execution

github.com/golang-ui/nuklear/nk._Cfunc_nk_convert(0x5c81d40, 0x5c86e50, 0x5ccca00, 0x5ccc800, 0x5cc7f20, 0xc000000000)
	github.com/golang-ui/nuklear/nk/_obj/_cgo_gotypes.go:3065 +0x54
github.com/golang-ui/nuklear/nk.NkConvert.func1(0x5c81d40, 0x5c86e50, 0x5ccca00, 0x5ccc800, 0x5cc7f20, 0x20000)
	C:/Users/alex/go/src/github.com/golang-ui/nuklear/nk/nk.go:155 +0x167
github.com/golang-ui/nuklear/nk.NkConvert(0x5c81d40, 0x5c86e50, 0x5ccca00, 0x5ccc800, 0xc042031dd8, 0xc042020000)
	C:/Users/alex/go/src/github.com/golang-ui/nuklear/nk/nk.go:155 +0x68
github.com/golang-ui/nuklear/nk.NkPlatformRender(0x1, 0x80000, 0x20000)
	C:/Users/alex/go/src/github.com/golang-ui/nuklear/nk/impl_glfw_gl3.go:99 +0x448
main.glRender(0xc042072000)
	C:/Users/alex/go/src/crashtest/main.go:53 +0x7b

I've found the root cause.

package main

import (
	"log"
	"os/exec"
	"runtime"

	"github.com/go-gl/gl/v3.2-core/gl"
	"github.com/go-gl/glfw/v3.2/glfw"
	"github.com/golang-ui/nuklear/nk"
)

const (
	maxVertexBuffer  = 512 * 1024
	maxElementBuffer = 128 * 1024
)

func main() {
	runtime.LockOSThread()
	defer runtime.UnlockOSThread()
	winWidth := 500
	winHeight := 200
	win := initWindow(winWidth, winHeight)
	win.MakeContextCurrent()
	log.Printf("glfw: created window %dx%d", winWidth, winHeight)
	ctx := InitNK(winWidth, winHeight, win)
	fontHandle := initFont(ctx)
	for !win.ShouldClose() {
		glfw.WaitEvents()
		nk.NkPlatformNewFrame()
		w, h := win.GetSize()
		bounds := nk.NkRect(0, 0, float32(w), float32(h))
		update := nk.NkBegin(ctx, "Demo", bounds, nk.WindowNoScrollbar)

		if update > 0 {
			nk.NkLayoutRowDynamic(ctx, 30, 2)
			nk.NkLabel(ctx, "Test:", nk.TextCentered)
			if nk.NkButtonLabel(ctx, "Click here") > 0 {
				out, err := exec.Command("ping", "ya.ru", "-n", "2").Output()
				log.Println(string(out), err)

			}
		}
		nk.NkEnd(ctx)
		glRender(win)
	}
	runtime.KeepAlive(fontHandle) // <-- We have to keep this.
}

func glRender(win *glfw.Window) {
	width, height := win.GetSize()
	gl.Viewport(0, 0, int32(width), int32(height))
	gl.Clear(gl.COLOR_BUFFER_BIT)
	nk.NkPlatformRender(nk.AntiAliasingOn, maxVertexBuffer, maxElementBuffer)
	win.SwapBuffers()
}
func initFont(ctx *nk.Context) *nk.UserFont {
	atlas := nk.NewFontAtlas()
	nk.NkFontStashBegin(&atlas)
	sansFont := nk.NkFontAtlasAddDefault(atlas, 30, nil)
	nk.NkFontStashEnd()
	if sansFont != nil {
		sansFontHandle := sansFont.Handle()
		nk.NkStyleSetFont(ctx, sansFontHandle)
		return sansFontHandle
	}
	return nil
}
func InitNK(winWidth int, winHeight int, win *glfw.Window) *nk.Context {
	if err := gl.Init(); err != nil {
		log.Fatal(err)
	}
	gl.Viewport(0, 0, int32(winWidth), int32(winHeight))
	ctx := nk.NkPlatformInit(win, nk.PlatformInstallCallbacks)
	return ctx
}
func initWindow(winWidth int, winHeight int) *glfw.Window {
	if err := glfw.Init(); err != nil {
		log.Fatal(err)
	}
	glfw.WindowHint(glfw.ContextVersionMajor, 3)
	glfw.WindowHint(glfw.ContextVersionMinor, 2)
	glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
	glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
	win, err := glfw.CreateWindow(winWidth, winHeight, "DICOM CD Writer GUI", nil, nil)
	if err != nil {
		log.Fatal(err)
	}
	return win
}

oov looks like you solve my problem!
Thanks a lot)

I am having the same crash but in a different scenario, maybe this will shed some light on the issue (also I am stuck).

Here I add the example GUI to my project: jakecoffman/tanklets@baf4e7e

When I run cmd/testlet, which starts the server and two clients, it crashes immediately or sometimes after I drag a window. Sometimes the other window crashes, not the one I am dragging in!

If I modify cmd/testlet to only launch one client then it doesn't crash... which seems to indicate there is some shared state between the two GUI processes somehow?!

Also I tried @oov's fix above but that didn't seem to help the crashing.

Any ideas? Happens on Windows 10 and OSX.

My mistake, @oov's fix does fix it for me too!

So the fix is to add:

runtime.KeepAlive(fontHandle) // <-- We have to keep this.

Do you know why this is required?

Because C references to Go's *nk.UserFont pointer that passed at nk.NkStyleSetFont.
So it is necessary to prevent it being collected by GC.