Monday, March 19, 2012

Signals - System Software Lab

NAME

signal, sigset, sighold, sigrelse, sigignore, sigpause - signal management

 SYNOPSIS



#include <signal.h>

void (*signal(int sig, void (*func)(int)))(int);
int sighold(int sig);
int sigignore(int sig);
int sigpause(int sig);
int sigrelse(int sig);
void (*sigset(int sig, void (*disp)(int)))(int);

 DESCRIPTION

Use of any of these functions is unspecified in a multi-threaded process. The signal() function chooses one of three ways in which receipt of the signal number sig is to be subsequently handled. If the value of func is SIG_DFL, default handling for that signal will occur. If the value of func is SIG_IGN, the signal will be ignored. Otherwise, func must point to a function to be called when that signal occurs. Such a function is called a signal handler.
When a signal occurs, if func points to a function, first the equivalent of a:

signal(sig, SIG_DFL);

is executed or an implementation-dependent blocking of the signal is performed. (If the value of sig is SIGILL, whether the reset to SIG_DFL occurs is implementation-dependent.) Next the equivalent of:

(*func)(sig);

is executed. The func function may terminate by executing a return statement or by calling abort(), exit(), or longjmp(). If func executes a return statement and the value of sig was SIGFPE or any other implementation-dependent value corresponding to a computational exception, the behaviour is undefined. Otherwise, the program will resume execution at the point it was interrupted. If the signal occurs other than as the result of calling abort(), kill() or raise(), the behaviour is undefined if the signal handler calls any function in the standard library other than one of the functions listed on the sigaction() page or refers to any object with static storage duration other than by assigning a value to a static storage duration variable of type volatile sig_atomic_t. Furthermore, if such a call fails, the value of errno is indeterminate.
At program startup, the equivalent of:

signal(sig, SIG_IGN);

is executed for some signals, and the equivalent of:

signal(sig, SIG_DFL);

is executed for all other signals (see exec).
The sigset(), sighold(), sigignore(), sigpause() and sigrelse() functions provide simplified signal management.
The sigset() function is used to modify signal dispositions. The sig argument specifies the signal, which may be any signal except SIGKILL and SIGSTOP. The disp argument specifies the signal's disposition, which may be SIG_DFL, SIG_IGN or the address of a signal handler. If sigset() is used, and disp is the address of a signal handler, the system will add sig to the calling process' signal mask before executing the signal handler; when the signal handler returns, the system will restore the calling process' signal mask to its state prior the delivery of the signal. In addition, if sigset() is used, and disp is equal to SIG_HOLD, sig will be added to the calling process' signal mask and sig's disposition will remain unchanged. If sigset() is used, and disp is not equal to SIG_HOLD, sig will be removed from the calling process' signal mask.
The sighold() function adds sig to the calling process' signal mask.
The sigrelse() function removes sig from the calling process' signal mask.
The sigignore() function sets the disposition of sig to SIG_IGN.
The sigpause() function removes sig from the calling process' signal mask and suspends the calling process until a signal is received. The sigpause() function restores the process' signal mask to its original state before returning.
If the action for the SIGCHLD signal is set to SIG_IGN, child processes of the calling processes will not be transformed into zombie processes when they terminate. If the calling process subsequently waits for its children, and the process has no unwaited for children that were transformed into zombie processes, it will block until all of its children terminate, and wait(), wait3(), waitid() and waitpid() will fail and set errno to [ECHILD].

 RETURN VALUE

If the request can be honoured, signal() returns the value of func for the most recent call to signal() for the specified signal sig. Otherwise, SIG_ERR is returned and a positive value is stored in errno. Upon successful completion, sigset() returns SIG_HOLD if the signal had been blocked and the signal's previous disposition if it had not been blocked. Otherwise, SIG_ERR is returned and errno is set to indicate the error.
The sigpause() function suspends execution of the thread until a signal is received, whereupon it returns -1 and sets errno to [EINTR].
For all other functions, upon successful completion, 0 is returned. Otherwise, -1 is returned and errno is set to indicate the error.

 ERRORS

The signal() function will fail if:
[EINVAL]
The sig argument is not a valid signal number or an attempt is made to catch a signal that cannot be caught or ignore a signal that cannot be ignored.
The signal() function may fail if:
[EINVAL]
An attempt was made to set the action to SIG_DFL for a signal that cannot be caught or ignored (or both).
The sigset(), sighold(), sigrelse(), sigignore() and sigpause() functions will fail if:
[EINVAL]
The sig argument is an illegal signal number.
The sigset(), and sigignore() functions will fail if:
[EINVAL]
An attempt is made to catch a signal that cannot be caught, or to ignore a signal that cannot be ignored.

 EXAMPLES

None.

 APPLICATION USAGE

The sigaction() function provides a more comprehensive and reliable mechanism for controlling signals; new applications should use sigaction() rather than signal(). The sighold() function, in conjunction with sigrelse() or sigpause(), may be used to establish critical regions of code that require the delivery of a signal to be temporarily deferred.
---------------------------------
Signals are software generated interrupts that are sent to a process when a event happens. Signals can be synchronously generated by an error in an application, such as SIGFPE and SIGSEGV, but most signals are asynchronous. Signals can be posted to a process when the system detects a software event, such as a user entering an interrupt or stop or a kill request from another process. Signals can also be come directly from the OS kernel when a hardware event such as a bus error or an illegal instruction is encountered. The system defines a set of signals that can be posted to a process. Signal delivery is analogous to hardware interrupts in that a signal can be blocked from being delivered in the future. Most signals cause termination of the receiving process if no action is taken by the process in response to the signal. Some signals stop the receiving process and other signals can be ignored. Each signal has a default action which is one of the following:
  • The signal is discarded after being received
  • The process is terminated after the signal is received
  • A core file is written, then the process is terminated
  • Stop the process after the signal is received
Each signal defined by the system falls into one of five classes:
  • Hardware conditions
  • Software conditions
  • Input/output notification
  • Process control
  • Resource control
Macros are defined in header file for common signals.
These include:

SIGHUP 1 /* hangup */ SIGINT 2 /* interrupt */
SIGQUIT 3 /* quit */ SIGILL 4 /* illegal instruction */
SIGABRT 6 /* used by abort */ SIGKILL 9 /* hard kill */
SIGALRM 14 /* alarm clock */  
SIGCONT 19 /* continue a stopped process */  
SIGCHLD 20 /* to parent on child stop or exit */  
Signals can be numbered from 0 to 31.

Sending Signals -- kill(), raise()

There are two common functions used to send signals
int kill(int pid, int signal) - a system call that send a signal to a process, pid. If pid is greater than zero, the signal is sent to the process whose process ID is equal to pid. If pid is 0, the signal is sent to all processes, except system processes.
kill() returns 0 for a successful call, -1 otherwise and sets errno accordingly.
int raise(int sig) sends the signal sig to the executing program. raise() actually uses kill() to send the signal to the executing program:
          kill(getpid(), sig);
There is also a UNIX command called kill that can be used to send signals from the command line - see man pages.
NOTE: that unless caught or ignored, the kill signal terminates the process. Therefore protection is built into the system.
Only processes with certain access privileges can be killed off.
Basic rule: only processes that have the same user can send/receive messages.
The SIGKILL signal cannot be caught or ignored and will always terminate a process.

For examplekill(getpid(),SIGINT); would send the interrupt signal to the id of the calling process.
This would have a similar effect to exit() command. Also ctrl-c typed from the command sends a SIGINT to the process currently being.
unsigned int alarm(unsigned int seconds) -- sends the signal SIGALRM to the invoking process after seconds seconds.

Signal Handling -- signal()

An application program can specify a function called a signal handler to be invoked when a specific signal is received. When a signal handler is invoked on receipt of a signal, it is said to catch the signal. A process can deal with a signal in one of the following ways:
  • The process can let the default action happen
  • The process can block the signal (some signals cannot be ignored)
  • the process can catch the signal with a handler.
Signal handlers usually execute on the current stack of the process. This lets the signal handler return to the point that execution was interrupted in the process. This can be changed on a per-signal basis so that a signal handler executes on a special stack. If a process must resume in a different context than the interrupted one, it must restore the previous context itself Receiving signals is straighforward with the function:
int (*signal(int sig, void (*func)()))() -- that is to say the function signal() will call the func functions if the process receives a signal sig. Signal returns a pointer to function func if successful or it returns an error to errno and -1 otherwise.

func() can have three values:
SIG_DFL
-- a pointer to a system default function SID_DFL(), which will terminate the process upon receipt of sig.
SIG_IGN
-- a pointer to system ignore function SIG_IGN() which will disregard the sig action (UNLESS it is SIGKILL).
A function address
-- a user specified function.
SIG_DFL and SIG_IGN are defined in signal.h (standard library) header file.
Thus to ignore a ctrl-c command from the command line. we could do:
   signal(SIGINT, SIG_IGN);
TO reset system so that SIGINT causes a termination at any place in our program, we would do:
   signal(SIGINT, SIG_DFL);

Example Program :
 #include "stdio.h"
 #include "signal.h"

void sighup(); /* routine child will call upon sigtrap */
void sigint(); /* routine child wiil call upon Signal intialize */
void sigquit(); /* routine child will call upon signal quit */

main()
{ int pid;

  /* get child process */
   printf("\n Lab-12 : Signals : System Software Lab\n");
 
   if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);
    }
  
   if (pid == 0)
     { /* child */
       printf("\n Inside Child Process\n");
       signal(SIGHUP,sighup); /* set function calls */
       signal(SIGINT,sigint);
       signal(SIGQUIT, sigquit);
       for(;;); /* loop for ever */
       printf("\n End of Child Process\n");
     }
  else /* parent */
     {  /* pid hold id of child */
       printf("\n Inside Parent Process\n");
       printf("\nPARENT: sending SIGHUP\n\n");
       kill(pid,SIGHUP);
       sleep(3); /* pause for 3 secs */
       printf("\nPARENT: sending SIGINT\n\n");
       kill(pid,SIGINT);
       sleep(3); /* pause for 3 secs */
       printf("\nPARENT: sending SIGQUIT\n\n");
       kill(pid,SIGQUIT);
       sleep(3);
       printf("\n End of Parent Process\n");
     }
}

void sighup()

{  signal(SIGHUP,sighup); /* reset signal */
   printf("CHILD: I have received a SIGHUP\n");
}

void sigint()

{  signal(SIGINT,sigint); /* reset signal */
   printf("CHILD: I have received a SIGINT\n");
}

void sigquit()

{ printf("Parent Process Stopped the Child Process\n");
  exit(0);
}

1 comment: