无法再按Ctrl-c我的SDL应用程序

昨天我可以和今天我不能在terminalctrl-c杀死我的SDL应用程序。 在SDL_Init之前,一切都按预期工作。 之后, ctrl-c什么都不做。 调用signal(SIGINT, SIG_DFL)不会改变这个。 除了Nvidia的驱动程序,我还没有更新任何我能想到的。 这也发生在几个月前我编写的应用程序上。

有什么方法可以debugging发生了什么?

[编辑]
即使这个在SDL_Init之后停止工作(虽然在gdb正常运行):

 signal(SIGINT, exit); raise(SIGINT); 

SDL1.2.15和SDL2都会发生同样的情况(尽pipe如此,还是可以的)。 我正在运行Fedora 18(x64),gcc 4.7.2,nvidia驱动331.2与gtx巨人。

当我点击窗口上的closuresbutton时,就会出现SDL_QUIT ,但是从来没有使用ctrl-c (afaik它从来没有用过 – SIGINT只会简单地杀死应用程序)。

[EDIT2]
这不是始终可重现的,但是非常普遍。 有时预先运行其他程序(如echo会增加ctrl-c的工作机会。 如果不起作用,重复将无法工作。

经过一些进一步的testing,似乎只有当SDL_INIT_TIMER传递给SDL_Init时, ctrl-c才会停止工作。 计时器子系统可以怎样处理信号

[EDIT3]
这是我的testing案例…

 #include <stdio.h> #include <unistd.h> #include <signal.h> #include <SDL2/SDL.h> int main() { SDL_Window* window = NULL; SDL_GLContext context; fprintf(stderr, "Start"); usleep(3000000); fprintf(stderr, ".\n"); //raise(SIGINT); //always works struct sigaction old; sigaction(SIGTERM, NULL, &old); fprintf(stderr, "Init"); SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE); //SDL_Init(SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE); //no problems fprintf(stderr, ".\n"); usleep(3000000); sigaction(SIGINT, &old, NULL); //signal(SIGINT, SIG_DFL); //raise(SIGINT); //fails with SDL_INIT_TIMER (commonly, but not always) fprintf(stderr, "Window"); window = SDL_CreateWindow("sdlwin", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 512, 512, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE); fprintf(stderr, ".\n"); usleep(3000000); fprintf(stderr, "Context"); context = SDL_GL_CreateContext(window); fprintf(stderr, ".\n"); usleep(3000000); fprintf(stderr, "Loop...\n"); while (1) { usleep(1000000); printf(".\n"); } return 0; } 

在某些情况下,第一个ctrl-c只是工作。 有时第一个结束当前的usleep ,并需要一秒杀死应用程序。 其他时候, ctrl-c从来没有工作。 随机性让我认为有什么地方没有初始化。 令人讨厌的是,我刚刚跑了ctrl-cctrl-c在90%的时间里只工作了几次。

我几天来一直有类似的问题…经过漫长而痛苦的调查,我在NVIDIA OpenGL驱动程序中找到了这个错误报告 。

问题在于NVIDIA OpenGL库的初始化代码破坏了进程的sigprocmask。 这可能发生在任何链接到该库的进程上。 在我的情况下,会话管理器受到影响,所以会话中的每个进程都继承了它。

您可以使用以下命令检查是否属于您的情况:

 $ grep SigBlk /proc/<pid>/status 

正常的输出应该是:

 SigBlk: 0000000000010000 

如果你得到一个看起来像内存地址的大数字,那么你就有这个bug。

降级到325.15-11将解决您的问题。

通过SDL源查看之后,似乎将SDL_INIT_EVENTS传递SDL_INIT_EVENTS SDL_Init将使SDL使用其自己的信号处理功能。 在SDL_quit.c我们有:

 /* Both SIGINT and SIGTERM are translated into quit interrupts */ (and the code that does that) 

你可以简单地用这个来反转

 #include <signal.h> ... struct sigaction action; sigaction(SIGINT, NULL, &action); SDL_Init(SDL_INIT_EVERYTHING); sigaction(SIGINT, &action, NULL); .... 

SDL信号处理程序只是将SDL_QUIT事件推送到事件队列中(并重置信号处理程序),所以如果不需要处理退出事件,则简单地反转它应该没问题。

默认情况下, ctrl+c应该将SDL_QUIT推送到事件队列中。 在我的电脑上,只要窗口被创建,它就会以这种方式工作。 尝试打印所有轮询事件的类型,并查看ctrl+c发送任何事件。 另外,如果您使用的是SDL 1 ,请考虑使用SDL 2

SDL默认处理通常的信号,不知道为什么它没有。

为了避免它并恢复到标准信号处理,将标志SDL_INIT_NOPARACHUTESDL_Init()

这是一个解决方法,而不是一个答案…

不要将SDL_INIT_TIMER传递给SDL_Init 。 没有它, SDL_GetTicks仍然可以正常工作(或者至少在其他平台上似乎仍然需要它)。 我不知道其他计时器子系统功能是否受到影响,因为我不使用它们。 使用另一种计时方法也可能不会伤害到更高的精度。