Un manual muy básico de cómo manejar señales en GNU/Linux

Introducción

GNU/Linux soporta las llamadas Señales fiables POSIX y las Señales en Tiempo Real POSIX. No voy a listar todas éstas señales, ya que se encuentran en signal.h y se pueden consultar en cualquier manual de GNU/Linux Para explicar el proceso de escribir un manejador de señales (en C), usaré un ejemplo muy sencillo y lo iré explicando después.

El código de ejemplo

Bueno, éste es el código que utilizaré como ejemplo. Guardadlo en un archivo con el nombre que querais y lo compilais con gcc (como toda la vida :D)
#include <stdio.h>
#include <signal.h>
#include <string.h>

void timerHandler();

int main () {
  struct sigaction sigTimerAction;

  memset (&sigTimerAction, 0, sizeof(sigTimerAction));

  sigTimerAction.sa_handler = timerHandler;
  sigTimerAction.sa_restorer = NULL;

  sigaction (SIGALRM, &sigTimerAction, NULL);

  alarm((unsigned int)1);

  while(1);
}

void timerHandler() {
  static int c;

  printf ("Contador %i\n", c++);
  alarm ((unsigned int)1);
}

Funcionamiento

Bueno, el código está formado por dos funciones, una es el main de toda la vida. La otra, timerHandler es el manejador de señales, que se ejecutara, en este caso, cada vez que se lance una señal SIGALRM. La función del manejador no tiene mucho misterio. Tan solo se trata de una línea que imprime el valor de un contador y una función que restaura el temporizador para que se lance una señal un segundo después de ejecutarse (Bueno, no es un segundo exacto, recordad que estamos en un entorno multiprogramado ;)). La función main empieza con una instancia de una estructura tipo sigaction. Es en ésta estructura donde se guarda la información de qué manejador se asocia a qué señal. La implementación de sigaction es la siguiente:
struct sigaction {
    void (*sa_handler)(int);
    void (*sa_sigaction)(int, siginfo_t *, void *);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_restorer)(void);
}
y la utilidad de los campos de dicha estructura es la que sigue a continuación:
  • sa_restorer: Está obsoleto y no debería utilizarse. POSIX no especifica ningún elemento sa_restorer.
  • sa_handler: Especifica la acción asociada a la señal signum. Ésta acción puede ser:
    • SIG_DFL para la acción por defecto,
    • SIG_IGN para ignorar la señal o
    • un puntero a una función que actue como manejador de dicha señal.
  • sa_mask: Proporciona una máscara de señales que deben ser bloqueadas durante la ejecución del manejador de señal. Además, la señal que activó el manejador actual también será bloqueada a menos que se utilicen los flags SA_NODEFER o SA_NOMASK.
  • sa_flags: Especifica un conjunto de flags que pueden variar el comportamiento del manejador de señal.
  • signum: Especifica la señal a capturar y puede ser cualquier señal válida excepto SIGKILL y SIGSTOP.
Bueno, podemos ver que después de limpiar (o iniciliazar para los mas puristas) la estructura, asignamos el manejador que queremos que sea ejecutado en el campo sa_handler. sa_restorer es mejor inicializarlo a NULL para evitar problemas. A continuación, se llama la función sigaction (¿de qué me sonará el nombre? ;)). El prototipo de ésta función, es el que sigue:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
Los argumentos son estos:
  • int signum: Se utiliza para especificar la señal que desea capturarse.
  • const struct sigaction *act: Especifica la estructura sigaction en la que se encuentra la información sobre el manejador a asociar a la señal capturada.
  • struct sigaction *oldact: Una estructura en la que se almacenará la información del antiguo manejador instalado para esa señal. Se puede dejar a NULL si se desea.
La función sigaction retorna 0 si todo ha ido bien y -1 si ha habido algún error. En nuestro caso, utilizamos ésta función para asociar timerHandler con la señal SIGALRM. Una vez hecho esto, ya solo queda llamar a la función alarm para que se lance una señal SIGALRM en un segundo y generar un bucle infinito para que el programa no finalice nunca ;).

Referencias



blog comments powered by Disqus