Cross platform C signals

It's always a good idea to handle Ctrl-C events with a custom function to perform any necessary cleanup, this shows handling Ctrl-C events in Win32 and POSIX console

Linux programmers are quite familiar with the sys/signal.h way of handling Ctrl-C events, such as this snippet:

#include <sys/signal.h>
...
static volatile sig_atomic_t exiting = 0;
/* Signal handler for exit signals */
static void
sigexit(int signo)
{exiting = 1;}
/* Register signal handler */
static void sig_register(void){
    struct sigaction sigact;
    sigact.sa_handler = sigexit;
    sigemptyset(&sigact.sa_mask);
    sigact.sa_flags = 0;
    sigaction(SIGINT, &sigact, NULL);
    sigaction(SIGTERM, &sigact, NULL);
}

Which creates a simple handler for SIGINT and SIGTERM that sets the value of the global variable 'exiting' to 1 on Ctrl-C events.

While Win32 doesn't support signal handling the POSIX way, you can make it cross platform with the corresponding Win32 version using the function SetConsoleCtrlHandler:

#include <windows.h>
...
static int exiting=0;
/* Signal handler for exit signals */
BOOL CtrlHandler( DWORD fdwCtrlType ){
    switch( fdwCtrlType ){
    case CTRL_C_EVENT:
        exiting=1;
        return( TRUE );
    // CTRL-CLOSE: confirm that the user wants to exit.
    case CTRL_CLOSE_EVENT:
        exiting=1;
        return( TRUE );
    // Pass other signals to the next handler.
    case CTRL_BREAK_EVENT:
        return FALSE;
    case CTRL_LOGOFF_EVENT:
        return FALSE;
    case CTRL_SHUTDOWN_EVENT:
        return FALSE;
    default:
        return FALSE;
    }
}
/* Register signal handler */
static void sig_register(void){
    if( !SetConsoleCtrlHandler( (PHANDLER_ROUTINE) CtrlHandler, TRUE ) )
        printf("Unable to register Control Handler.\n");
}

Note that by returning true, you're telling the windows that you've handled the event, and the default handler (usually 'exit') will not be called.

References

  1. Sigaction on opengroup
  2. SetConsoleCtrlHandler on MSDN