• Nie Znaleziono Wyników

Obsługa sygnałów

N/A
N/A
Protected

Academic year: 2021

Share "Obsługa sygnałów"

Copied!
17
0
0

Pełen tekst

(1)

Obsługa

sygnałów

Tomasz Borzyszkowski

(2)

Wprowadzenie

2 Zaawansowane systemy operacyjne często realizując duże zadania, wykorzystują do ich realizacji wiele współdziałających ze sobą

programów/procesów. Do dobrego współdziałania procesy te muszą komunikować się ze sobą. W systemach Unixowych istnieje wiele mechanizmów komunikacji międzyprocesowej. Najczęściej używane to: sygnały, potoki i kolejki FIFO. Na bieżącym wykładzie

przyjrzymy się bliżej sygnałom.

Sygnały dostarczają prostej metody przekazywania przerwań

programowych do procesu Unixowego. Z powodu swojej natury,

sygnały są używane raczej do obsługi nietypowych sytuacji, a nie do prostego przesyłania danych pomiędzy procesami. Proces może zrobić z sygnałem następujące rzeczy:

 Wybrać sposób reakcji po otrzymaniu sygnału (obsługa sygnału)

Blokować sygnał, tj. pozostawić go na później; dotyczy krytycznych

fragmentów kodu

(3)

Nazwy sygnałów

3

Sygnały nie mogą bezpośrednio przenosić informacji, co ogranicza ich użyteczność jako ogólnego mechanizmu komunikacji między

procesami. Jadnak każdy typ sygnału posiada nadaną mnemoniczną nazwę, wskazującą cel w jakim sygnał jest zwykle używany. Nazwy sygnałów są zdefiniowane w pliku nagłówkowym <signal.h>.

Większość sygnałów Unixowych jest przeznaczona do użycia przez jądro, chociaż istnieje również kilka do przesyłania między zwykłymi procesami. Oto kilka wybranych, najczęściej używanych sygnałów:

SIGABRT sygnał przerwania procesu wysyłany przez bieżący proces

za pomocą funkcji abort. Obsługa tego syganłu powinna się

zakończyć tzw. zakończeniem anormalnym. W rzeczywistości następuje zrzut rdzenia (core dump) do pliku w celu dalszej analizy.

SIGALRM tzw. zegar alarmu. Wysyłany do procesu przez jądro, gdy

upłynie ustalony czas. Wszystkie procesy mają w sumie do dyspozycji trzy czasomierze.Czasomierz jest ustawiany przez proces za pomocą funkcji alarm.

(4)

4

cd

Nazwy sygnałów

SIGCHLD proces potomny zakończony lub zatrzymany. Zawsze, gdy

proces potomny kończy się lub zatrzymuje, jądro zawiadamia o tym jego proces rodzicielski, wysyłając mu ten sygnał. Domyślnie proces rodzicielski ignoruje sygnał, więc jeżeli chce wiedzieć o

każdym ukończonym procesie, musi jawnie przechwytywać sygnał.

SIGCONT kontynuuj proces, jeżeli był zatrzymany. Jest to sygnał

sterowania pracą, który powinien wznowić proces, jeżeli został

zatrzymany. W przeciwnym przypadku proces powiniem ignorować sygnał. Stanowi on przeciwieństwo sygnału SIGSTOP.

SIGFPE wyjątek zmiennoprzecinkowy. Wysyłany przez jądro, gdy

wystapi błąd obliczeń zmiennoprzecinkowych, np. nadmiar lub niedomiar. Powoduje anormalne zakończenie.

SIGINT przerwanie. Wysyłany przez jądro do wszystkich procesów

powiązanych z sesją terminala, gdy użytkownik wciśnie klawisz przerwania (Ctrl-c). Jest to powszechnie stosowany sposób

(5)

5

cd

II

Nazwy sygnałów

SIGHUP sygnał zawieszenia. Wysyłany przez jądro do wszystkich

procesów powiązanych z terminalem sterujacym, jeśli zostaje on odłączony. Wysłany także do wszystkich członków sesji, gdy kończy się proces wiodący sesji, którym zwykle jest proces powłoki, pod warunkiem, że sesja jest powiązana z terminalem sterującym.

Dzięki temu, po wylogowaniu użytkownika, jego procesy dziłające w tle są kończone (o ile nie wyłączono obsługi tego sygnału).

SIGILL nielegalna instrukcja. Wysyłany przez system, gdy proces

próbuje wykonać nielegalna instrukcję. Staje się to możliwe, gdy program uszkodzi swój własny kod lub próbuje wykonać instrukcję zmiennoprzecinkową bez odpowiedniego wsparcia sprzętowego. Sygnał powoduje anormalne zakończenie procesu.

(6)

6

cd

III

Nazwy sygnałów

SIGKILL usunięcie. Specjalny sygnał wysyłany do jednego procesu

przez inny, aby usunąć odbiorcę. Jest on także czasem wysyłany przez system, np. podczas zamykania systemu. Jest to jeden z dwóch sygnałów, które nie mogą być zignorowane lub

przechwycone, tj. obsłużone przez procedurę zdefinowaną przez użytkownika.

SIGSTOP zatrzymanie wykonania. Jest to sygnał kontroli zdarzeń,

który zatrzymuje proces. Podobnie jak SIGKILL, nie może zostać

przechwycony lub zignorowany.

SIGTERM programowy sygnał zakończenia. Zwyczajowo jest

używany do kończenia procesu. Programista może użyć tego

sygnału, aby dać procesowi trochę czasu na działania porządkujące przed wysłaniem sygnału SIGKILL.

SIGUSR1 i SIGUSR2 podobnie jak SIGTERM, sygnały te nigdy nie

są wysyłane przez jądro. Mogą być wykorzystane przez użytkownika w dowolnym celu.

(7)

7

Obsługa sygnałów

Po otrzymaniu sygnału proces ma do wyboru jeden z trzech sposobów działania:

 Podejmij działania domyślne, stosowne do otrzymanego sygnału

 Zignoruj sygnał całkowicie i kontynuuj przetwarzanie

 Podejmij działania zdefiniowane przez użytkownika

W starszych wersjach Unixa obsługa sygnałów była względnie prosta, choć czasem zawodziła. Nowe procedury, które przedstawimy, są bardziej niezawodne i jednocześnie bardziej złożone.

Jednym z głównych parametrów przekazywanych do funkcji

systemowych obsługujących sygnały są tzw. zestawy sygnałów. Określają one listy sygnałów, z którymi chcemy coś zrobić.

Zestawy sygnałów są definiowane za pomocą typu sigset_t,

zdefiniowanego w pliku nagłówkowym <signal.h>. Typ ten jest

wystarczająco pojemny, aby zapamiętać reprezentację wszystkich zdefiniowanych w systemie sygnałów.

(8)

8

Zestawy sygnałów

implementacja

Użytkownik może definiować zestawy potrzebnych mu sygnałów za pomocą następujących funkcji:

int sigemptyset(sigset_t *set); int sigfillset (sigset_t *set);

Pierwsza z funkcji inicjuje zestaw funkcji, wskazywany przez set

tak, że wszystkie sygnały są wyłączone, natomiast druga inicjuje zestaw funkcji, wskazywany przez set tak, że wszystkie sygnały są

włączone.

Kolejne funkcje to:

int sigaddset(sigset_t *set, int signo); int sigdelset(sigset_t *set, int signo);

Funkcje te, odpowiednio, dodają do i usuwają z zestawu sygnałów wskazywajego przez set, sygnał signo. Zalecane jest by parametr signo był nazwą sygnału, taką jak np. SIGINT. Podanie

rzeczywistego numeru sygnału jest możliwe ale niezalecane ze względu na przenośność kodu.

(9)

9

Ustalanie działania sygnału

Po zdefiniowaniu zestawu sygnałów można wybrać konkretną metodę obsługi sygnałów używając funkcji:

int sigaction(int signo,

const struct sigaction *act, const struct sigaction *oact);

Parametr signo identyfikuje sygnał, dla którego chcemy określić

działanie. Może to być dowolny sygnał, z wyjątkiem SIGSTOP i

SIGKILL. Drugi parametr określa działanie, jakie chcemy ustawić dla signo. Trzeci parametr jest ustawiany na NULL lub na aktualne

ustawienia.

Struktura sigaction składa się z następujących pól:

void (* sa_handler)(int) identyfikuje działanie, jakie ma

być podjęte po otrzymaniu sygnału. Może przyjmować jedną z następujących wartości: SIG_DFL domyślne działanie systemu, SIG_IGN zignoruj ten sygnał (nie dla SIGSTOP i SIGKILL) albo

adres funkcji wywoływanej po otrzymaniu sygnału. Sygnał zostanie przekazany do funkcji jako jej argument.

(10)

10

Struktura

sigaction

sigset_t sa_mask maska sygnałów, które powinny być

blokowane podczas wywoływania funkcji sa_handler. Dodatkowo,

sygnał, który wywołał funkcję będzie zablokowany (dodany do

sa_mask), chyba że użyto flagę SA_NODEFER lub SA_NOMASK.

Blokowanie przekształca sygnały w bardziej, ale nie całkowicie, godny zaufania mechanizm komunikacji.

int sa_flags zbiór flag, które modyfikują zachowanie procesu

obsługi sygnałów. Jest to zbiór wartości połączonych bitowym OR. Zobacz man sigaction.

Struktura sigaction posiada również wskaźnik do dodatkowej funkcji obsługi. Standard POSIX nie przewiduje jeszcze jego wykorzystania. Powyższy opis przedstawia tylko wybrane definicje zachowań jakie może podjąć program po otrzymaniu sygnału (patrz dokumnetacja systemowa). Poniższe programy ilustrują typowe wykorzystanie przechwytywania sygnałów. Zobacz: sygnaly1.c

sygnaly2.c sygnaly3.c

(11)

11

Sygnały a funkcje systemowe

W większości przypadków, jeżeli do procesu wysyłany jest sygnał w chwili, gdy wykonuje on funkcję systemową, sygnał nie odnosi

żadnego skutku, dopóki funkcja się nie skończy. Jednak kilka funkcji systemowych zachowuje się inaczej i mogą być przerwane przez

sygnał. Dotyczy to funkcji read, write i open w odniesieniu do

powolnych urządzeń takich, jak: terminal, ale już nie plik dyskowy, oraz funkcji wait i pause. We wszystkich tych przypadkach

przerwana funkcja systemowa zwraca -1 i umieszcza EINTR w

zmiennej errno.

Sygnały systemów Unixowych zwykle nie mogą być odkładane na stosie. Ściślej, dla danego procesu w danej chwili nie może istnieć więcej niż jeden zaległy sygnał danego typu, chociaż może

występować więcej niż jeden zaległy typ sygnałów. Z tego względu nie powinno się używać sygnałów jako godnej zaufania metody

(12)

12

sigsetjmp

i

siglongjmp

Czasami w momencie otrzymania sygnału istnieje potrzeba

przeskoczenia do poprzedniej pozycji w programie. Zachowanie takie jest możliwe dzięki podprogramom:

int sigsetjmp (sigjmp_t env, int savemask); void siglongjmp(sigjmp_t env, int val);

Pierwszy zachowuje bieżącą pozycję programu i maskę sygnału przez zapamiętanie środowiska stosu. Drugi przekazuje sterowanie wstecz, do zachowanej pozycji.

Pozycja programu jest zachowana w obiekcie typu sigjmp_buf,

zdefiniowanym w pliku nagłówkowym <setjmp.h>. Jeżeli w

wywołaniu sigsetjmp wartość savemask jest niezerowa, to

zachowana zostanie bieżąca maska sygnału, tj. stan i działania

związane ze wszystkimi sygnałami, oraz środowisko. Mogą one więc być odtworzone przez siglongjmp. Powrót z sigsetjmp zwróci

wartość val, gdy został wywołany z siglongjmp, gdy został

wywołany jako kolejna instrukcja sekwencyjna 0.

(13)

13

Blokowanie sygnałów

Jeżeli program wykonuje odpowiedzialne zadanie, np. aktualizuje bazę danych, należałoby go zabezpieczyć przed przerwaniami w kluczowych sytuacjach. Zamiast ignorowania wszystkich

nadchodzących sygnałów proces może blokować sygnały. Oznacza to, że nie będą one obsługiwane, dopóki proces nie zkończy swojej

krytycznej operacji. Funkcją systemową pozwalającą procesowi zablokować konkretny sygnał jest:

int sigprocmask(int how, const sigset_t *set const sigset_t *oset);

Parametr how informuje jakie działanie wykonać, np. SIG_SETMASK

oznacza blokowanie sygnałów ustawionych w drugim parametrze set.

Trzeci parametr jest wypełniany bieżącą maską blokowanych sygnałów.

(14)

14

Wysyłanie sygnałów

Do wysyłania sygnałów do procesów służy funkcja:

int kill(pid_t pid, int sig);

Pierwszy parametr pid określa proces albo procesy, do których

będzie wysłany sygnał sig. Ponieważ proces, który wywołuje

funkcja kill musi znać PID procesu, do którego wysyła sygnał,

funkcji kill używa się najczęściej między procesami powiązanymi,

np. procesem rodzicielskim i potomnym. Warto też zauważyć, że proces może wysyłać sygnał do samego siebie.

Proces może wysyłać sygnały tylko do takich procesów, których RIUD lub EUID jest taki sam, co procesu wysyłającego. Jak zwykle, proces administratora może wysyłać sygnały do wszystkich procesów. Jeżeli proces zwykłego użytkownika wysyła sygnał do procesu innego

użytkownika, to funkcja kill zwraca -1 i umieszcza wartość EPERM

w errno. Inne możliwości, to ESRCH: nie ma takiego procesu i EINVAL: sig nie jest ważnym numerem sygnału.

(15)

15

Wysyłanie sygnałów

cd

Parametr pid funkcji kill może przybierać następujące wartości:

 Jeżeli pid jest równy zero, sygnał będzie wysłany do wszystkich

procesów, które należą do tej samej grupy procesów co nadawca. Dotyczy to również nadawcy.

 Jeżeli pid jest równy -1, a efektywny EUID nie jest

administratorem, wtedy sygnał zostanie wysłany do wszystkich procesów z RUID równym EUID nadawcy. Ponownie dotyczy to również nadawcy.

 Jeżeli pid jest równy -1, a efektywny EUID jest administratorem,

wtedy sygnał zostanie wysłany do wszystkich procesów z wyjątkiem pewnych specjalnych procesów systemowych.

 Jeżeli pid jest mniejszy niż 0, ale różny od -1, wtedy sygnał

zostanie wysłany do wszystkich procesów z GUID równym

bezwzględnej wartości pid. Dotyczy również nadawcy, jeśli jego

(16)

16

Wysyłanie sygnałów do siebie

Do wysyłania sygnału do procesu wywołującego służy funkcja:

int raise(int sig);

Sygnał o numerze sig jest wysyłany do procesu wywołującego. W

przypadku powodzenia funkcja zwraca 0.

Do ustawiania zegara alarmu procesu służy funkcja:

int alarm(unsigned int sec);

Parametr sec podaje czas w sekundach do alarmu. Kiedy czas

upłynie, do procesu zostanie wysłany sygnał SIGALRM. Funkcja ta nie

powoduje zawieszenia działania procesu, jak sleep(), proces

kontynuuje wykonanie, przynajmniej do otrzymania sygnału. Aktywny zegar alarmu przedostaje się także przez wywołanie exec(),

natomiast wywołanie funkcji fork() wyłącza zegar alarmu w

procesie potomnym. Alarm może być wyłączony za pomocą

wywołania funkcji alarm(0), ponieważ wywołania tej funkcji nie są

odkładane na stosie, tj. drugie wywołanie zastąpi pierwsze. Jednak zwracany jest wówczas czas pozostający do poprzedniego alarmu.

(17)

17

Funkcja systemowa

pause

Systemy Unixowe dostarczają również funkcji systemowej:

int pause(void);

Funkcja ta zawiesza wywołujący proces, aż do otrzymania

dowolnego sygnału. Jeżeli sygnał powoduje normalne zakończenie, wtedy zdarzy się tylko to. Jeżeli sygnał jest ignorowany przez

proces, pause() ignoruje go również. Jeżeli jednak sygnał jest

przechwytywany, to gdy kończy się procedura obsługi przerwania, funkcja zwraca -1 i umieszcza EINTR w errno.

Przykład

:

Program w pliku tml.c używa kolejno funkcji alarm() i pause()

do wyświetlenia komunikatu za określoną liczbę sekund. Wywołuje się go następująco:

$ tml 10 koniec pracy

Cytaty

Powiązane dokumenty

Dla systemu obsługi masowej o wielu strumieniach zgłoszeń i ograniczonej pojemności buforów sformułowano regułę o- kreślajęcę, w zależności od stanu

Odp.: Zaproponowana zmiana może zawęzić krąg wykonawców. Zamawiający w OPZ podał minimalne wymagania, które są również na zaproponowanej przez Wykonawcę liście

Ustaliliśmy, że można to określić jednym zdaniem następująco — dobrze wyspaliśmy się, zjedliśmy dobre śniadanie, odrobinę pobawiliśmy się na Uniwersytecie, żeby

pełnio,ne są ludźmi, szukającymi ochłody. przyjął na aud1enc1i prywatnei nowego or- closc, ze konsckracp nowego b.1skupa do- Robotnicy, zatrudnieni przy robotach

Jednostka gospodarcza ALFA-2 spółka z ograniczoną odpowiedzialnością (dalej: ALFA-2 sp. z o.o.) zajmująca się działalnością produkcyjną jest czynnym podatnikiem

In this study we demonstrated that in TS patients ultra low-dose estrogen replacement therapy in prepubertal age is associated with healthier lipid profile than conventional

budując solidarne państwo dobrobytu, źródłem ograniczenia wolności, praw człowieka i dyskryminacji okazuje się kultura, w której zapisane są ograniczające nas wzorce

.W trakcie zgrupowania wyżywienie serwowane jest zgodne z wytycznymi sanitarnymi, Obiad składa się z dwóch dań z podwieczorkiem.. Podczas posiłków serwowane są różnorodne,