昨天我可以和今天我不能在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-c
, ctrl-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_NOPARACHUTE
给SDL_Init()
。
这是一个解决方法,而不是一个答案…
不要将SDL_INIT_TIMER
传递给SDL_Init
。 没有它, SDL_GetTicks
仍然可以正常工作(或者至少在其他平台上似乎仍然需要它)。 我不知道其他计时器子系统功能是否受到影响,因为我不使用它们。 使用另一种计时方法也可能不会伤害到更高的精度。