Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

The signal() function behaves differently in Windows than it does on Linux/BSD systems. When a signal handler is installed with the signal() function in Windows, the default action is restored for that signal after the signal is triggered. Conversely, Linux/BSD systems leave the signal handler defined by the user in place until it is explicitly removed.

Different actions must be taken depending on whether or not you desire signal handlers to be persistent.

Persistent handlers

By default, *nix systems leave the handler in place after a signal is generated.

Non-Compliant Code Example (Windows)

This non-complaint code example fails to persist the signal handler on Windows platforms.

Code Block
bgColor#FFCCCC
#include <stdio.h>
#include <signal.h>

volatile sig_atomic_t e_flag = 0;

void handler(int signum) {
  e_flag = 1;
}

int main(void) {
  signal(SIGINT, handler);
  while(!e_flag) {}
  puts("Escaped from first while()");
  e_flag = 0;
  while(!e_flag) {}
  puts("Escaped from second while()");
  return 0;
}

When *nix systems automatically reinstall signal handlers upon handler execution. For example, when compiled with gcc 3.4.4 and executed under Red Hat Linux, the signal handler is automatically reinstalled upon handler execution SIGINT is captured both times by handler.

Code Block
% ./SIG01-A
^C
Escaped from first while()
^C
Escaped from second while()
%

However, under Windows systems signal handlers are not automatically reinstalled. For example, when compiled with Microsoft Visual Studio 2005 version 8.0 and executed under Windows the signal handler is not automatically reinstalled, only the first SIGINT is captured by handler.

Code Block
> SIG01-A.exe
^C
Escaped from first while()
^C
>

The second interrupt SIGINT executes the default action for SIGINT, which is to terminate program execution.

Different actions must be taken depending on whether or not you desire signal handlers to be persistent.

Persistent handlers

By default, *nix systems leave the handler in place after a signal is generated.

Non-Compliant Code Example (Windows)

This non-complaint code example fails to persist the signal handler on Windows platforms.

Code Block
bgColor#ffcccc

void handler(int signum) {
  /* handling code */
}

Compliant Solution (Windows)

...

Code Block
bgColor#ccccff
void handler(int signum) {
#ifdef WINDOWS
  signal(signum, handler);
#endif
  /* rest of handling code */
}

...

This non-complaint code example fails to reset the signal handler to its default actionbehavior on *nix systems.

Code Block
bgColor#FFCCCC#ffcccc


#include <stdio.h>
#include <signal.h>

volatile sig_atomic_t e_flag = 0;

void handler(int signum) {
  e_flag = 1;
}

int main(void) {
  signal(SIGINT, handler);
  while(!e_flag) {}
  puts("Escaped from first while()");
  e_flag = 0;
  while(!e_flag) {}
  puts("Escaped from second while()");
  return 0;/* handling code */
}

Compliant Solution (*nix)

The compliant solution explicitly resets the signal handler to its A C99-compliant solution to reset the handler on a *nix system is to rebind the signal to the implementation-defined default behaviorhandler in the first line of the handler itself.

Code Block
bgColor#ccccff

#include <stdio.h>
#include <signal.h>

volatile sig_atomic_t e_flag = 0;

void handler(int signum) {
#ifdef  signal(signum, SIG_DFL);
  e_flag = 1;
}

int main(void) {WINDOWS
  /* windows automatically resets handlers to default */
#else
  signal(SIGINTsignum, handler);
  while(!e_flag) {}
  puts("Escaped from first while()");
  e_flag = 0;
  while(!e_flag) {}
  puts("Escaped from second while()");
  return 0;SIG_DFL);
#endif
  /* rest of handling code */
}

Risk Analysis

Failure to re-establish a persistent signal handler on Windows platforms can lead to unexpected behavior.

...