无法再使用我的SDL应用程序了

时间:2013-11-18 13:29:25

标签: c linux opengl signals sdl

昨天我可以,今天我终于无法在终端中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%的时间工作,只有几次失败。

4 个答案:

答案 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功能是否会受到影响,因为我不使用它们。使用另一种计时方法获得更高的准确度可能不会有什么坏处。