Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't ctrl-c my SDL apps anymore

Yesterday I could and today I can't ctrl-c in the terminal to kill my SDL apps. Before SDL_Init is called, everything works as expected. After, ctrl-c does nothing. Calling signal(SIGINT, SIG_DFL) doesn't change this. I haven't updated anything I can think of except for Nvidia drivers. This happens with apps I've compiled months ago too.

Is there any way to debug what's happening?

[EDIT]
Even this ceases to work after SDL_Init (although behaves normally within gdb):

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

The same happens with both SDL1.2.15 and SDL2 (glut is ok though). I'm running Fedora 18 (x64), gcc 4.7.2, nvidia drivers 331.2 with a gtx titan.

SDL_QUIT occurs when I hit the close button on the window, but never ctrl-c (afaik it never used to either - SIGINT would simply kill the app).

[EDIT2]
This isn't consistently reproducible but is very common. Sometimes running other programs beforehand such as echo gives an increased chance for ctrl-c to work. If it doesn't work, repeats never works.

After some further testing it seems ctrl-c stops working only when SDL_INIT_TIMER is passed to SDL_Init. What could the timer subsystem have to do with signals??

[EDIT3]
Here's my test case...

#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;
}

In some cases the first ctrl-c just works. Sometimes the first ends the current usleep and it takes a second to kill the app. Other times, ctrl-c never works. The randomness makes me assume there's something uninitialized somewhere. Annoyingly I've just had a run where ctrl-c worked 90% of the time with only a couple of fails.

like image 403
jozxyqk Avatar asked Nov 18 '13 13:11

jozxyqk


2 Answers

After looking through the SDL source, it seems that passing SDL_INIT_EVENTS it SDL_Init will cause SDL to use its own signal handling function. In SDL_quit.c we have:

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

You can simply reverse this with

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

The SDL signal handler does nothing but push an SDL_QUIT event onto the event queue (and reset the signal handler), so simply reversing it should be okay if you don't need to handle the quit event.

By default, ctrl+c should push SDL_QUIT onto the event queue. On my computer it works this way as long as a window is created. Try printing the types of all polled events, and see if ctrl+c sends any event at all. Also, if you are using SDL 1, consider using SDL 2.

like image 134
Gavin Haynes Avatar answered Sep 30 '22 05:09

Gavin Haynes


I've been having similar issues for a few days... and after a long and painful investigation I reached to this bug report in the NVIDIA OpenGL drivers.

The problem is that the initialization code of the NVIDIA OpenGL librariy corrupts the sigprocmask of the process. This may happen to any process that links to that library. In my case the session manager was affected, so every single process in my session inherited it.

You can check if that is your case with the following command:

$ grep SigBlk /proc/<pid>/status

The normal output should be:

SigBlk: 0000000000010000

If you instead get a big number that looks like a memory address, you have the bug.

Downgrading to 325.15-11 will solve your problems.

like image 43
rodrigo Avatar answered Sep 30 '22 04:09

rodrigo