昨天我可以,今天我终于无法在终端中ctrl-c
杀死我的SDL应用。在调用SDL_Init
之前,一切都按预期工作。之后,ctrl-c
什么也没做。调用signal(SIGINT, SIG_DFL)
不会改变这一点。我没有更新任何我能想到的东西,除了Nvidia的司机。这种情况发生在我几个月前编写的应用程序中。
有没有办法调试正在发生的事情?
[编辑]
即使这种情况在SDL_Init
之后仍然有效(尽管通常在gdb
内表现):
signal(SIGINT, exit);
raise(SIGINT);
SDL1.2.15和SDL2也是如此(但过剩是好的)。我正在运行Fedora 18(x64),gcc 4.7.2,带有gtx titan的nvidia驱动程序331.2。
当我点击窗口上的关闭按钮时出现 SDL_QUIT
,但从来没有ctrl-c
(afaik它从未用过 - SIGINT只会杀死应用程序)。
[EDIT2]
这不是一贯可重复的,但是很常见。有时事先运行其他程序(例如echo
)会增加ctrl-c
工作的机会。如果它不起作用,重复从不起作用。
经过一些进一步测试后,ctrl-c
似乎只有在SDL_INIT_TIMER
传递给SDL_Init
时才会停止工作。 计时器子系统与信号有什么关系?
[EDIT3]
这是我的测试用例...
#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
有90%的时间工作,只有几次失败。
答案 0 :(得分:2)
查看SDL源后,似乎将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
事件推送到事件队列(并重置信号处理程序)之外什么都不做,因此如果您不需要处理quit事件,只需将其反转即可。
默认情况下,ctrl+c
应将SDL_QUIT
推送到事件队列中。在我的计算机上,只要创建一个窗口,它就会以这种方式工作。尝试打印所有轮询事件的类型,并查看ctrl+c
是否发送任何事件。另外,如果您使用SDL 1
,请考虑使用SDL 2
。
答案 1 :(得分:2)
我在几天内遇到过类似的问题......经过长时间的痛苦调查后,我在NVIDIA OpenGL驱动程序中找到了this bug report。
问题是NVIDIA OpenGL库的初始化代码会破坏进程的sigprocmask。这可能发生在链接到该库的任何进程中。在我的情况下,会话管理器受到影响,因此我的会话中的每个进程都继承了它。
您可以使用以下命令检查是否是您的情况:
$ grep SigBlk /proc/<pid>/status
正常输出应为:
SigBlk: 0000000000010000
如果你得到一个看起来像内存地址的大数字,你就会有错误。
降级至325.15-11将解决您的问题。
答案 2 :(得分:1)
SDL默认处理通常的信号,不知道为什么之前没有。
要避免它并恢复标准信号处理,请将标记SDL_INIT_NOPARACHUTE
传递给SDL_Init()
。
答案 3 :(得分:0)
这是一种解决方法,而非答案......
不要将SDL_INIT_TIMER
传递给SDL_Init
。如果没有它,SDL_GetTicks
仍然可以正常工作(或者至少看起来,或许在其他平台上仍然需要它)。我不知道其他timer subsystem功能是否会受到影响,因为我不使用它们。使用另一种计时方法获得更高的准确度可能不会有什么坏处。