英文:
Go causes OpenGL to segfault with time.Tick but not time.After
问题
我有以下两个文件:
bridge.go:
package cube
// #cgo LDFLAGS: -lGL -lGLEW -lglfw
// #include <GLFW/glfw3.h>
// int init(GLFWwindow**);
// void render(GLFWwindow*);
import "C"
import (
"fmt"
"time"
)
func Init() {
var window *_Ctype_GLFWwindow
windowWat := (*[0]byte)(window)
fmt.Printf("Calling init\n")
if C.init(&windowWat) != 1 {
return
}
window = (*_Ctype_GLFWwindow)(windowWat)
//t := time.Tick(time.Second) // Doesn't work
t := time.After(time.Second) // Works
<-t
fmt.Println("Rendering")
C.render((*[0]byte)(window))
select {}
}
cube.c:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define INIT_WINDOW_W (800)
#define INIT_WINDOW_H (800)
void render(GLFWwindow* window) {
glClearColor(135.0f / 255.0f, 206.0f / 255.0f, 250.f / 254.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwSwapBuffers(window);
}
static void glfw_error(int errno, const char* description) {
fprintf(stderr, "GLFW [%d] %s\n", errno, description);
exit(1);
}
int init(GLFWwindow** window) {
GLenum glewErr;
glfwSetErrorCallback(glfw_error);
if (!glfwInit()) {
return 0;
}
*window = glfwCreateWindow(
INIT_WINDOW_H,
INIT_WINDOW_W,
"wat",
NULL,
NULL
);
if (*window == NULL) {
glfwTerminate();
return 0;
}
glfwMakeContextCurrent(*window);
glewErr = glewInit();
if (glewErr != GLEW_OK) {
fprintf(stderr, "glewInit failed: %s\n", glewGetErrorString(glewErr));
return 0;
}
if (!GL_VERSION_2_0) {
fprintf(stderr, "Don't have OpenGL >= 2.0\n");
return 0;
}
return 1;
}
还有一个调用cube.Init()
而不做其他操作的main.go文件。
我的问题出现在调用C.render
之前的几行代码。如果我使用time.After
,它可以正常工作,并显示一个蓝色的窗口。如果我使用time.Tick
,它有时会显示一个黑色的窗口,有时会导致段错误。这个测试案例是从我的实际代码中大大简化而来的。
我有一种感觉是Go的调度器在某种程度上搞乱了事情,但我无法想出具体原因(或如何测试/修复)。我想知道是否有人有任何关于这个问题的想法,或者能否想出任何进一步调查的方法。
其他可能相关的信息:
- Arch Linux,3.14.4-1-ARCH.x86_64
- GLFW 3.0.4-1
- GLEW 1.10.0-2
- nVidia GeForce GTX 570M
- nVidia驱动程序337.12-1
- go1.2 linux/amd64
编辑:
这是段错误的消息:
SIGSEGV: segmentation violation
PC=0x7fda7d6a2e29
signal arrived during cgo execution
runtime.cgocall(0x401260, 0x7fda7d6f0e58)
/opt/go/src/pkg/runtime/cgocall.c:149 +0x11b fp=0x7fda7d6f0e40
game/cube._Cfunc_render(0x24e13b0)
game/cube/_obj/_cgo_defun.c:62 +0x31 fp=0x7fda7d6f0e58
game/cube.Init()
/tmp/wat/cube/bridge.go:28 +0x156 fp=0x7fda7d6f0ee0
main.main()
/tmp/wat/main.go:10 +0xac fp=0x7fda7d6f0f48
runtime.main()
/opt/go/src/pkg/runtime/proc.c:220 +0x11f fp=0x7fda7d6f0fa0
runtime.goexit()
/opt/go/src/pkg/runtime/proc.c:1394 fp=0x7fda7d6f0fa8
goroutine 3 [syscall]:
runtime.goexit()
/opt/go/src/pkg/runtime/proc.c:1394
rax 0x0
rbx 0x24e13b0
rcx 0x7fda7d6f0e58
rdx 0x7fda7d6f0df0
rdi 0x24e13b0
rsi 0xc210001900
rbp 0xc21002a000
rsp 0x7fda76506dc8
r8 0xc210001120
r9 0x7fda7d6f0df0
r10 0x7fda76506ba0
r11 0x7fda7d6a2e20
r12 0x0
r13 0x7fda76507700
r14 0x0
r15 0x7fda76d07c80
rip 0x7fda7d6a2e29
rflags 0x10202
cs 0x33
fs 0x0
gs 0x0
exit status 2
看起来它在调用glClearColor
时导致了段错误。
英文:
I have the following two files:
bridge.go:
package cube
// #cgo LDFLAGS: -lGL -lGLEW -lglfw
// #include <GLFW/glfw3.h>
// int init(GLFWwindow**);
// void render(GLFWwindow*);
import "C"
import (
"fmt"
"time"
)
func Init() {
var window *_Ctype_GLFWwindow
windowWat := (*[0]byte)(window)
fmt.Printf("Calling init\n")
if C.init(&windowWat) != 1 {
return
}
window = (*_Ctype_GLFWwindow)(windowWat)
//t := time.Tick(time.Second) // Doesn't work
t := time.After(time.Second) // Works
<-t
fmt.Println("Rendering")
C.render((*[0]byte)(window))
select {}
}
cube.c:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define INIT_WINDOW_W (800)
#define INIT_WINDOW_H (800)
void render(GLFWwindow* window) {
glClearColor(135.0f / 255.0f, 206.0f / 255.0f, 250.f / 254.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glfwSwapBuffers(window);
}
static void glfw_error(int errno, const char* description) {
fprintf(stderr, "GLFW [%d] %s\n", errno, description);
exit(1);
}
int init(GLFWwindow** window) {
GLenum glewErr;
glfwSetErrorCallback(glfw_error);
if (!glfwInit()) {
return 0;
}
*window = glfwCreateWindow(
INIT_WINDOW_H,
INIT_WINDOW_W,
"wat",
NULL,
NULL
);
if (*window == NULL) {
glfwTerminate();
return 0;
}
glfwMakeContextCurrent(*window);
glewErr = glewInit();
if (glewErr != GLEW_OK) {
fprintf(stderr, "glewInit failed: %s\n", glewGetErrorString(glewErr));
return 0;
}
if (!GL_VERSION_2_0) {
fprintf(stderr, "Don't have OpenGL >= 2.0\n");
return 0;
}
return 1;
}
As well as a main.go file which calls cube.Init()
and nothing else.
My issue lies in the lines just before calling C.render
. If I do a time.After
, it works fine and displays a blue window as it's supposed to. If I do a time.Tick
, it will rarely also display that blue window, but either display a black window or segfault. This test case is significantly boiled down from my actual code.
I have a feeling that go's scheduler is messing things up somehow, but I can't think how (or how to test/fix that). I'm curious if anyone has any ideas what's causing this, or can think of any ways to investigate further.
Other possibly significant information:
- Arch linux, 3.14.4-1-ARCH.x86_64
- GLFW 3.0.4-1
- GLEW 1.10.0-2
- nVidia GeForce GTX 570M
- nVidia driver 337.12-1
- go1.2 linux/amd64
EDIT:
Here's the segfault message:
SIGSEGV: segmentation violation
PC=0x7fda7d6a2e29
signal arrived during cgo execution
runtime.cgocall(0x401260, 0x7fda7d6f0e58)
/opt/go/src/pkg/runtime/cgocall.c:149 +0x11b fp=0x7fda7d6f0e40
game/cube._Cfunc_render(0x24e13b0)
game/cube/_obj/_cgo_defun.c:62 +0x31 fp=0x7fda7d6f0e58
game/cube.Init()
/tmp/wat/cube/bridge.go:28 +0x156 fp=0x7fda7d6f0ee0
main.main()
/tmp/wat/main.go:10 +0xac fp=0x7fda7d6f0f48
runtime.main()
/opt/go/src/pkg/runtime/proc.c:220 +0x11f fp=0x7fda7d6f0fa0
runtime.goexit()
/opt/go/src/pkg/runtime/proc.c:1394 fp=0x7fda7d6f0fa8
goroutine 3 [syscall]:
runtime.goexit()
/opt/go/src/pkg/runtime/proc.c:1394
rax 0x0
rbx 0x24e13b0
rcx 0x7fda7d6f0e58
rdx 0x7fda7d6f0df0
rdi 0x24e13b0
rsi 0xc210001900
rbp 0xc21002a000
rsp 0x7fda76506dc8
r8 0xc210001120
r9 0x7fda7d6f0df0
r10 0x7fda76506ba0
r11 0x7fda7d6a2e20
r12 0x0
r13 0x7fda76507700
r14 0x0
r15 0x7fda76d07c80
rip 0x7fda7d6a2e29
rflags 0x10202
cs 0x33
fs 0x0
gs 0x0
exit status 2
And it appears to segfault at the call to glClearColor
答案1
得分: 2
将我的评论转化为答案:
由于某种原因,OpenGL通常要求所有内容在同一个操作系统线程中运行。time.Tick和time.After调用不同的运行时函数,其中一个可能导致不同的OpenGL调用在不同的线程中运行。默认情况下,Go语言不能保证goroutine在特定线程上运行。
要解决这个问题,你需要使用runtime.LockOSThread。这将确保只有该goroutine在当前线程上运行。
你可以在这里阅读更多相关主题的内容:https://groups.google.com/forum/#!topic/golang-nuts/5Pvv1Gr1eoo
英文:
Turning my comment into an answer:
For some reason OpenGL often requires everything run in the same OS thread. time.Tick and time.After call different runtime functions and one may be causing different opengl calls to run in separate threads. By default, Go makes does not guarantee a goroutine runs on a specific thread.
To fix this, you need to use runtime.LockOSThread. This will ensure that goroutine and only that goroutine ever run on the current thread.
You can read more on the topic here: https://groups.google.com/forum/#!topic/golang-nuts/5Pvv1Gr1eoo
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论