Co powoduje wysyłanie różnych sygnałów?

28

Czasami jestem trochę zdezorientowany wszystkimi sygnałami, które może odbierać proces. Jak rozumiem, proces ma domyślny moduł obsługi ( rozmieszczenie sygnałów ) dla każdego z tych sygnałów, ale może zapewnić własny moduł obsługi przez wywołanie sigaction().

Oto moje pytanie: co powoduje wysłanie każdego z sygnałów? Zdaję sobie sprawę, że za pomocą -sparametru można ręcznie wysyłać sygnały do ​​uruchomionych procesów kill, ale jakie są naturalne okoliczności, w których sygnały te są wysyłane? Na przykład kiedy SIGINTzostanie wysłany?

Czy istnieją również ograniczenia dotyczące obsługiwanych sygnałów? Czy SIGSEGVmożna przetwarzać nawet sygnały i zwracać kontrolę do aplikacji?

Nathan Osman
źródło
Prawidłowa odpowiedź na to pytanie będzie epicka i w zasadzie powiela informacje zawarte w artykule na ten temat w Wikipedii , więc po prostu tam wskażę.
Shawn J. Goff
@Shawn: Artykuł w Wikipedii zawiera listę sygnałów, ale nie ma jasnej prezentacji tego, kto wysyła jakie sygnały.
Gilles „SO- przestań być zły”

Odpowiedzi:

41

Oprócz wywoływania procesów kill(2)niektóre sygnały są wysyłane przez jądro (lub czasami sam proces) w różnych okolicznościach:

  • Sterowniki terminali wysyłają sygnały odpowiadające różnym zdarzeniom:
    • Powiadomienia o naciśnięciu klawisza: SIGINT(proszę wrócić do głównej pętli) na Ctrl+ C, SIGQUIT(proszę natychmiast wyjść) na Ctrl+ \, SIGTSTP(proszę zawiesić) na Ctrl+ Z. Klucze można zmienić za pomocą sttypolecenia.
    • SIGTTINi SIGTTOUsą wysyłane, gdy proces w tle próbuje odczytać lub zapisać na terminalu sterującym.
    • SIGWINCH jest wysyłany w celu zasygnalizowania zmiany rozmiaru okna terminala.
    • SIGHUPprzesyłany jest do sygnału, że terminal zniknął (historycznie, ponieważ modem miał godzinie h Ung w górę , w dzisiejszych czasach zazwyczaj dlatego, że zamknął okno emulatora terminala).
  • Niektóre pułapki procesorowe mogą generować sygnał. Szczegóły są zależne od architektury i systemu; oto typowe przykłady:
    • SIGBUS dla niewyrównanej pamięci dostępu;
    • SIGSEGV dostęp do niezapisanej strony;
    • SIGILL za nielegalną instrukcję (zły kod operacji);
    • SIGFPEdla instrukcji zmiennoprzecinkowej ze złymi argumentami (np sqrt(-1).).
  • Szereg sygnałów powiadamia proces docelowy o wystąpieniu jakiegoś zdarzenia systemowego:
    • SIGALRMinformuje, że upłynął czas ustawiony w procesie. Czasomierze można ustawić alarm, setitimeri inni.
    • SIGCHLD powiadamia proces, że jedno z jego dzieci zmarło.
    • SIGPIPEjest generowany, gdy proces próbuje zapisać do potoku, gdy koniec odczytu został zamknięty (chodzi o to, że jeśli uruchomisz foo | bari barwyjdziesz, foozostanie zabity przez a SIGPIPE).
    • SIGPOLL(nazywany także SIGIO) powiadamia proces o wystąpieniu zdarzenia pollable. POSIX określa zdarzenia pollable zarejestrowane przez I_SETSIG ioctl. Wiele systemów zezwala na zdarzenia pollable na dowolnym deskryptorze pliku ustawionym za pomocą O_ASYNC fcntlflagi. Powiązanym sygnałem jest SIGURGpowiadomienie o pilnych danych na urządzeniu (zarejestrowanym przez I_SETSIG ioctl) lub gnieździe .
    • W niektórych systemach SIGPWRjest wysyłany do wszystkich procesów, gdy UPS sygnalizuje, że nastąpi awaria zasilania.

Te listy nie są wyczerpujące. Standardowe sygnały są zdefiniowane w signal.h.

Większość sygnałów może zostać przechwycona i przetworzona (lub zignorowana) przez aplikację. Jedynymi dwoma przenośnymi sygnałami, których nie można złapać, są SIGKILL(po prostu zgiń) i STOP(zatrzymaj wykonanie).

SIGSEGV( błąd segmentacji ) i jego kuzyn SIGBUS( błąd magistrali ) można złapać, ale to zły pomysł, chyba że naprawdę wiesz, co robisz. Typową aplikacją do ich przechwytywania jest drukowanie śladu stosu lub innych informacji debugowania. Bardziej zaawansowaną aplikacją jest implementacja pewnego rodzaju zarządzania pamięcią wewnątrzprocesową lub wychwytywanie złych instrukcji w silnikach maszyn wirtualnych.

Na koniec pozwól mi wspomnieć o czymś, co nie jest sygnałem. Naciśnięcie Ctrl+ Dna początku wiersza w programie, który odczytuje dane wejściowe z terminala, informuje program, że osiągnięto koniec pliku wejściowego. To nie jest sygnał: jest przesyłany przez interfejs API wejścia / wyjścia. Podobnie jak Ctrl+ Ci przyjaciele, klucz można skonfigurować za pomocą stty.

Gilles „SO- przestań być zły”
źródło
I SIGHUP, modem się rozłączył. :-)
Keith
1
Kolejna rzecz do zapamiętania SIGFPE:, nieco nieintuicyjnie, sygnalizowana jest również przy całkowitym dzieleniu przez zero, a czasem przy przepełnieniu całkowitą ze znakiem.
ephemient
18

Najpierw odpowiedz na drugie pytanie: SIGSTOPi SIGKILLnie może zostać złapany przez aplikację, ale każdy inny sygnał może nawet SIGSEGV. Ta właściwość jest przydatna do debugowania - na przykład, przy odpowiedniej obsłudze biblioteki, możesz nasłuchiwać SIGSEGVi generować ślad stosu, aby pokazać, gdzie wystąpił ten segfault.

Oficjalne słowo (w każdym razie dla systemu Linux) na temat tego, co robi każdy sygnał, jest dostępne po wpisaniu man 7 signalz wiersza poleceń systemu Linux. http://linux.die.net/man/7/signal ma te same informacje, ale tabele są trudniejsze do odczytania.

Jednak bez pewnego doświadczenia z sygnałami z krótkich opisów trudno jest dowiedzieć się, co robią w praktyce, więc oto moja interpretacja:

Wywołane z klawiatury

  • SIGINTdzieje się, gdy uderzasz CTRL+C.
  • SIGQUITjest wywoływany przez CTRL+\i zrzuca rdzeń.
  • SIGTSTPzawiesza program po naciśnięciu CTRL+Z. W przeciwieństwie do tego SIGSTOP, jest to możliwe do złapania, co daje programom viszansę na zresetowanie terminala do bezpiecznego stanu przed zawieszeniem.

Interakcje terminalowe

  • SIGHUP („zawieszanie się”) dzieje się, gdy zamkniesz xterm (lub w inny sposób odłączysz terminal) podczas działania programu.
  • SIGTTINi SIGTTOUwstrzymaj swój program, jeśli będzie próbował czytać lub pisać na terminalu, gdy działa w tle. Aby SIGTTOUtak się stało, myślę, że program musi pisać /dev/tty, a nie tylko domyślny standard.

Wyzwalany przez wyjątek procesora

Oznacza to, że Twój program próbował zrobić coś złego.

  • SIGILLoznacza nielegalną lub nieznaną instrukcję procesora. Może się tak zdarzyć, jeśli próbujesz na przykład uzyskać bezpośredni dostęp do portów we / wy procesora.
  • SIGFPEoznacza, że ​​wystąpił błąd matematyczny sprzętu; najprawdopodobniej program próbował podzielić przez zero.
  • SIGSEGV oznacza, że ​​twój program próbował uzyskać dostęp do niezapisanego regionu pamięci.
  • SIGBUSoznacza, że ​​program uzyskał niepoprawny dostęp do pamięci w inny sposób; Nie będę wchodził w szczegóły tego podsumowania.

Interakcja procesowa

  • SIGPIPEdzieje się, jeśli spróbujesz napisać do potoku po tym, jak czytnik potoku zamknie ich koniec. Zobaczyć man 7 pipe.
  • SIGCHLDdzieje się, gdy utworzony proces potomny zostanie zamknięty lub zawieszony (przez SIGSTOPlub podobny).

Przydatny do auto-sygnalizacji

  • SIGABRTjest zwykle spowodowany przez program wywołujący abort()funkcję i domyślnie powoduje zrzut pamięci. Coś w rodzaju „przycisku paniki”.
  • SIGALRMjest spowodowany alarm()wywołaniem systemowym, które spowoduje, że jądro dostarczy SIGALRMdo programu po określonej liczbie sekund. Zobacz man 2 alarmi man 2 sleep.
  • SIGUSR1i SIGUSR2są używane w dowolny sposób. Mogą być przydatne do sygnalizacji między procesami.

Wysłane przez administratora

Sygnały te są zwykle wysyłane z wiersza polecenia, killpolecenia fglub bgw przypadku SIGCONT.

  • SIGKILLi SIGSTOPsą sygnałami, których nie można zablokować. Pierwszy zawsze kończy proces natychmiast; drugi zawiesza proces.
  • SIGCONT wznawia zawieszony proces.
  • SIGTERMjest dającą się złapać wersją SIGKILL.
Jander
źródło
Jaki sygnał jest wysyłany, gdy shutdownpolecenie jest używane?
Nathan Osman
To zależy od skryptów zamykających. Zazwyczaj SIGTERMwysyłany jest jako pierwszy, następnie następuje opóźnienie, a następnie SIGKILL. Zasadniczo w przypadku twardego, natychmiastowego zamknięcia jądro wcale nie musi wysyłać sygnału; może po prostu przestać działać.
Jander