3.8. Demony, sygnały i unicestwianie procesów

Kiedy korzystamy z edytora tekstu, możemy go w prosty sposób obsługiwać, wczytywać pliki, itp. Jest to możliwe dzięki cechom samego edytora oraz dzięki temu, że edytor jest podłączony do terminala. Jednakże, niektóre programy pracują bez ciągłej komunikacji z użytkownikiem, są więc odłączone od terminala. Przykładem takiego programu może być serwer WWW, nieustannie odpowiadający na żądania pochodzące z sieci, bez potrzeby komunikacji z użytkownikiem. Inny przykład to programy przesyłające emaile pomiędzy komputerami.

Takie programy nazywane są demonami (ang. daemons). Demony to postaci z mitologii greckiej -- niewielkie usłużne istoty, ani dobre, ani złe, które w rozmaity sposób pomagały ludziom. Podobnie pomagają dzisiejsze serwery pocztowe i serwery WWW. Dlatego właśnie od długiego czasu maskotką BSD jest wesoły demon z widłami i w

Przyjęto, iż programy uruchamiane jako demony mają nazwy zakończone literą “d”. BIND (Berkeley Internet Name Daemon) jest serwerem nazw uruchamianym przez program named, serwer WWW Apache nosi nazwę httpd, demon kolejkowania drukarki (line printer spooling daemon) to lpd, itd. Nie jest to sztywna reguła, lecz przyjęta konwencja; na przykład główny demon pocztowy programu Sendmail nazywa się sendmail, a nie jak można by przypuszczać maild.

Niekiedy istnieje potrzeba komunikacji z procesem -- demonem. Odbywa się ona poprzez sygnały, to znaczy możemy porozumieć się z demonem (lub jakimkolwiek działającym procesem) wysyłając mu sygnał. Są różne rodzaje sygnałów, które możemy wysłać -- niektóre z nich mają określone znaczenie, inne są odpowiednio interpretowane przez aplikację, co powinno być opisane w dokumentacji aplikacji. Sygnał możemy wysłać tylko do procesu, którego jesteśmy właścicielem. Wysłanie sygnału do procesu należącego do kogoś innego za pośrednictwem kill(1) lub kill(2) spowoduje odmowę dostępu. Wyjątkiem jest użytkownik root, który może wysyłać sygnały do dowolnego procesu, niezależnie od jego właściciela.

Zdarza się, że samo FreeBSD również wysyła aplikacjom sygnały. Jeżeli niewłaściwie napisany program próbuje dostać się do niedostępnego dla niego obszaru pamięci, FreeBSD wysyła procesowi sygnał Segmentation Violation (SIGSEGV). Aplikacja może skorzystać z funkcji systemowej alarm(3), wówczas po upłynięciu pewnego czasu zostanie do niej wysłany sygnał Alarm (SIGALRM). I tak dalej.

Do zatrzymania procesu można wykorzystać dwa sygnały: SIGTERM i SIGKILL. Pierwszy z nich jest łagodnym sposobem unicestwienia procesu; proces może przechwycić ten sygnał, następnie zakończyć swoją pracę, np. zamykając pliki, które otworzył. Czasami proces może zignorować sygnał SIGTERM, jeśli akurat zajmuje się czymś, co nie powinno być przerywane.

Sygnał SIGKILL nie może zostać zignorowany. Działa według zasady “Nie obchodzi mnie, co robisz, w tej chwili przestań”. Wysłanie procesowi sygnału SIGKILL powoduje, iż FreeBSD natychmiast go wstrzymuje[1].

Inne użyteczne sygnały to SIGHUP, SIGUSR1 i SIGUSR2. Są to sygnały ogólnego przeznaczenia, różne aplikacje reagują na nie w różny sposób.

Powiedzmy, że dokonaliśmy zmiany w pliku konfiguracji serwera WWW, i chcemy nakazać serwerowi, aby konfiguracja została ponownie wczytana. Moglibyśmy zatrzymać i ponownie uruchomić httpd, ale ubocznym efektem takiego postępowania byłaby chwilowa przerwa w pracy serwera, co jest raczej niepożądane. Większość demonów działa w taki sposób, iż po otrzymaniu sygnału SIGHUP dokonują ponownego przeczytania swojego pliku konfiguracyjnego. Dzięki temu zamiast unicestwiania i ponownego uruchamiania httpd możemy wysłać mu sygnał SIGHUP. Nie jest jednoznacznie określone, jak procesy reagują na sygnał SIGHUP, dlatego różne demony mogą zachowywać się w różny sposób -- w razie niepewności warto zapoznać się z dokumentacją konkretnego demona.

Sygnały wysyłane są przy użyciu polecenia kill(1), jak w poniższym przykładzie.

Wysyłanie sygnału do procesu

W tym przykładzie zaprezentowano wysyłanie sygnału do inetd(8). Plik konfiguracyjny dla inetd to /etc/inetd.conf. Wysłanie sygnału SIGHUP spowoduje ponowne przeczytanie tego pliku.

  1. Trzeba ustalić PID procesu, do którego wysyłać będziemy sygnał -- do tego celu posłużą polecenia ps(1) i grep(1). Polecenia grep(1) używamy do odnalezienia podanego ciągu znaków. Ponieważ polecenia wydajemy jako zwykły użytkownik, a inetd(8) działa jako root, polecenie ps(1) musimy wywołać z opcją ax.

    % ps -ax | grep inetd
      198  ??  IWs    0:00.00 inetd -wW
    

    Jak widać, inetd(8) ma PID o wartości 198. Niekiedy w przedstawionym powyżej przykładzie może się także pojawić proces grep inetd, wynika to ze sposobu, w jaki ps(1) odnajduje działające procesy.

  2. Sygnał wysyłamy przy pomocy polecenia kill(1). Najpierw skorzystamy jednak z polecenia su(1) by stać się rootem, gdyż inetd(8) działa jako root.

    % su
    Password:
    # /bin/kill -s HUP 198
    

    Podobnie jak wiele poleceń w systemach UNIX®, kill(1) nie wyświetla żadnego komunikatu w przypadku powodzenia. Jeżeli natomiast sygnał został wysłany do procesu, którego nie jest się właścicielem, pojawi się informacja: “kill: PID: Operation not permitted” (niedozwolona operacja). Błędne wpisanie PID-u spowoduje albo wysłanie sygnału do niewłaściwego procesu, co może skończyć się źle, albo też wysłanie sygnału do PID-u, który nie jest w danej chwili wykorzystywany -- pojawi się wówczas komunikat “kill: PID: No such process” (nie ma takiego procesu).

    Dlaczego warto korzystać z /bin/kill?: W wielu powłokach polecenie kill jest wbudowane; oznacza to, że sama powłoka zajmuje się wysyłaniem sygnału, nie wywołując /bin/kill. Może to być użyteczne, jednakże w różnych powłokach stosowana jest różna składnia do określenia nazwy sygnału, który ma być wysłany. Zamiast więc zapamiętywania wszystkich możliwych składni, łatwiej jest po prostu korzystać z polecenia /bin/kill ...

Inne sygnały wysyła się tą samą metodą, wystarczy zastąpić TERM lub KILL w odpowiedni sposób.

WAŻNE: Unicestwianie losowo wybranego procesu jest raczej złym pomysłem. Szczególne znaczenie ma init(8), proces o PID równym 1. Wydanie polecenia /bin/kill -s KILL 1 jest szybką metodą wyłączenia systemu. Należy zawsze sprawdzać poprawność argumentów polecenia kill(1) przed naciśnięciem klawisza Return.

Przypisy

[1]

Nie do końca jest to prawdą -- w kilku przypadkach nie można przerwać procesu. Na przykład gdy proces stara się przeczytać plik znajdujący się na innym komputerze w sieci, a ów inny komputer z jakiegoś powodu będzie niedostępny (na skutek awarii sieci, lub po prostu zostanie wyłączony), to proces stanie się “nieprzerywalny”. Po chwili (zwykle po dwóch minutach) proces przekroczy czas oczekiwania, wówczas zostanie unicestwiony.

Ten i inne dokumenty można pobrać z ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

W przypadku pytań o FreeBSD prosimy przeczytać dostępną dokumentację przed kontaktem z <questions@FreeBSD.org>.
W sprawie zapytań o tę dokumentację prosimy o kontakt z <doc@FreeBSD.org>.