460 likes | 1.08k Views
[Unix Programming] Signal and Signal Processing. Young-Ju, Han Email: yjhan@imtl.skku.ac.kr. Contents. Introduction signal names normal and abnormal termination signal handling signal sets setting the signal action : signal & sigaction Signal blocking Sending signals
E N D
[Unix Programming]Signal and Signal Processing Young-Ju, Han Email: yjhan@imtl.skku.ac.kr
Contents • Introduction • signal names • normal and abnormal termination • signal handling • signal sets • setting the signal action : signal & sigaction • Signal blocking • Sending signals • to other processes : kill • to yourself : raise and alarm • pause system call 2007 UNIX Programming
Introduction • Signals • A simple method for transmitting software interrupts to UNIX processes • Asynchronous events • has a name • begin with the three characters SIG • defined by positive integer constants • <signal.h> • 0 : special usage (normal error checking) • It is often used to determine if a specific process still exists. • 3 things with signals • signal handling • signal blocking • signal sending • Terminology • generate : when event causes the signal occur • delivered : when action for a signal is taken • pending : during the time between generation and delivery • option of block • if generated and action is default or catch • then pending until unblocks or changes to ignore 2007 UNIX Programming
Introduction • signal name 2007 UNIX Programming
Introduction 2007 UNIX Programming
Introduction • abnormal termination • SIGABRT, SIGBUS, SIGSEGV, SIGQUIT, SIGILL, SIGTRAP, SIGSYS, SIGXCPU, SIGXFSZ, SIGFPE • core dump file • memory dump of process • values of all program variables, h/w register and control information from the kernel when it terminate • WCOREDUMP(status) • abort(); • SIGABRT signal • core dump • a process can send a signal to itself 2007 UNIX Programming
signal handling • disposition of the signal (action) • We can tell the kernel to do when a signal occurs • ignore the signal • When delivered to process, it is discarded • never be ignored: SIGKILL, SIGSTOP • Let the default action apply • terminate process (abnormal terminate) • ignore (SIGCHLD ) • stop (SIGSTOP,SIGSTP) • catch the signal • take a specified user-defined action • to perform clean-up operation • Never be catched: SIGKILL, SIGSTOP 2007 UNIX Programming
signal handling • signal C library • ANSI C • signo : signal name • sa_handler • SIG_IGN , SIG_DFL , user_defined signal handler #include <signal.h> void (*signal(int signo, void (*sa_handler)(int)))(int); Returns : previous disposition of signal (see following) if OK, SIG_ERR on error = typedef void sigfunction (int); sigfunction *signal(int, sa_handler *); SIG_ERR SIG_DFL SIG_IGN 2007 UNIX Programming
signal handling • Ex) signal C library #include <signal.h> #include <stdio.h> #include <unistd.h> int main() { void catchint(int); signal(SIGINT,catchint); printf(“sleep call #1\n”); sleep(4); printf(“sleep call #2\n”); sleep(4); printf(“Exiting \n”); exit(0); } void catchint(int signo) { printf(“\nCATCHINT: signo=%d\n”, signo); printf(“CATCHINT: returning\n\n”); } 2007 UNIX Programming
signal handling • signal sets • type sigset_t <signal.h> • a list of signals (to do something with) • one of the main parameters passed to system call that deal with signal #include <signal.h> //initialize int sigemptyset (sigset_t *set); int sigfillset (sigset_t *set);//manipulateint sigaddset (sigset_t *set, int signo); int sigdelset (sigset_t *set, int signo); //signo가 set의 member인지 check int sigismember(const sigset_t *set, int signo); 0 : ok -1 : error 0 : ok -1 : error 0 : non-member 1 : member 2007 UNIX Programming
signal handling • signal sets #include <signal.h> sigset_t mask1, mask2; sigemptyset(&mask1); sigaddset(&mask1, SIGINT); sigaddset(&mask1, SIGQUIT); sigfillset(&mask2); sigdelset(&mask2, SIGCHLD); 2007 UNIX Programming
signal handling • sigaction system call • setting the signal action • Detailed signal management • to choose a particular method of handling a signal #include <signal.h> int sigaction(int signo, const struct sigaction *act, const struct sigaction *oldact ); specify an action except) SIGSTOP SIGKILL previous setting to set either one can NULL 2007 UNIX Programming
signal handling • <signal.h> struct sigaction{ void (* sa_handler) (int); sigset_t sa_mask; int sa_flags; int (*sa_sigaction)(int, siginfo_t*, void *); } sigset_t • sa_handler: the action to be taken(SIG_IGN,SIG_DEF,func) • sa_mask: to add signal blocked during sa_handler • sa_flags: flags which affect the behavior of the signal • SA_RESETHAND : reset to SIG_DFL after executing sa_handler • SA_SIGINFO : passing additional information to sa_sigaction • its number, sending PID, RUID of the sending PID.. • Must use sa_sigaction() instead of sa_handler() • SA_RESTART : slow system call restart 2007 UNIX Programming
signal handling • ex) catching SIGINT void catchint(int signo) { printf(“\nCATCHINT: signo=%d\n”, signo); printf(“CATCHINT: returning\n\n”); } #include <signal.h> #include <stdio.h> #include <unistd.h> int main() { static struct sigaction act; void catchint(int); act.sa_handler = catchint; sigfillset(&(act.sa_mask)); sigaction(SIGINT, &act, NULL); printf(“sleep call #1\n”); sleep(4); printf(“sleep call #2\n”); sleep(4); printf(“sleep call #3\n”); sleep(4); printf(“sleep call #4\n”); sleep(4); printf(“Exiting \n”); exit(0); } 2007 UNIX Programming
signal handling • ex) ignoring SIGINT #include <signal.h> #include <stdio.h> #include <unistd.h> int main() { static struct sigaction act; act.sa_handler = SIG_IGN; sigfillset(&(act.sa_mask)); sigaction(SIGINT, &act, NULL); sigaction(SIGQUIT, &act, NULL); printf(“sleep call #1\n”); sleep(4); printf(“sleep call #2\n”); sleep(4); printf(“sleep call #3\n”); sleep(4); printf(“sleep call #4\n”); sleep(4); printf(“Exiting \n”); exit(0); } 2007 UNIX Programming
signal handling • ex) restoring a previous action #include <signal.h> #include <stdio.h> #include <unistd.h> int main() { static struct sigaction act, oldact; void catchint(int); act.sa_handler = catchint; sigfillset(&(act.sa_mask)); //step1 : signal disposition 설정 sigaction(SIGINT, &act, NULL); sleep(4); printf(“sleep call #1\n”); sleep(4); //step2 : step1에서 설정한 signal disposition을 저장 sigaction(SIGINT, NULL, &oldact); 2007 UNIX Programming
signal handling • ex) restoring a previous action (cont’d) act.sa_handler = SIG_IGN; sigfillset(&(act.sa_mask)); //step3 : signal disposition 재설정 sigaction(SIGINT, &act, NULL); sigaction(SIGINT, &act, &oldact); printf(“sleep call #2\n”); sleep(4); printf(“sleep call #3\n”); sleep(4); //step2에서 저장했던 signal disposition을 다시 복원 sigaction(SIGINT, &oldact, NULL); printf(“sleep call #4\n”); sleep(4); printf(“Exiting \n”); exit(0); } void catchint(int signo) { printf(“\nCATCHINT: signo=%d\n”, signo); printf(“CATCHINT: returning\n\n”); } 2007 UNIX Programming
signal handling • ex) a graceful exit #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> int main(){ static struct sigaction act; void g_exit(int); act.sa_handler = g_exit; sigaction(SIGINT, &act, NULL); ……… //tempfile 조작 } void g_exit(int s) { unlink(“tempfile”); fprintf(stderr, “Interrupted – exiting\n”); exit(1); } 2007 UNIX Programming
Signals and System Calls • If a process is sent a signal when it is executing a system call • Default action • the signal has no effect until the system call completes • Exception • Slow system calls : read(), write(), open() etc • Return errno (errno = EINTR) • example for interrupted system calls if(write(tfd, buf, size) < 0 ){ if(errno == EINTR){ fprintf(stderr,”write interrupted\n”); } /* handle other errors */ } 2007 UNIX Programming
Signals and system calls • Solution for interrupted slow system calls • Solution 1 • Solution2 • sa_flags of struct sigaction : setting SA_RESTART • Ex) • act.sa_flags |= SA_RESTART again: if(write(tfd, buf, size) < 0 ){ if(errno == EINTR){ fprintf(stderr,”write interrupted\n”); goto again; // just an interrupted system call } /* handle other errors */ } 2007 UNIX Programming
signal blocking • Blocked Signal • Not delivered to process • When the signal is unblocked, it is delivered to process • Don’t the block SIGKILL and SIGSTOP • Signal mask • The collection of signals that are currently blocked 2007 UNIX Programming
signal blocking #include <signal.h> int sigpending(sigset_t *set); set : the set of signals that are pending Returns : 0 if OK, -1 on error • returns the set of signals that are blocked from delivery and currently pending for the calling process • The set of signals is returned through the set argument 2007 UNIX Programming
signal blocking • to block out specific signals #include <signal.h> int sigprocmask (int how, const sigset_t *set, sigset_t *oldset); ≠ NULL : previous signal mask NULL : not used 0: ok -1 : error if set ≠ NULL SIG_SETMASK Use set for the mask- ignore the previous value of the mask SIG_UNBLOCK Unblock the signals in set- remove them from the existing mask SIG_BLOCK Block the signals in set- add them to the existing mask. The new mask is the union of the existing mask and set 2007 UNIX Programming
Signal blocking • Print the signal mask for the process void pr_mask() { sigset_t sigset; int errno_save; errno_save = errno; if(sigprocmask(SIG_SETMASK, NULL, &sigset) < 0) perror(“sigprocmask error”); if(sigismember(&sigset, SIGINT)) printf(“SIGINT ”); if(sigismember(&sigset, SIGQUIT)) printf(“SIGQUIT ”); if(sigismember(&sigset, SIGUSR1)) printf(“SIGUSR1 ” ); if(sigismember(&sigset, SIGALRM)) printf(“SIGALRM ”); printf(“\n”); } 2007 UNIX Programming
signal blocking • Ex) extremely critical code #include <signal.h> ... sigset_t set1; sigfillset(&set1); sigprocmask(SIG_SETMASK, &set1, NULL); ... /* perform extremely critical code */ ... sigprocmask(SIG_UNBLOCK, &set1, NULL); 2007 UNIX Programming
signal blocking • Ex) less critical piece of code #include <signal.h> sigset_t set1, set2; sigfillset(&set1); sigfillset(&set2); sigdelset(&set2, SIGINT); sigdelset(&set2, SIGQUIT); /* perform non critical code */ sigprocmask(SIG_SETMASK, &set1, NULL); /* perform extremely critical code */ sigprocmask(SIG_UNBLOCK, &set2, NULL); /* perform less critical code */ sigprocmask(SIG_UNBLOCK, &set1, NULL); 2007 UNIX Programming
signal blocking • Signal blocking with fork and exec #include <errno.h> #include <stdio.h> #include <signal.h> #include <unistd.h> #include <sys/types.h> #include <sys/wait.h> void catchctrlc(int signo){ printf("interupted %ld - %d\n", getpid(), signo); } int main(){ pid_t child; sigset_t mask,omask; struct sigaction act; //SIGINT로 signal mask 설정 if((sigemptyset(&mask) == -1) || (sigaddset(&mask,SIGINT)== -1) || (sigprocmask(SIG_SETMASK,&mask,&omask) == -1)) { perror("sigprocmask"); return 1; } act.sa_handler = catchctrlc; sigfillset(&(act.sa_mask)); sigaction(SIGINT, &act,NULL); 2007 UNIX Programming
signal blocking • Signal blocking with fork and exec if((child=fork()) == -1) return 1; if(child == 0){ sleep(14); execl("/bin/ls","ls","-l",NULL); perror("execl"); return 1; } sleep(5); //unblocked SIGINT if(sigprocmask(SIG_SETMASK, &omask, NULL) == -1){ return 1; } while(wait(NULL) == -1){ if(errno != EINTR) { perror("error"); return 1 ; } } return 0; } 2007 UNIX Programming
signal blocking • pause system call • to pause the calling process until any signal • Obsolete by sigsuspendsystem call #include <unistd.h> int pause (); Returns : -1 with errno set to EINTR #include <unistd.h> #include <signal.h> void sig_handler(int signo) { printf("SIGINT발생\n"); } int main(){ static struct sigaction act; act.sa_handler = sig_handler; sigfillset(&(act.sa_mask)); sigaction(SIGINT, &act, NULL); printf("hello world!\n"); pause(); printf("Interupt\n");} 2007 UNIX Programming
signal blocking • Reliability Problem of pause system call if(!usr_interrupt) pause(); sigset_t newmask, oldmask; sigemptyset(&newmask); sigaddset(&newmask, SIGINT); /* block SIGINT and save current signal mask */ sigprocmask(SIG_BLOCK, &newmask, &oldmask); .. /* critical region of code */ .. /* reset signal mask, which unblocks SIGINT */ sigprocmask(SIG_SETMASK, &oldmask, NULL); /* window is open */ pause(); /*wait for signal to occur */ Unblock된 Signal이 발생한다면? 2007 UNIX Programming
signal blocking #include <signal.h> int sigsuspend(const sigset_t *sigmask) sigmask : blocked signal (usually empty set) Returns : -1 with errno set to EINTR(OK) -1 with errno set to EFAULT(error) • A way to both reset the signal mask and put the process to sleep in a single atomic operation • Replace the caller’s signal mask with the set of signals pointed to by the sigmask argument • Suspend the caller until delivery of a signal whose action is either to execute a signal catching function or to terminate the process • If a signal is caught and if the signal handler returns, then sigsuspend returns and the signal mask of the process is set to its value before the call to sigsuspend 2007 UNIX Programming
signal blocking int main(void) { signal(SIGINT, sig_int); sigemptyset(&zeromask); sigaddset(&zeromask, SIGUSR1); sigemptyset(&newmask); sigaddset(&newmask, SIGINT); sigprocmask(SIG_BLOCK, &newmask, &oldmask); /* critical region of code */ /* pause, allowing all signals except SIGUSR1 */ sigsuspend(&zeromask); sigprocmask(SIG_SETMASK, &oldmask, NULL); exit(0); } static void sig_int(int signo) { return; } 2007 UNIX Programming
sending signal • send a signal to other process or a group • kill UNIX command • Signal used mainly • SIGHUP(1), SIGINT(2), SIGQUIT(3), SIGKILL(9), SIGTERM(15) • Ex) kill –s signal_name pid… kill [-signal_name] pid…. kill [-signal_number] pid… kill -2 100 kill –s int 100 kill –s INT 100 kill –INT 100 2007 UNIX Programming
sending signal • send a signal to other process or a group • kill system call #include <sys/types.h> #include <signal.h> int kill (pid_t pid, int sig); 0 : ok -1 : error EPERM : permission ESRCH : no such process EINVAL : sig is not valid > 0 : to certain process = 0 : to all process in own process group = -1 : if euid = root, all process except init process if euid = user, all process with a ruid equal to euid of the sender < 0 : to all process in |pid| process group > 0 : certain signal = 0 : normal error checking 2007 UNIX Programming
sending signal • raise • to send a signal to itself #include <signal.h> int raise (int sig); [ = kill(getpid(), sig); ] • alarm • to set a timer (timer expire : SIGALRM) • alarm(0) : alarm turned off • Not supported multiple alarm #include <unistd.h> unsigned int alarm (unsigned int secs); 0 : not setting any pervious alarm timer >0 :time remaining for any previous alarm timer in seconds 2007 UNIX Programming
sending signal • Simple, incomplete implementation of a sleep static void sig_alarm(int signo) { /* nothing to do, just return to wake up the pause */ return ; } unsigned int sleep1(unsigned int nsecs) { if(signal(SIGALRM, sig_alarm) == SIG_ERR) return (nsecs); alarm(nsecs); /* start the timer */ pause(); /* next caught signal wakes us up */ return (alarm(0)); /* turn off timer, return unslept time */ } 2007 UNIX Programming
sigsetjmp and siglongjmp #include <setjmp.h> int sigsetjmp(sigjmp_buf env, int savemask); Returns : 0 if called directly, nonzero if returning from a call to siglongjmp void siglongjmp(sigjmp_buf env, int val); • When a signal is caught, the signal-catching function is entered with the current signal automatically being added to the signal mask of the process • prevents subsequent occurrence of that signal from interrupting the signal handler • If savemask is nonzero then • sigsetjmp saves the current signal mask of the process in env • When siglongjmp is called, if the env argument was saved by a call to sigsetjmp with a nonzero savemask, • then siglongjmp restores the saved signal mask 2007 UNIX Programming
sigsetjmp and siglongjmp void goback(int signo) { write(2, “\nInterrupt\n”); /* go back to saved position */ siglongjmp(position,1); } sigsetjmp_buf position; void goback(int); int main(void) { static struct sigaction act; . . . /* save current position */ if(sigsetjmp(position, 1) == 0){ act.sa_handler = goback; sigaction(SIGINT,&act, NULL); } domenu(); . . } 2007 UNIX Programming
sigsetjmp and siglongjmp static void sig_alrm(int signo) { return; } int main(void) { signal(SIGUSR1, sig_usr1); signal(SIGALRM, sig_alrm); if(sigsetjmp(jmpbuf,1)) { exit(1); } canjump = 1; for(;;) pause(); } static void sig_usr1(int signo) { if(canjmp ==0) return; alarm(3); for(;;) ... /* busy wait for 3 seconds */ canjump = 0; siglongjmp(jmpbuf,1); } 2007 UNIX Programming
sigsetjmp and siglongjmp • Another (imperfect) implementation of a sleep static jmp_buf env_alrm; static void sig_alrm(int signo) { setlongjmp(env_alrm,1); } unsigned int sleep2(unsigned int nsecs) { if(signal(SIGALRM, sig_alrm) == SIG_ERR) return (nsecs); if( sigsetjmp(env_alrm,1) == 0) { alarm(nsecs); pause(); } return (alarm(0)); } 2007 UNIX Programming