110 likes | 337 Views
Signal : - 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
E N D
Signal: - 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 Example: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.Example: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.Example: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 function:signal (SIGALRM, catch_alarm_&_setitimer); signal (SIGVTALRM, catch_alarm_&_setitimer); Notes: - 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. Notes:- 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.Example:pid_t my_pid = getpid(); // sends itself the STOP signalkill(my_pid, SIGSTOP);Example:pid_t pid = fork();sleep(2);// sends KILL signal to its childkill(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
Example:alarm (10); // the process will get SIGALRM signal after 10 (real-time) secondsNotes: - 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.Example: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)Example: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 for func1 in func2(…) we use setjmp to save the current process environment stack frame for func2 func2 calls to func3(…) stack frame for func_n func_n calls to func_n+1( ) stack frame for func_n+1 we detected some error and want to return to func2(…); since we used setjmp from it, we can do it using longjmp
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).
Example:#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) do_line(line); … }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. Example: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.