Mechanizm sygnalizacji w jądrze Linux umożliwia uruchamianym aplikacjom asynchroniczne powiadamianie systemu o wystąpieniu nowego zdarzenia. Ze względu na swoją naturę ten mechanizm sygnalizacji jest ogólnie znany jako przerwania programowe. Podobnie jak przerwania sprzętowe, sygnały przerywają normalny przepływ aplikacji i nie można przewidzieć, kiedy aplikacja otrzyma sygnał.
Zanurzmy się głęboko w mechanizm sygnalizacji w Linuksie i zrozummy, co dzieje się za kulisami.
Podstawowe koncepcje dotyczące sygnałów w systemie Linux
W systemie Linux procesy generują sygnały w trzech podstawowych sytuacjach:
- Gdy po stronie sprzętowej wystąpi sytuacja wyjątkowa. Na przykład możesz pomyśleć o zdarzeniach, takich jak aplikacja próbująca uzyskać dostęp do regionu poza dopuszczalna przestrzeń adresowa (błąd segmentacji) lub generowanie kodu maszynowego z dzieleniem przez zero operacja.
- Sytuacje, takie jak użycie kombinacji klawiszy, takich jak Ctrl + C lub Ctrl + Z na konsoli przez użytkownika, zmieniając rozmiar ekranu konsoli lub wysyłając sygnał „kill”.
- Zegar ustawiony w aplikacji wygasa, limit procesora nadany aplikacji jest wysoki, dane przychodzą do otwartego deskryptora pliku itp.
Pojęcie sygnałów istnieje od wczesnych wersji Uniksa. Wcześniej istniało kilka różnic między wersjami Uniksa w zakresie przetwarzania sygnału. Później, z standaryzacja POSIX stworzony do zarządzania sygnałami, Linux i inne pochodne Uniksa zaczęły przestrzegać tych standardów. Z tego powodu koncepcje sygnałów Unix i sygnałów POSIX, które można napotkać w niektórych dokumentach, wskazują na różnice.
Numery sygnałów
Sygnały mają różne wartości liczbowe, zaczynając od jednej. Na przykład sygnał 1 to a HUP sygnał w prawie każdym systemie lub sygnał 9 to a ZABIĆ sygnał.
Jednak używanie tych liczb jest zdecydowanie odradzane, gdy używasz sygnałów w swoich aplikacjach. Dla sygnałów POSIX, sygnał.h plik powinien znajdować się w aplikacji, a programista powinien używać stałych definicji powiązanych liczb, takich jak ZGŁOSZENIE, SIGKILLitp. zamiast.
Jeśli zbadasz /usr/include/signal.h pliku w twoim systemie, możesz zobaczyć dodatkowe operacje i inne dołączone pliki, patrząc na definicje wartości, takie jak __USE_POSIX, __UŻYJ_XOPEN, __USE_POSIX199309itp. w pliku. Dostępne numery sygnałów w systemach Linux można znaleźć w /usr/include/asm-generic/signal.h plik, którego nie musisz umieszczać bezpośrednio w kodzie aplikacji.
Generowanie i wysyłanie sygnału
Generowanie sygnału następuje w wyniku zdarzenia. Jednak wysłanie (dostarczenie) sygnału do odpowiedniej aplikacji nie następuje jednocześnie z generowaniem sygnału.
Aby sygnał został wysłany do aplikacji, aplikacja musi być aktualnie uruchomiona i posiadać zasoby procesora. Dlatego wysłanie sygnału do określonej aplikacji następuje, gdy po zmianie kontekstu dana aplikacja ponownie zacznie działać.
Koncepcja Oczekującego Sygnału
W czasie od wygenerowania do wysłania sygnału sygnały są w stanie czuwania. Możesz uzyskać dostęp do liczby oczekujących sygnałów i liczby oczekujących sygnałów dozwolonych dla procesu z /proc/PID/status plik.
# Dla procesu z PID: 2299
kot /proc/2299/status
# Wyjście
...
SigQ: 2/31630
...
Maski i blokowanie sygnału
Dokładny czas nadejścia sygnałów jest często nieprzewidywalny przez aplikację. Dlatego podczas każdej operacji mogą wystąpić pewne krytyczne przerwy. Może to powodować poważne problemy w przypadku aplikacji na dużą skalę.
Aby zapobiec takim niepożądanym sytuacjom, konieczne jest stosowanie masek sygnałowych. W ten sposób możliwe jest zablokowanie niektórych sygnałów przed krytyczną operacją. Na tym etapie ważne jest, aby ukończyć część krytyczną i usunąć zdefiniowane bloki. Ten proces jest czymś, na co programista aplikacji powinien zwrócić uwagę.
Gdy aplikacja zablokuje sygnał, inne wygenerowane sygnały tego samego typu będą w stanie oczekiwania na odblokowanie. W aplikacji wysyłanie oczekujących sygnałów jest również zapewnione, gdy tylko blokada zostanie usunięta.
W ten sposób te same typy sygnałów zawieszonych w momencie zablokowania są wysyłane do aplikacji tylko raz po usunięciu blokady podczas normalnego użytkowania. Sytuacja wygląda inaczej w przypadku sygnałów czasu rzeczywistego.
Typy sygnałów systemu Linux
Domyślne działania mogą się różnić w zależności od typu sygnału. Jeśli aplikacja, która odbiera odpowiedni sygnał, nie ma funkcji obsługi sygnału, wykonywana jest akcja domyślna. Czasami oznacza to zamknięcie aplikacji, a czasami zignorowanie sygnału.
Niektórych sygnałów nie można przechwycić w warstwie aplikacji, sygnały te zawsze wykonują domyślną akcję (jak sygnał KILL).
Oprócz niektórych działań, które powodują zamknięcie aplikacji, tworzony jest również plik zrzutu pamięci. Pliki zrzutu rdzenia, utworzone przez zapisanie tabeli pamięci wirtualnej powiązanego procesu na dysk, pomagają użytkownika do sprawdzenia informacji o stanie przed zakończeniem procesu za pomocą narzędzi debugowania w kolejnych etapach.
Poniższe wartości są oparte na przykładowa architektura MIPS:
Sygnał | Numer | Akcja domyślna | Czy można go złapać? |
---|---|---|---|
ZGŁOSZENIE | 1 | Zakończ aplikację | TAk |
PODPIS | 2 | Zakończ aplikację | TAk |
WYJDŹ | 3 | Zakończ aplikację (zrzut pamięci) | TAk |
SIGILL | 4 | Zakończ aplikację (zrzut pamięci) | TAk |
SIGTRAP | 5 | Zakończ aplikację (zrzut pamięci) | TAk |
SIGABRT | 6 | Zakończ aplikację (zrzut pamięci) | TAk |
SIGFPE | 8 | Zakończ aplikację (zrzut pamięci) | TAk |
SIGKILL | 9 | Zakończ aplikację | Nie |
SIGBUS | 10 | Zakończ aplikację (zrzut pamięci) | TAk |
SIGSEGV | 11 | Zakończ aplikację (zrzut pamięci) | TAk |
SIGSYS | 12 | Zakończ aplikację (zrzut pamięci) | TAk |
SIGPIPE | 13 | Zakończ aplikację | TAk |
SIGALRM | 14 | Zakończ aplikację | TAk |
SIGTERM | 15 | Zakończ aplikację | TAk |
SIGUSR1 | 16 | Zakończ aplikację | TAk |
SIGUSR2 | 17 | Zakończ aplikację | TAk |
SIGCHLD | 18 | Ignorować | TAk |
SIGTSTP | 20 | Zatrzymaj się | TAk |
SIGURG | 21 | Ignorować | TAk |
SIGPOLL | 22 | Zakończ aplikację | TAk |
SIGSTOP | 23 | Zatrzymaj się | Nie |
SYGKONT | 25 | Kontynuuj, jeśli się zatrzymałeś | TAk |
PODPIS | 26 | Zatrzymaj się | TAk |
SIGTTOU | 27 | Zatrzymaj się | TAk |
SIGVTALRM | 28 | Zakończ aplikację | TAk |
SIGPROF | 29 | Zakończ aplikację | TAk |
SIGXCPU | 30 | Zakończ aplikację (zrzut pamięci) | TAk |
SIGXFSZ | 31 | Zakończ aplikację (zrzut pamięci) | TAk |
Cykl życia sygnałów w systemie Linux
Sygnały przechodzą przez trzy etapy. Są one wytwarzane głównie w fazie produkcji, przez jądro lub dowolny proces i są reprezentowane przez liczbę. Działają lekko i szybko, ponieważ nie obciążają ich dodatkowo. Ale jeśli spojrzysz na stronę POSIX, zobaczysz, że sygnały czasu rzeczywistego mogą przesyłać dodatkowe dane.
Faza dostawy sygnałów następuje po fazie produkcji. Zwykle sygnały docierają do aplikacji z jądra tak szybko, jak to możliwe. Czasami jednak aplikacje mogą blokować sygnały podczas wykonywania krytycznych operacji. W takich przypadkach sygnał pozostaje w toku do momentu zawarcia transakcji.
Podobnie jak sygnały, procesy są również integralną częścią ekosystemu Linuksa. Zrozumienie, czym są procesy i jak działają, jest kluczowe, jeśli planujesz zostać administratorem systemu Linux.
Czym jest proces w Linuksie?
Czytaj dalej
Powiązane tematy
- Linux
- Jądro Linuksa
- Administracja systemu
O autorze
Inżynier i programista, pasjonat matematyki i technologii. Zawsze lubił komputery, matematykę i fizykę. Opracował projekty silników gier, a także uczenie maszynowe, sztuczne sieci neuronowe i biblioteki algebry liniowej. Ponadto kontynuuje prace nad uczeniem maszynowym i macierzami liniowymi.
Zapisz się do naszego newslettera
Dołącz do naszego newslettera, aby otrzymywać porady techniczne, recenzje, bezpłatne e-booki i ekskluzywne oferty!
Kliknij tutaj, aby zasubskrybować