07 Systems Programming-IPC-Signals
07 Systems Programming-IPC-Signals
Inter-Process
Communication
Inter-Process Communications
using Signals
What is a signal?
• Program must sometimes deal with unexpected or unpredictable events,
such as :
• a floating point error
• a power failure
• an alarm clock “ring”
• the death of a child process
• a termination request from a user ( i.e., Control+C )
• a suspend request from a user ( i.e., Control+Z )
• These kind of events are sometimes called interrupts, as they must
interrupt the regular flow of a program in order to be processed.
• When UNIX recognizes that such an event has occurred, it sends the
corresponding process a signal.
Therefore a signal is:
• a software interrupt delivered to a process by the OS because:
• it did something (segmentation fault, FPE)
• the user did something (pressed Ctrl+C)
• another process wants to tell it something (SIGUSR?)
• one way a process can communicate with other processes
• Signal Types:
• Some signals are asynchronous, they may be raised at any time (user pressing Ctrl+C)
• Some signals are directly related to hardware/process code (illegal instruction,
arithmetic exception, such as attempt to divide by 0) - synchronous signals
• Signals functions are defined in signal.h and signal numbers are defined in
signal.h or signum.h (signum.h is used inside signal.h if used)
Actions when Signal is received
• The default handler usually performs one of the following actions:
• Abort: terminate the process and generate a core file ( dump )
• Quit/Exit: terminate the process without generating a core image file ( quit )
• Ignore: ignore and discard the signal ( ignore )
• Stop: suspend the process ( suspend )
• Continue: resume the process (resume)
List of Signals (Linux)
Macro Signal Default Description
Code Action
SIGHUP 1 Quit Hang up - sent to a process when its controlling terminal has
disconnected
SIGINT 2 Quit Interrupt – Ctrl+C pressed by user, terminate the process after saving
the work, Signal can be trapped
SIGQUIT 3 Dump Quit
SIGILL 4 Dump Illegal instruction (bad opcode)
SIGTRAP 5 Dump Trace trap (used by debuggers)
SIGABRT 6 Dump Abort process – Ctrl+\ pressed by user, terminate immediately
SIGBUS 7 Dump bus error (bad format address or unaligned memory access)
SIGFPE 8 Dump Floating Point (Arithmetic) execution bad argument
SIGKILL 9 Quit shell command Kill –SIGKILL or kill -9 or system call kill() to send
SIGKILL signal by another process (unblockable)
List of Signals (BSD)
Macro Signal Default Action Description
Code
SIGUSR1 10 Quit user signal 1
SIGSEGV 11 Dump segmentation violation (out-of-range address)
SIGUSR2 12 Quit user signal 2
SIGPIPE 13 Quit write on a pipe or other socket with no one to read it.
SIGALRM 14 Quit alarm clock timeout
SIGTERM 15 Quit software termination signal(default signal sent by kill )
SIGSTKFLT 16 Quit Stack fault
SIGCHLD 17 Ignore child status changed
SIGCONT 18 Ignore continued after suspension
SIGSTOP 19 Quit Suspend process by signal (unblockable)
SIGTSTP 20 Quit Keyboard store, Stopped by user (Ctrl+Z pressed which
suspend/pause the process)
List of Signals (BSD)
Macro Signal Default Action Description
Code
SIGTTIN 21 Quit Background read from tty
SIGTTOU 22 Quit Background write from tty output
SIGURG 23 Ignore Urgent condition on socket
SIGXCPU 24 Dump CPU time limit exceeded
SIGXFSZ 25 Dump file size limit exceeded
SIGVTALRM 26 Quit virtual timer expired
SIGPROF 27 Quit profiling timer expired
SIGWINCH 28 Ignore window size change
SIGIO 29 Ignore I/O is now possible
SIGINFO 29 Ignore Status request from keyboard
SIGPWR 30 Quit Power failure restart
SIGSYS 31 Dump bad argument to system call or non-existence system call
Sending signals from keyboard
• Process suspended using Ctrl+Z (SIGTSTP) can be brought back to life
using fg command which sends (SIGCONT) signal to resume
• For background process cant use Ctrl+C, Ctrl+Z etc hence kill
command is used (how one can run process in background ?)
kill [options] pid
--l lists all signals you can send
--signal number
kill command can send SIGKILL signal upon pressing Ctrl+C to the
foreground process which cannot be ignored
Signal Handling
• Most signals can be ignored
except SIGKILL and SIGSTOP
• Application can trap the signal
(e.g. SIGINT when Ctrl+C
pressed) and handle signal
disposition via signal handler
• Signal handler can perform
default action (usually process
termination) or customized
actions such as blocking the
signal
Catching Signal
Requesting an Alarm Signal SIGALRM using
alarm() System Call
System Call : unsigned int alarm( unsigned int count )
• alarm() instructs the kernel to send the SIGALRM signal to the calling
process after counting seconds.
• If an alarm had already been scheduled, than an alarm is overwritten.
• If count is 0, any pending alarm requests are cancelled.
• The default handler for this signal displays the message “Alarm clock”
and terminates the process.
• alarm() returns the number of seconds that remain until the alarm
signal is sent
System Call alarm() example
• Set Alarm for 3 second with default action handler which will display
a default message “Alarm clock” and exit the program
Signals\alarm_test.c
Handling Signals (Overriding Default Action)
System Call: void(*signal(int sigCode, void (*func)(int))) (int)
• signal() allows a process to specify the action that it will take when a
particular signal is received.
• sigCode specifies the signal number (as per the table shown in earlier slides)
that is to be reprogrammed
• func may be one of several values:
• SIG_IGN, which indicates that the specified signal should be ignored and discarded (i.e.
No Action to be taken)
• SIG_DFL, which indicates that the kernel’s default handler should be used.
• an address of a user-defined function, which indicates that the function should be
executed when the specified signal arrives.
Handling Signals
• The valid signal numbers are stored in /usr/include/signal.h or
/usr/include/bits/signum.h
• The signals SIGKILL and SIGSTP may not be reprogrammed.
• signal() returns the previous func value associated with sigCode if
successful; otherwise, it returns a value of -1
• signal() system call can be used to override the default action
• A child process inherits the signal settings from its parent during a
fork()
System Call pause()
System Call: int pause(void)
• pause() suspends the calling process and returns when a calling
process receives a signal.
• It is most often used to wait efficiently for a signal.
• pause() doesn’t return anything useful.
$ limit 4 sleep 100 ---> run it again; command takes too long
Child 4032 exceeded limit and is being killed
Suspending and Resuming Process using
SIGSTOP and SIGCONT signals
• The SIGSTOP and SIGCONT signals suspend and resume a process,
respectively.
• They are used by the UNIX shells that support job control to
implement built-in commands like stop, fg, and bg.
• Program in next slide performs these steps:
• The main program creates two children; they both enter an infinite loop and
display a message every second.
• The main program waits for three seconds and then suspend the first child.
• After another three seconds, the parent restarts the first child, waits a little
while longer, and then terminated both children.
Suspending and Resuming Process using SIGSTOP
and SIGCONT signals
Signals\sigstop_sigcont_example.c
#include <signal.h> if ( pid2 == 0 )
#include <stdio.h> {
int main(void) while(1) /* Infinite loop */
{ int pid1; {
int pid2; printf(“pid2 is alive \n”);
pid1 = fork(); sleep(1);
if (pid1== 0) /* First child */ }
{ }
while(1) /* Infinite loop */ sleep(3);
{ kill( pid1, SIGSTOP ); /* Suspend first child */
printf(“pid1 is alive \n”); sleep(3);
sleep(1); kill( pid1, SIGCONT ); /* Resume first child */
} sleep(3);
} kill( pid1, SIGINT ); /* Kill first child */
pid2 = fork(); /* Second child */ kill( pid2, SIGINT ); /* Kill second child */
}
Suspending and Resuming Process using
SIGSTOP and SIGCONT signals
• $ pulse ---> run the program.
• pid1 is alive ---> both run in first three seconds.
• pid2 is alive
• pid1 is alive
• pid2 is alive
• pid1 is alive
• pid2 is alive
• pid2 is alive ---> just the second child runs now since first child is suspended
• pid2 is alive
• pid2 is alive
• pid1 is alive ---> the first child is resumed.
• pid2 is alive
• pid1 is alive
• pid2 is alive
• pid1 is alive
• pid2 is alive
SIGUSR1 and SIGUSR2 → User Defined
Signals
• Developer can use SIGUSR1 and/or SIGUSR2 to create own signals
• Steps for implementing SIGUSR1/2:
• Process designated as recipient of SIGUSR1/2:
• First create a signal handler function → void my_signal_handler(int signum)
• signum will be passed as SIGUSR1 or SIGUSR2 depending on which signal was sent
• Register signal handler function for each signal so that it can be called upon receipt of
that signal → signal( SIGUSR1, my_signal_handler)
• Process designated for sending signals SIGUSR1/2:
• Uses kill() system call to generate/send signal to a specific process using pid → kill( pid1,
SIGUSR1)
• As we studied earlier kill() system call is misnomer and you can use it to send any signal
to a process, in this case it is sending SIGUSR1 signal to pid1
Synchronize the common activity between all
children
• At a particular time interval parent and child all need to do certain
activity
• Parent can set alarm for a specified time and upon receipt of the
SIGALRM it sends SIGUSR1 to the group
• Signals\siguser_sync_example.c
Synchronization between two processes
• Inter Process Communication between parent and child using SIGUSR1 and
SIGUSR2
• This example shows
• Register signal handler for SIGUSR1 and SIGUSR2 for parent process which
inherited by child process because they belong to the same process group
• Child first sends SIGUSR1 to parent
• Parent upon receiving SIGUSR1 sends SIGUSR1 to child
• Child upon receiving SIGUSR1 sends SIGUSR2 to parent
• Parent upon receiving SIGUSR2 sends SIGUSR2 to child
• Child upon receiving SIGUSR2 terminates itself by sending SIGINT signal to itself
• Parent when detect child has died it termininates
• Signals\siguser_test.c
Ignore Other Signals inside Signal Handler
Signals\ignore_signls_inside_signalhandler.c
int main(int ac, char *av[]) void inthandler(int s)
{ {
void inthandler(int); printf(" Received SIGINT signal %d .. waiting\n", s );
void quithandler(int);
char input[100]; printf(" Leaving inthandler \n");
signal( SIGINT, inthandler ); // set trap }
signal( SIGQUIT, quithandler ); // set trap
int i=1;
while (i<5) { void quithandler(int s)
sleep(1);
{
printf("main:%d\n",i++);
} signal(SIGINT, SIG_IGN);
} printf(" Received SIGQUIT signal %d .. waiting\n", s );
sleep(5);
printf(" Leaving quithandler \n");
signal( SIGINT, inthandler );
}
System Call: sigaction()
System Call : int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact )
• It is more advance system call then signal()
• It uses struct sigaction for additional controls
struct sigaction {
void (*sa_handler)(int); →SIG_DFL or SIG_IGN or pointer to signal handler
void(*sa_sigaction)(int, siginfo_t *, void *); → Used only of SA_SIGINFO value in sa_flags,
passes additional information
sigset_t sa_mask; → set of additional signals to be blocked during execution of sa_handler
function
int sa_flags; → special flags affecting signal behavior e.g. SA_SIGINFO value in this flag
indicates handler is sa_sigaction rather than sa_handler
void (*sa_restore)(void); → used for POSIX real time signal only not used by application
}
Manipulating Signal Sets
sa_mask of sigaction structure has set of signal to block.
Set can be modified using these functions:
sigemptyset(sigset_t *set) →init to no signals
sigfillset(sigset_t *set) → init to all signals
sigaddset(sigset_t *set, int signum) → add signal to set
sigdelset(sigset_t *set, int signum) → remove signal from set
sigismember(sigset_t *set, int signum) → check if signal is member of
set
System Call : sigprocmask()
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
oldset: oldset is set with currently block set of signals before making
any changes (this will be used to restore the block state before the call
to sigprocmask)
set : set of signals that will follow action of “how”
how:
SIG_BLOCK: add set of signals in “set” to current blocked signal set
SIG_UNBLOCK: remove set of signals in “set” from current blocked
signal set
SIG_SETMASK: set of blocked signal is set to “set”
Block Other Signal inside Signal Handler using
segprocmask()
void inthandler(int s) int main(int ac, char *av[])
{ {
sigset_t sigset, sigoldset; void inthandler(int);
sigemptyset(&sigset);
signal( SIGINT, inthandler ); // set trap
sigaddset(&sigset, SIGQUIT);
sigprocmask(SIG_SETMASK, &sigset, int i=1;
&sigoldset); while (i<5) {
printf(" Received signal %d .. waiting\n", s ); sleep(1);
.... printf("main:%d\n",i++);
printf(" Leaving SIGINT Handler \n"); }
sigprocmask(SIG_SETMASK, &sigoldset, NULL); }
}
sigaction() example
main()
{
struct sigaction newhandler; /* new settings */
sigset_t blocked; /* set of blocked sigs */
void inthandler(); /* the handler */
newhandler.sa_handler = inthandler; /* handler function */
sigfillset(&blocked); /* mask all signals */
newhandler.sa_mask = blocked; /* store blockmask */
int i;
for (i=1; i<31;i++)
if (i!=9 && i!=17) /* catch all except these signals */
if ( sigaction(i, &newhandler, NULL) == -1 )
printf("error with signal %d\n", i);
while(1){}
}