Using Signals

From oldwiki.scinet.utoronto.ca
Jump to navigation Jump to search

General

In unix/linux one can send signals to a program or a script. Some common signals are:

HUP Terminal log-out
INT Interrupt signal (Ctrl-C is pressed)
TERM Termination of the process (as if 'kill' was called)
KILL Kill of the process (as if 'kill -9' was called)
STOP Stop the process
USR1 Unspecified user signal (can be given with 'kill -USR1')
USR2 Unspecified user signal (can be given with 'kill -USR2')

Signals can be given using the 'kill' command, but can also be given by the system. One important instance of this is that on SciNet, a TERM signal is sent to a jobs whose requested time is over, after which the job has about 30 seconds to clean up.

As explained below, a program or script can be set up to listen for a particular kind of signal (except for KILL and STOP, which cannot be blocked). When it receive a signal of that kind, its execution is interrupted and a call is made to a function, specified earlier in the program. It is up to the program or script what this signal handling function does but it is a good idea to make the action appropriate for the event that triggers the signal. For instance, a TERM signal should be handled as a request to terminate the application. The user signals USR1 and USR2 do not have a pre-designated meaning and can be used for application-specific actions such as checkpointing.


Trapping signals in bash scripts

To trap signals in a bash script, one has to bind a specific signal to a command or function with the trap command. For example, <source lang="bash">

  1. !/bin/bash

trap "echo Term was trapped.; exit" TERM for ((i=0;i<60;i++)) do

 echo $i
 sleep 1

done </source> Running this script in the background and sending it a TERM command ('kill -TERM [pid]') will cause the message 'Term was trapped.' to be printed. Notes:

  • The trapped command has to use 'exit' explicitly to stop the script's execution.
  • The 'sleep' command in bash cannot be interrupted, which is why the script contains a succession of 1 second 'sleep's.

Another useful example is given on the wiki page about using ramdisk.


Trapping signals in C

To trap signals in a c program, one has to include the signal.h header file: <source lang="c">

  1. include <signal.h>

</source> and provide a signal handler function <source lang="c"> void term_trap(int sig) {

  /* do something */

} </source> which is linked to the specific signal somewhere as follows: <source lang="c"> signal(SIGTERM, term_trap); </source> Note that the names of signals are prepended with "SIG" in signal.h.

A minimal example: <source lang="c">

  1. include <stdio.h>
  2. include <signal.h>

void term_trap(int sig) {

   printf("Term was trapped.\n");

}

int main() {

   signal(SIGTERM, term_trap);
   sleep(60);

} </source> Note that the names of the signals are prepended with SIG in C. To test this program:

  • save the above code as sigex.c
  • compile: icc -O3 -xHost sigex.c -o sigex
  • run: sigex&
  • note the pid (process idenitfier)
  • you can then give the process the term signal with kill -TERM [pid].


Trapping signals in C++

The same method as for a C program works in C++, except the header file is 'csignal'. For example: <source lang="c">

  1. include <iostream>
  2. include <csignal>

void term_trap(int sig) {

   std::cout << "Term was trapped.\n";

}

int main() {

   signal(SIGTERM, term_trap);
   sleep(60);

} </source>


Trapping signals in Fortran

The following works at least with gfortran. <source lang="f77"> PROGRAM SIGEX

     INTRINSIC SIGNAL
     EXTERNAL TRAP_TERM
     CALL SIGNAL (15, TRAP_TERM)
     CALL SLEEP (60)

END SUBROUTINE TRAP_TERM

     PRINT *, "Term was trapped."

END </source>

More to come.