220 likes | 460 Views
Operating Systems IPC Unix Case Study: Signals. Signal: An IPC Mechanism. With pipes we communicated data With signal, we can communicate control command The only information is: The number identifying the signal Interrupts a process and forces it to handle the event immediately
E N D
Signal: An IPC Mechanism • With pipes we communicated data • With signal, we can communicate control command • The only information is: • The number identifying the signal • Interrupts a process and forces it to handle the event immediately • kill –l can be used to view all the signals supported by your system
Sending signals to process • From keyboard • Ctrl-C, Ctrl-Z etc • From the command line • kill -<signal> <PID> • fg • Using the kill() system call • Also used by the kill and fg command #include <signal.h> /* signal name macros, and the kill() prototype */ /* first, find my own process ID */ pid_t my_pid = getpid(); /*now that i got my PID, send myself the STOP signal.*/ kill(my_pid, SIGSTOP);
Actions Performed upon Receiving a Signal There are three ways in which a process can respond to a signal: • Explicitly ignore the signal. • Execute the default action associated with the signal. • Catch the signal by invoking a corresponding signal-handler function.
Signal Handler • Corresponding to each signal is a signal handler • Called when a process receives a signal • The function is called “asynchronously” • When the signal handler returns the process continues, as if it was never interrupted • Signal are different from interrupts as: • Interrupts are sent to OS by H/W • Signals are sent to a process by the OS, or by other processes • Note that signals have nothing to do with software interrupts, which are still sent by the hardware (the CPU itself, in this case).
The signal() System Call • Used to set signal handler for a signal type
Example void main() { /* set the INT (Ctrl-C) signal handler to 'catch_int' */ signal(SIGINT, catch_int); /* now, lets get into an infinite loop of doing nothing. */ for ( ;; ) pause(); } /* first, here is the signal handler */ void catch_int(int sig_num) { /* re-set the signal handler again to catch_int, for next time */ signal(SIGINT, catch_int); /* and print the message */ printf("Don't do that"); }
Signal Handlers • Pre-defined Signal Handlers • SIG_IGN: • Causes the process to ignore the specified signal. • To ignore Ctrl-C completely • signal(SIGINT, SIG_IGN); • SIG_DFL: • Causes the system to set the default signal handler for the given signal • signal(SIGTSTP, SIG_DFL);
Race conditions • The occurrence of a second signal while the signal handler function executes • Might be of a different type then the one being handled • Or even of the same type
sigprocmask() • Allows us to specify a set of signals to block • Returns the list of signals that were previously blocked • int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
sigprocmask() • int how • SIG_BLOCK • Add set to the set of currently blocked signals • SIG_UNBLOCK • The signals in set are removed from the current set of blocked signals. • SIG_SETMASK • The set of blocked signals is set to the argument set. • const sigset_t *set • The set of signals to be blocked, or to be added to the current mask, or removed from the current mask (depending on the 'how' parameter). • sigset_t *oldset • If this parameter is not NULL, then it'll contain the previous mask. • Can be used later restore back the situation, before sigprocmask() was called.
Signal functions • Define a new mask set sigset_t mask_set; • Clear the set (i.e. make it contain no signal numbers) sigemptyset(&mask_set); • Add a signal sigaddset(&mask_set, SIGTSTP); • Remove the TSTP signal from the set sigdelset(&mask_set, SIGTSTP); • Check if the TSTP signal is defined in our set if (sigismember(&mask_set, SIGINT) printf("signal INT is in our set\n"); else printf("signal INT is not in our set - how strange...\n"); • Make the set contain ALL signals available on the system sigfillset(&mask_set)
#include <stdio.h> /* standard I/O functions */ #include <unistd.h> /* standard unix functions, like getpid()*/ #include <signal.h> /* signal name macros, and the signal() prototype */ /* first, define the Ctrl-C counter, initialize it with zero. */ int ctrl_c_count = 0; #define CTRL_C_THRESHOLD 5 int main(int argc, char* argv[]) { /* set the Ctrl-C and Ctrl-Z signal handlers */ signal(SIGINT, catch_int); signal(SIGTSTP, catch_suspend); /* enter an infinite loop of waiting for signals */ for ( ;; ) pause(); return 0; }
/* the Ctrl-C signal handler */ void catch_int(int sig_num) { sigset_t mask_set; /* used to set a signal masking set. */ sigset_t old_set; /* used to store the old mask set. */ /* mask any further signals while we're inside the handler. */ sigfillset(&mask_set); sigprocmask(SIG_SETMASK, &mask_set, &old_set); /* increase count, and check if threshold was reached */ ctrl_c_count++; if (ctrl_c_count >= CTRL_C_THRESHOLD) { char answer[30]; /* prompt the user to tell us if to really exit or not */ printf("\nRealy Exit? [y/N]: "); fflush(stdout);
gets(answer); if (answer[0] == 'y' || answer[0] == 'Y') { printf("\nExiting...\n"); fflush(stdout); exit(0); } else { printf("\nContinuing\n"); fflush(stdout); /* reset Ctrl-C counter */ ctrl_c_count = 0; } } /* restore the old signal mask */ sigprocmask(SIG_SETMASK, &old_set, NULL); }
/* the Ctrl-Z signal handler */ void catch_suspend(int sig_num) { sigset_t mask_set; /* used to set a signal masking set. */ sigset_t old_set; /* used to store the old mask set. */ /* mask any further signals while we're inside the handler. */ sigfillset(&mask_set); sigprocmask(SIG_SETMASK, &mask_set, &old_set); /* print the current Ctrl-C counter */ printf("\n\nSo far, '%d' Ctrl-C presses were counted\n\n", ctrl_c_count); fflush(stdout); /* restore the old signal mask */ sigprocmask(SIG_SETMASK, &old_set, NULL); }
Implementing Timers Using Signals • alarm : set a process alarm clock • #include <unistd.h> • unsigned alarm(unsigned sec); • Sends the signal SIGALRMto the calling process after the sec number of seconds have elapsed • If sec is 0, any previously made alarm request is canceled.
#include <signal.h> /* signal name macros, and the signal() prototype */ char user[40]; /* buffer to read user name from the user */ int main(int argc, char* argv[]) { /* set a signal handler for ALRM signals */ signal(SIGALRM, catch_alarm); /* prompt the user for input */ printf("Username: "); fflush(stdout); /* start a 30 seconds alarm */ alarm(30); /* wait for user input */ gets(user); /* remove the timer, now that we've got the user's input */ alarm(0); printf("User name: '%s'\n", user); }`
/* define an alarm signal handler. */ void catch_alarm(int sig_num) { printf("Operation timed out. Exiting...\n\n"); exit(0); }