Signals by xiangpeng


   - is a notification sent to a process to notify it of some event
   - interrupts whatever the process is doing and force it to handle a signal
   - has an integer number that represents it, and symbolic name
signal SIGALRM (numeral value is 14), caused (also) by alarm clock.
Tip: you can get a list with all available signals using $kill –l shell command
(they will appear without the prefix SIG).

What can a process do with the signal he got?
  1. catch it
  2. let the default action of signal apply
  3. ignore it
1. In order to catch a signal, we should build a special function that will be
executed when a signal arrives. Such a function is called a signal handler.
void catch_alarm (int sig_num) {
      printf ( “Operation time out. Exiting. \n”);
      exit (0);
Signal handler should be of type void (*)(int) .
This argument is the signal number that the handler catches.
This property allows to use the same function to handle several signals.

void catch_alarm_&_setitimer (int sig_num) {
     if (sig_num == SIGALRM)
           printf (“got a signal SIGALRM”);
     if (sig_num == SIGVTALRM)
           printf (“got a signal virtual time setitimer signal”);
How would the operating system know that there is a specific signal handler
handles a specific signal? We should connect them, using signal ( ) C library
  signal (SIGALRM, catch_alarm_&_setitimer);
  signal (SIGVTALRM, catch_alarm_&_setitimer);
- a process can order some signals using C functions; for example,
SIGALRM signal can be ordered by using alarm (int x); function. That
means that after x seconds a process will get SIGALRM signal.
- most but not all signals can be caught. For example, SIGKILL (terminate a
process) and SIGSTOP (suspends a process) signals can‟t be caught.
2. In order to let the default action of signal apply process has do nothing.
Each signal has a default action (figure 10.1 in Stevens).
3. In order to ignore a signal, we should use signal ( ) C function:
signal (SIGALRM, SIG_IGN);

Note: that not all the signals can be ignored. For example, SIGKILL (terminate
a process) and SIGSTOP (suspends a process) signals can‟t be ignored.
- if you want to disconnect a signal handler from some special signal, use signal( ):
signal (SIGALRM, SIG_DFL);
- some o.s. automatically reset signal action to be the default action after the first signal
is caught. In this case, if you want your signal handler to continue to catch this signal,
you should re-connect them (in the same way you connected them).
- it can happen that different C functions provides the same signals (like alarm and
setitimer). You must be careful when order signals.
- return value from signal( ) in case of error:
    0 or previous address of the signal handler - on success
    SIG_ERR - in a case of error
My first program with signals (in C language):
signal1.c => when run it, get this output.
My second program with signals:
signal2.c => when run it, get this output.

What should process do in order to send a signal?
It should use kill (…) system call.
pid_t my_pid = getpid();
// sends itself the STOP signal
kill(my_pid, SIGSTOP);
pid_t pid = fork();
// sends KILL signal to its child
kill(pid, SIGKILL);
What can user do to send a signal to a process via command prompt (shell)?
- use CTRL+C to send an SIGINT signal to the running process
- use CTRL+Z to send a SIGTSTP signal to the running process, etc.
One can use this tutorial to become more familiar with signals.
                                   Ordering signals:
alarm, ualarm, setitimer
Description: these functions provide a mechanism for a process to interrupt itself
at some future time. They do it by setting a timer; when the timer expires, the
process receive a signal.
Possible signals:
SIGALRM - a real-time timer that counts clock time (alarm, ualarm, setitimer )
SIGVTALRM - a virtual timer that counts CPU time used by the process
(setitimer )
SIGPROF - a profiling timer that counts both CPU time used by the process,
and CPU time spent in system calls on behalf of the process (setitimer )
Important: you can have one timer of each kind set at any given time. If you set a
timer that has not yet expired, that timer is simply reset to the new value.
How to use:
#include <unistd.h>
unsigned int alarm (unsigned int seconds);
 - notifies of a timeout after the number of real-time seconds (only for once)
 - returns 0, or (if we used alarm before and the timer didn‟t expired yet) number of
seconds until previously set alarm
alarm (10); // the process will get SIGALRM signal after 10 (real-time) seconds
 - if you want to delete the alarm order you made, use alarm (0) instruction
 - int pause (void) function suspends the process until SIGALRM signal is caught. Pay
attention that you still have to catch this signal in order to change its default action.

#include <unistd.h>
unsigned int ualarm( unsigned int mseconds, unsigned int interval) ;
- notifies of a timeout after the number of real-time microseconds. When the interval
parameter is nonzero, timeout notification occurs after the number of microseconds
specified by the interval parameter has been added to the mseconds parameter.
 - return values are the same as of alarm.
ualarm(1000000, 3000000); // the process will get the first SIGALRM signal after one
second, and then it will get this signal every three seconds
#include <unistd.h>
int setitimer ( int which, struct itimerval * value, struct itimerval old_value)
 - notifies of a timeout according to the chosen interval timer (real, virtual or profiling).
When the value parameter is nonzero, timeout notification occurs each interval of time
that is specified in value . When the old_value is nonzero, the old value of the timer is
stored here.
 - 0 is returned on success, -1 is returned and the errno global variable is set – on failure.
Timer values are defined by the following structures:
     struct itimerval {
        struct timeval it_interval; // next value
        struct timeval it_value;    // current value
    struct timeval {
        long tv_sec; // seconds
        long tv_usec; // microseconds
There are three interval timers (that don‟t intersect):
ITIMER_REAL – provides SIGALRM signal (real-time timer)
ITIMER_VIRTUAL – provides SIGVTALRM signal (virtual time timer)
ITIMER_PROF – provides SIGPROF signal (profiling timer)
struct itimerval itv;
itv.it_interval.tv_sec = 2;
itv.it_interval.tv_usec = 0;
itv.it_value.tv_sec = 4;
itv.it_value.tv_usec = 0;
setitimer (ITIMER_VIRTUAL, &itv, NULL);
In this example a process sets a virtual timer (that counts CPU time used by a process).
It will get a first SIGVTALRM signal after 4 seconds, and then every two seconds.
Note: for more information about alarm, ualarm go here, for more information about
setitimer go here.
setjmp, longjmp
Description: these functions are useful for handling error conditions that occur in a
deeply nested function call. They allow to a process branch back through the
call frames to a function that is in the call path of the current function, without
walking through all the calls tree:
Example:                                                      process stack
process calls to func1(…)                                      stack frame
                                                                 for main
func1 calls to func2(…)
                                                               stack frame
in func2(…) we use setjmp to save the                           for func1
current process environment                                    stack frame
                                                                for func2
func2 calls to func3(…)

                                                               stack frame
func_n calls to func_n+1( )                                     for func_n

we detected some error and want to return                      stack frame
to func2(…); since we used setjmp from                             for
it, we can do it using longjmp                                  func_n+1
How to use:
#include <setjmp.h>
int setjmp ( jmp_buf env );
- saves the stack context/environment in env for later use by longjmp()
- returns 0 if returning directly and non-zero when returning from longjmp() using the
saved context.
#include <setjmp.h>
void longjmp (jmp_buf env, int val);
 - restores the environment saved by setjmp; parameter val would be the returned value of
setjmp (if a process branch using longjmp, it returns to setjmp function, and setjmp can
recognize and return the val argument to the function from which setjmp was called).
#include <setjmp.h>
jmp_buf jmpbuffer; // define a global variable for saving an environment
int main ( ) {
  int test = 2;
  char line [100];
  if (setjmp (jmpbuffer) != 0) // if return value is 1, then a process just returned from here
       printf (“a process returned from deeply nested function due to error detection”);
  test = 3;
  while ( fgets (line, 100, stdin) != NULL)
  … }
void do_line (char * line) { … do_more (line); ….}
void do_more (char * line) { … count_something (line); …}
void count_something (char * line) {
     if line[0] != „a‟
        longjmp (jmpbuffer, 1);
… }
In this example, we use setjmp to save the current environment of the process in the main
function. Then we start an infinite loop, while getting a line from a user and processing
it. If in the function “count_something” (that is deeply nested call) we detect an error
we return to main using longjmp.
Suppose we have some variable - int test in our example. Its value while using setjmp was 2,
and then it is changed to be 3. The question is: what would be its value after a process
uses longjmp? The common case that its value wouldn‟t rolled back, but if you want to
guarantee that it wouldn‟t be changed by longjmp, you can use volatile variable type.
int main ( ) {
  volatile int a = 3;
  int b = 3;
  setjmp (jmpbuffer);
  printf (“a = %d, b = %d \n”, a, b);
  a = b = 4;
  …. }
 void count_something (char * line) {
  longjmp (jmpbuffer, 1);
  … }
In this example, suppose that longjmp was executed. When printf is executed the first time,
we will see that the values of a and b are 4. When printf is executed the second time,
the value of a would be the most updated value, i.e. a = 3; the value of b depends on the
compiler we used to compile the process – it might have rolling back mechanism, and
might not.

To top