| sigaction(2) | System Calls Manual | sigaction(2) |
sigaction, rt_sigaction - bada i zmienia akcję sygnału
Standardowa biblioteka C (libc, -lc)
#include <signal.h>
int sigaction(int signum,
const struct sigaction *_Nullable restrict act,
struct sigaction *_Nullable restrict oldact);
sigaction():
_POSIX_C_SOURCE
siginfo_t:
_POSIX_C_SOURCE >= 199309L
Wywołanie systemowe sigaction() jest używane do zmieniania akcji, którą wykonuje proces po odebraniu określonego sygnału (wprowadzenie do sygnałów można znaleźć w podręczniku signals(7)).
signum określa sygnał i może być dowolnym prawidłowym sygnałem poza SIGKILL i SIGSTOP.
Jeśli act nie jest NULL-em, to nowa akcja dla sygnału signum jest brana z act. Jeśli oldact też jest różny od NULL, to poprzednia akcja jest w nim zachowywana.
Struktura sigaction jest zdefiniowana jako:
struct sigaction {
void (*sa_handler)(int);
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;
void (*sa_restorer)(void);
};
Na niektórych architekturach część tej struktury może być unią: nie należy ustawiać jednocześnie pól sa_handler oraz sa_sigaction.
Pole sa_restorer nie jest przeznaczone do bezpośredniego stosowania (POSIX nie określa pola sa_restorer). Więcej informacji o przeznaczeniu tego pola można znaleźć w podręczniku sigreturn(2).
sa_handler określa akcję, jaka ma być powiązana z signum i może być to jedna z:
Jeśli w sa_flags poda się SA_SIGINFO, to sa_sigaction (zamiast sa_handler) będzie określało funkcję obsługi sygnału signum. Funkcja ta ma trzy argumenty, opisane poniżej.
sa_mask określa maskę sygnałów, które powinny być blokowane (tj. dodane do maski sygnałów wątku, z którego sygnał został wywołany) podczas wywoływania funkcji obsługi sygnałów. Dodatkowo, sygnał, który wywołał tę funkcję obsługi będzie zablokowany, chyba że użyto znacznika SA_NODEFER.
sa_flags podaje zbiór znaczników, które modyfikują zachowanie procesu obsługi sygnałów. Jest to zbiór wartości połączonych bitowym OR:
Gdy w act.sa_flags poda się znacznik SA_SIGINFO, to adres procedury obsługi sygnału jest przekazywany za pomocą pola act.sa_sigaction. Ta procedura obsługi przyjmuje trzy argumenty jak poniżej:
void
handler(int sig, siginfo_t *info, void *ucontext)
{
...
}
Te trzy argumenty to:
Typ danych siginfo_t jest strukturą zawierającą następujące pola:
siginfo_t {
int si_signo; /* Numer sygnału */
int si_errno; /* Wartość zmiennej errno */
int si_code; /* Kod sygnału */
int si_trapno; /* Numer pułapki, które spowodowała
sprzętowe wygenerowanie sygnału
(nieużywane na większości architektur) */
pid_t si_pid; /* ID procesu wysyłającego */
uid_t si_uid; /* Rzeczywiste ID użytk. procesu wysyłającego */
int si_status; /* Kod lub sygnał zakończenia */
clock_t si_utime; /* Czas użyty w przestrzeni użytkownika */
clock_t si_stime; /* Czas użyty przez system operacyjny */
union sigval si_value; /* Wartość sygnału */
int si_int; /* Sygnał POSIX.1b */
void *si_ptr; /* Sygnał POSIX.1b */
int si_overrun; /* Licznik przekr. czasom.; czasom POSIX.1b */
int si_timerid; /* ID czasomierza; czasom. POSIX.1b */
void *si_addr; /* Adres pamięci powodujący błąd */
long si_band; /* Grupa zdarzenia (był int w
glibc 2.3.2 i wcześniejszych) */
int si_fd; /* Deskryptor pliku */
short si_addr_lsb; /* Najmniej znaczący bit adresu
(od Linuksa 2.6.32) */
void *si_lower; /* Kres dolny przy wystąpieniu naruszenia
adresu (od Linuksa 3.19) */
void *si_upper; /* Kres górny przy wystąpieniu naruszenia
adresu (od Linuksa 3.19) */
int si_pkey; /* Klucz zabezpieczający na PTE będący powodem
błędu (od Linuksa 4.6) */
void *si_call_addr;/* Adres instrukcji wywołania systemowego
(od Linuksa 3.5) */
int si_syscall; /* Liczba próbowanych wywołań systemowych
(od Linuksa 3.5) */
unsigned int si_arch; /* Architektura próbowanego wywoł. systemowego
(od Linuksa 3.5) */
}
si_signo, si_errno i si_code są zdefiniowane dla wszystkich sygnałów. (Generalnie si_errno nie jest używane pod Linuksem). Pozostałe pola struktury mogą być unią; powinno się odczytywać tylko pola istotne dla danego sygnału.
Pole si_code, wewnątrz argumentu siginfo_t, które jest przekazywane do procedury obsługi sygnału SA_SIGINFO, jest wartością (a nie maską bitową) określającą powód wysłania sygnału. Dla zdarzenia ptrace(2), pole si_code będzie zawierać SIGTRAP i mieć zdarzenie ptrace w najwyższym bajcie:
(SIGTRAP | PTRACE_EVENT_foo << 8).
Dla zdarzeń innych niż ptrace(2), wartości jakie mogą wystąpić w si_code są opisane w pozostałej części niniejszego rozdziału. Od glibc 2.20, definicje większości z tych symboli są pozyskiwane z <signal.h> za pomocą definicji makr testowania cech (przed włączeniem jakiegokolwiek pliku nagłówkowego), jak poniżej:
Dla stałych TRAP_*, definicje symboli są zapewnione jedynie w dwóch pierwszych przypadkach. Przed glibc 2.20, nie było konieczne ustawianie makr, do pozyskania tych symboli.
W przypadku zwykłego sygnału, poniżej zestawiono wartości, które mogą występować w si_code dowolnego sygnału razem z powodami, dla których sygnał był wygenerowany.
Następujące wartości mogą zostać umieszczone w si_code sygnału SIGILL:
Następujące wartości mogą zostać umieszczone w si_code sygnału SIGFPE:
Następujące wartości mogą zostać umieszczone w si_code sygnału SIGSEGV:
Następujące wartości mogą zostać umieszczone w si_code sygnału SIGBUS:
Następujące wartości mogą zostać umieszczone w si_code sygnału SIGTRAP:
Następujące wartości mogą zostać umieszczone w si_code sygnału SIGCHLD:
Następujące wartości mogą zostać umieszczone w si_code sygnału SIGIO/SIGPOLL:
Następująca wartość może zostać umieszczona w si_code sygnału SIGSYS:
Wywołanie sigaction() w Linuksie akceptuje nieznane bity ustawione w act->sa_flags nie zgłaszając błędu. Zachowanie jądra, od Linuksa 5.11 jest takie, że drugie sigaction() wyczyści nieznane bity z oldact->sa_flags. Jednak historycznie, drugie wywołanie zwykle pozostawiało te bity ustawione w oldact->sa_flags.
Oznacza to, że nie da się wykryć obsługi nowych znaczników jedynie sprawdzając znacznik w sa_flags, lecz konieczne jest sprawdzenie, czy SA_UNSUPPORTED zostało wyczyszczone, przed poleganiem na zawartości sa_flags.
Ponieważ zachowania procedury obsługi sygnału nie można zagwarantować, jeśli nie dokonano sprawdzenia, powinno się albo blokować dany sygnał podczas rejestrowania procedury obsługi i wykonać w takim przypadku sprawdzenie, albo — tam, gdzie nie jest to możliwe, np. gdy sygnał jest asynchroniczny — wywołać sigaction() po raz drugi z samej procedury obsługi sygnału.
W jądrach nieobsługujących danego znacznika, jądro zachowa się tak, jakby znacznik ten nie był ustawiony, nawet jeśli znacznik był ustawiony w act->sa_flags.
Znaczników SA_NOCLDSTOP, SA_NOCLDWAIT, SA_SIGINFO, SA_ONSTACK, SA_RESTART, SA_NODEFER, SA_RESETHAND i, jeśli jest zdefiniowany na danej architekturze, SA_RESTORER nie da się wiarygodnie sprawdzić za pomocą opisywanego mechanizmu, ponieważ zostały one wprowadzone przez Linuksem 5.11. Zwykle jednak, programy mogą przyjąć, że znaczniki te są obsługiwane, ponieważ wszystkie były obsługiwane już od Linuksa 2.6, wydanego w roku 2003.
W rozdziale PRZYKŁADY poniżej, zademonstrowano korzystanie z SA_UNSUPPORTED.
sigaction() w przypadku powodzenia zwraca 0. W razie wystąpienia błędu zwracane jest -1 i ustawiana jest zmienna errno wskazując na błąd.
Funkcja opakowująca glibc dla sigaction() daje błąd (EINVAL) przy próbie zmiany dyspozycji dwóch sygnałów czasu rzeczywistego używanych wewnętrznie przez implementację wątkową NPTL. Więcej szczegółów w podręczniku nptl(7).
Na architekturach, na których trampolina sygnału jest zawarta w bibliotece C, funkcja opakowujące sigaction() z glibc, umieszcza adres kodu trampoliny w polu act.sa_restorer i ustawia znacznik SA_RESTORER w polu act.sa_flags. Zob. sigreturn(2).
Oryginalne linuksowe wywołanie systemowe nazywało się sigaction(). Jednak po pojawieniu się sygnałów czasu rzeczywistego w Linuksie 2.2, 32-bitowy typ sigset_t o stałym rozmiarze obsługiwany przez to wywołanie przestał dobrze służyć swemu zadaniu. Z tego powodu, w celu obsługi powiększonego typu sigset_t dodano nowe wywołanie systemowe rt_sigaction(). Nowe wywołanie przyjmuje czwarty argument size_t sigsetsize, który określa rozmiar w bajtach zestawu sygnałów w act.sa_mask i oldact.sa_mask. Argument ten obecnie musi mieć wartość sizeof(sigset_t) (albo nastąpi błąd EINVAL). Opakowanie glibc sigaction() ukrywa te detale przed nami, po cichu wywołując rt_sigaction() jeśli udostępnia je jądro.
POSIX.1-2008.
POSIX.1-2001, SVr4.
POSIX.1-1990 zabraniał ustawiania akcji dla SIGCHLD na SIG_IGN. POSIX.1-2001 i późniejsze pozwalają na to, tak że można użyć ignorowania SIGCHLD, żeby zapobiec tworzeniu procesów zombie (patrz wait(2)). Niemniej jednak, historyczne zachowanie systemów BSD i System V w zakresie ignorowania SIGCHLD jest inne, tak więc jedyną całkowicie przenośną metodą zapewnienia, że potomek po zakończeniu nie zostanie procesem zombie jest przechwytywanie sygnału SIGCHLD i wywołanie funkcji wait(2) lub podobnej.
POSIX.1-1990 określał tylko SA_NOCLDSTOP. W POSIX.1-2001 dodano SA_NOCLDWAIT, SA_NODEFER, SA_ONSTACK, SA_RESETHAND, SA_RESTART i SA_SIGINFO jako rozszerzenia XSI. POSIX.1-2008 przeniósł SA_NODEFER, SA_RESETHAND, SA_RESTART i SA_SIGINFO do głównej normy. Używanie tych nowych wartości sa_flags może być mniej przenośne w aplikacjach przewidzianych do użycia w starszych implementacjach Uniksa.
Znacznik SA_RESETHAND jest kompatybilny ze znacznikiem w SVr4 o tej samej nazwie.
Znacznik SA_NODEFER jest kompatybilny z podobnym znacznikiem z SVr4 dla Linuksa 1.3.9 i nowszych. Na starszych jądrach implementacja Linuksa pozwalała na otrzymanie dowolnego sygnału, nie tylko tego instalowanego (w praktyce przesłaniając ustawienie sa_mask).
Potomek utworzony przez fork(2) dziedziczy kopię ustawień sygnałów od swojego rodzica. Podczas wywołania execve(2) przywracane są wartości domyślne ustawień, z wyjątkiem ustawienia ignorowania sygnału, które nie jest zmieniane.
Zgodnie z POSIX, zachowanie procesu po zignorowaniu sygnału SIGFPE, SIGILL lub SIGSEGV, niewygenerowanego przez kill(2) lub raise(3), jest niezdefiniowane. Dzielenie liczby całkowitej przez zero ma wynik niezdefiniowany. Na niektórych architekturach generuje sygnał SIGFPE (także dzielenie najmniejszej ujemnej liczby całkowitej przez -1 może wygenerować SIGFPE). Ignorowanie go może prowadzić do nieskończonej pętli.
sigaction() może być wywoływany z drugim argumentem o wartości NULL, powodując w ten sposób zapytanie o bieżącą procedurę obsługi sygnału. Może go też użyć do sprawdzenia, czy dany sygnał jest prawidłowy na obecnej maszynie. W tym celu należy zarówno drugi, jak i trzeci argument ustawić na NULL.
Nie można zablokować sygnałów SIGKILL lub SIGSTOP (przez podanie ich w sa_mask). Próby takie zostaną zignorowane.
Zobacz sigsetops(3) dla szczegółów o operacjach na zbiorach sygnałów.
Listę funkcji, które są async-signal-safe i można je bezpiecznie wywołać w procedurze obsługi sygnału, można znaleźć w podręczniku signal-safety(7).
Przed wprowadzeniem SA_SIGINFO również było możliwe otrzymanie pewnych dodatkowych informacji o sygnale. Działo się to poprzez użycie procedury obsługi sygnału sa_handler z drugim argumentem, będącym typu struct sigcontext, który jest taką samą strukturą jak ta przekazywana w polu uc_mcontext struktury ucontext, przekazywanym (wskaźnikiem) w trzecim argumencie procedury obsługi sa_sigaction. Szczegóły można znaleźć w odpowiednich źródłach jądra Linux. To użycie jest obecnie przestarzałe.
Przy dostarczaniu sygnału za pomocą procedury obsługi SA_SIGINFO, jądro nie zawsze dostarcza przydatnych wartości we wszystkich polach siginfo_t, które są istotne dla danego sygnału.
Do Linuksa 2.6.13 włącznie, podanie SA_NODEFER w sa_flags zapobiegało maskowaniu nie tylko dostarczonego sygnału podczas wykonywania procedury obsługi sygnału, ale także sygnałów określonych w sa_mask. Ten błąd został poprawiony w Linuksie 2.6.14.
Patrz mprotect(2).
Poniższy przykładowy program wychodzi ze statusem EXIT_SUCCESS gdy sprawdzi, że SA_EXPOSE_TAGBITS jest obsługiwany albo EXIT_FAILURE w przeciwnym przypadku.
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void
handler(int signo, siginfo_t *info, void *context)
{
struct sigaction oldact;
if (sigaction(SIGSEGV, NULL, &oldact) == -1
|| (oldact.sa_flags & SA_UNSUPPORTED)
|| !(oldact.sa_flags & SA_EXPOSE_TAGBITS))
{
_exit(EXIT_FAILURE);
}
_exit(EXIT_SUCCESS);
}
int
main(void)
{
struct sigaction act = { 0 };
act.sa_flags = SA_SIGINFO | SA_UNSUPPORTED | SA_EXPOSE_TAGBITS;
act.sa_sigaction = &handler;
if (sigaction(SIGSEGV, &act, NULL) == -1) {
perror("sigaction");
exit(EXIT_FAILURE);
}
raise(SIGSEGV);
}
kill(1), kill(2), pause(2), pidfd_send_signal(2), restart_syscall(2), seccomp(2), sigaltstack(2), signal(2), signalfd(2), sigpending(2), sigprocmask(2), sigreturn(2), sigsuspend(2), wait(2), killpg(3), raise(3), siginterrupt(3), sigqueue(3), sigsetops(3), sigvec(3), core(5), signal(7)
Tłumaczenie niniejszej strony podręcznika: Przemek Borys <pborys@dione.ids.pl>, Robert Luberda <robert@debian.org> i Michał Kułach <michal.kulach@gmail.com>
Niniejsze tłumaczenie jest wolną dokumentacją. Bliższe informacje o warunkach licencji można uzyskać zapoznając się z GNU General Public License w wersji 3 lub nowszej. Nie przyjmuje się ŻADNEJ ODPOWIEDZIALNOŚCI.
Błędy w tłumaczeniu strony podręcznika prosimy zgłaszać na adres listy dyskusyjnej manpages-pl-list@lists.sourceforge.net.
| 2 maja 2024 r. | Linux man-pages 6.9.1 |