dalsi predchozi obsah
Dalsi: Meziprocesni komunikace Predchozi: Rizeni procesu

  Signaly





Uvod

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.



Koncepce signalu

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 CPOSIX.1 Pozn.Norm. akce
SIGABRT Abnormalni ukonceni (abort) o o Ukon.+core
SIGALRM Budik o Ukonceni
SIGBUS Chyba sbernice Ukonceni
SIGCHLD Potomek zastaven ci ukoncen o Ignorace
SIGCONT Pokracovani po SIGSTOP o Pokracovani
SIGEMP Instrukce EMP Ukon.+core
SIGFPE Aritmeticka vyjimka o o Ukon.+core
SIGHUP Zaveseni o Ukonceni
SIGILL Ilegalni instrukce o o Ukonceni
SIGINFO Pozadavek o info z terminalu BSD Ignorace
SIGINT Preruseni z terminalu o o Ukonceni
SIGIO Asynchronni I/O Ukon./Ign.
SIGIOT Hardwarova chyba (IOT) Ukon.+core
SIGKILL Ukonceni (nejde chytit) o Ukonceni
SIGPIPE Zapis do roury bez ctenaru o Ukonceni
SIGPOLL Sdilena udalost Sys.V Ukonceni
SIGPROF Budik profile (settimer) Ukonceni
SIGPWR Chyba napajeni/restart Sys.V Ignorace
SIGQUIT Ukonceni z terminalu o Ukon.+core
SIGSEGV Vadny odkaz do pameti o o Ukon.+core
SIGSTOP Zastaveni (nejde chytit) o Zastaveni
SIGSYS Chybne volani systemu Ukon.+core
SIGTERM Ukonceni o o Ukonceni
SIGTRAP Trasovani (hw vyjimka) Ukon.+core
SIGTSTP Zastaveni z terminalu o Zastaveni
SIGTTIN Proces v pozadi chce cist tty o Zastaveni
SIGTTOU Pr. v pozadi chce psat do tty o Zastaveni
SIGURG Urgentni podminka na soket Ignorace
SIGUSR1 Uzivatelsky signal 1 o Ukonceni
SIGUSR2 Uzivatelsky signal 2 o 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
Tabulka 13: Unixove signaly






Funkce signal

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;
}


Funkce kill a raise

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 a pause

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 */
}



  Funkce pro priklad v kapitole "Podminky zavodu"

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");
}



Funkce abort

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

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:



Cviceni

  1. Implementujte funkci raise.
  2. Napiste nasleduji program, ktery otestuje synchronizaci rodic-potomek v programu v kapitole ??. Proces vytvori soubor a zapise do nej cislo 0. Potom zavola fork a rodic a potomek stridave inkrementuji pocitadlo v souboru. Pokazde, kdyz je pocitadlo zvetseno, tisknete, ktery proces to provedl (rodic nebo potomek).


dalsi predchozi obsah
Dalsi: Meziprocesni komunikace Predchozi: Rizeni procesu

Ladislav Dobias
Sat Nov 1 15:38:32 MET 1997