Signaly jsou vlastne softwarova preruseni. Kazdy netrivialni program ma co do cineni se signaly. Signaly se objevily uz ve Verzi 7, ale az s prichodem SVR3 se staly efektivni.
Kazdy signal ma sve jmeno. Jmeno kazdeho signalu zacina na SIG. Verze 7 mela 15 ruznych signalu. SVR4 a BSD maji 31 ruznych signalu. Jmena techto signalu jsou definovana v souboru <signal.h>. Zadny z techto signalu nema hodnotu 0, POSIX.1 totiz definuje signal null.
Signaly mohou byt generovany ruznymi udalostmi:
Signaly jsou klasickou asynchronni zalezitosti. Reakce na ne mohou byt nasledujici:
Tabulka 13 uvadi prehled signalu dle ruznych norem.
Jmeno Popis ANSI C POSIX.1
Pozn. Norm. akce SIGABRT
Abnormalni ukonceni (abort)
Ukon.+core SIGALRM
Budik
Ukonceni SIGBUS
Chyba sbernice
Ukonceni SIGCHLD
Potomek zastaven ci ukoncen
Ignorace SIGCONT
Pokracovani po SIGSTOP
Pokracovani SIGEMP
Instrukce EMP
Ukon.+core SIGFPE
Aritmeticka vyjimka
Ukon.+core SIGHUP
Zaveseni
Ukonceni SIGILL
Ilegalni instrukce
Ukonceni SIGINFO
Pozadavek o info z terminalu
BSD
Ignorace SIGINT
Preruseni z terminalu
Ukonceni SIGIO
Asynchronni I/O
Ukon./Ign. SIGIOT
Hardwarova chyba (IOT)
Ukon.+core SIGKILL
Ukonceni (nejde chytit)
Ukonceni SIGPIPE
Zapis do roury bez ctenaru
Ukonceni SIGPOLL
Sdilena udalost
Sys.V
Ukonceni SIGPROF
Budik profile (settimer)
Ukonceni SIGPWR
Chyba napajeni/restart
Sys.V
Ignorace SIGQUIT
Ukonceni z terminalu
Ukon.+core SIGSEGV
Vadny odkaz do pameti
Ukon.+core SIGSTOP
Zastaveni (nejde chytit)
Zastaveni SIGSYS
Chybne volani systemu
Ukon.+core SIGTERM
Ukonceni
Ukonceni SIGTRAP
Trasovani (hw vyjimka)
Ukon.+core SIGTSTP
Zastaveni z terminalu
Zastaveni SIGTTIN
Proces v pozadi chce cist tty
Zastaveni SIGTTOU
Pr. v pozadi chce psat do tty
Zastaveni SIGURG
Urgentni podminka na soket
Ignorace SIGUSR1
Uzivatelsky signal 1
Ukonceni SIGUSR2
Uzivatelsky signal 2
Ukonceni SIGVTALRM
Virtualni hodiny (settimer)
Ukonceni SIGWINCH
Zmena velikosti okna terminalu
Ignorace SIGXCPU
Prekrocen casovy limit CPU
Ukon.+core SIGXFSZ
Prekr. limit velikost souboru
Ukon.+core
Nejjednodussim prostrednikem k signalum je funkce signal.
#include <signal.h> |
void (*signal (int signo, void (*func)(int)))(int); |
Vraci: predchozi obsluhu signalu |
Za argument signo lze dosadit nazev z tabulky 13. Argument func muze nabyvat nasledujicich hodnot:
Priklad:
#include <signal.h> static void sig_usr(int); /* one handler for both signals */ int main(void) { if (signal(SIGUSR1, sig_usr) == SIG_ERR) err_sys("can't catch SIGUSR1"); if (signal(SIGUSR2, sig_usr) == SIG_ERR) err_sys("can't catch SIGUSR2"); for ( ; ; ) pause(); } static void sig_usr(int signo) /* argument is signal number */ { if (signo == SIGUSR1) printf("received SIGUSR1\n"); else if (signo == SIGUSR2) printf("received SIGUSR2\n"); else err_dump("received signal %d\n", signo); return; }
Jestlize jsme schopni signaly zpracovavat, musime je umet i zasilat. To nam umoznuje funkce kill nebo raise. Funkce kill umoznuje zaslani signalu procesu nebo skupine procesu. raise umoznuje poslat signal procesu samotnemu.
#include <sys/types.h> #include <signal.h> |
int kill (pid_t pid, int signo); int raise (int signo); |
Vraci: 0 kdyz OK, -1 pri chybe |
Je nekolik rozdilnych podminek pro argument pid funkce kill.
pid > 0 | Signal je posilan procesu s danym PID |
pid == 0 | Signal pro vsechny procesy ze skupiny vysilajiciho |
pid < 0 | Signal pro vsechny procesy ze skupiny abs(pid) |
pid == -1 | Nespecifikovano v POSIX.1 |
POSIX.1 rezervuje signal 0 jako specialni null signal. Tento signal se casto pouziva pro zjisteni, zda dany proces existuje. Jestlize posleme signal null neexistujicimu procesu, errno bude ESRCH. Pozor, nezapominejte, ze unix po urcite dobe recykluje identifikacni cisla procesu.
Funkce alarm nam umoznuje nastavit budik na predem stanoveny cas. Zazvoneni budiku je v unixu reprezentovano generovanim signalu SIGALRM. Jestli bude signal ignorovan nebo zpracovan, je jiz veci daneho procesu.
#include <unistd.h> |
unsigned int alarm (unsigned int seconds); |
Vraci: 0 nebo pocet sekund predchoziho alarmu |
Argument sice specifikuje cas, ale musite pocitat s dodatecnou rezii systemu. Jeden proces muze mit nastaven maximalne jeden budik.
Doplnek k teto funkci tvori funkce pause. Po vyvolani teto funkce prejde proces do stavu pozdrzeni (suspend) az do prichodu signalu.
#include <unistd.h> |
int pause (void); |
Vraci: -1 s errno nastavenou na EINTR |
Pouziti funkce ilustruje nejlepe priklad.
Priklad:
#include <signal.h> #include <unistd.h> static void sig_alrm(int signo) { return; /* nothing to do, just return to wake up the pause */ } unsigned int sleep1(unsigned int nsecs) { if (signal(SIGALRM, sig_alrm) == 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 */ }
Tato funkce vypada jako funkce sleep (viz funkci sleep). Implementace vsak prinasi problemy:
Standardnim pouzitim alarm je implementace tzv. hlidaciho psa (watch dog). Je to vlastne nastaveni maximalni doby trvani nejake operace. Neni-li operace hotova do urcite doby, doslo patrne k chybe.
Priklad:
#include <signal.h> static void sig_alrm(int); int main(void) { int n; char line[MAXLINE]; if (signal(SIGALRM, sig_alrm) == SIG_ERR) err_sys("signal(SIGALRM) error"); alarm(10); if ( (n = read(STDIN_FILENO, line, MAXLINE)) < 0) err_sys("read error"); alarm(0); write(STDOUT_FILENO, line, n); exit(0); } static void sig_alrm(int signo) { return; /* nothing to do, just return to interrupt the read */ }
Pomoci signalu muzeme implementovat take funkce TELL_CHILD, ... z kap. "Podminky zavodu". Popis funkci, ktere jsou pouzity v tomto prikladu a nejsou popsany v teto praci, lze nalezt napr. v manualovych strankach.
Priklad:
#include <signal.h> static volatile sig_atomic_t sigflag; /* set nonzero by signal handler */ static sigset_t newmask, oldmask, zeromask; static void sig_usr(int signo) /* one signal handler for SIGUSR1 and SIGUSR2 */ { sigflag = 1; return; } void TELL_WAIT() { if (signal(SIGUSR1, sig_usr) == SIG_ERR) err_sys("signal(SIGINT) error"); if (signal(SIGUSR2, sig_usr) == SIG_ERR) err_sys("signal(SIGQUIT) error"); sigemptyset(&zeromask); sigemptyset(&newmask); sigaddset(&newmask, SIGUSR1); sigaddset(&newmask, SIGUSR2); /* block SIGUSR1 and SIGUSR2, and save current signal mask */ if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) err_sys("SIG_BLOCK error"); } void TELL_PARENT(pid_t pid) { kill(pid, SIGUSR2); /* tell parent we're done */ } void WAIT_PARENT(void) { while (sigflag == 0) sigsuspend(&zeromask); /* and wait for parent */ sigflag = 0; /* reset signal mask to original value */ if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) err_sys("SIG_SETMASK error"); } void TELL_CHILD(pid_t pid) { kill(pid, SIGUSR1); /* tell child we're done */ } void WAIT_CHILD(void) { while (sigflag == 0) sigsuspend(&zeromask); /* and wait for child */ sigflag = 0; /* reset signal mask to original value */ if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) err_sys("SIG_SETMASK error"); }
Tato funkce slouzi k predcasnemu ukonceni programu. Posle signal SIGABRT procesu.
#include <stdlib.h> |
void abort (void); |
Procesy by nemely signal SIGABRT ignorovat.
Funkce sleep je v textu mnohokrat pouzita. Jde vlastne jen o uspani procesu na prislusnou dobu.
#include <stdlib.h> |
unsigned int sleep (unsigned int seconds); |
Vraci: 0 nebo pocet nedospalych sekund |
Funkce prevede proces do stavu pozastaveni (suspend) do te doby, nez:
Ladislav Dobias