Gdy proces jest w trybie użytkownika, można go przerwać w dowolnym momencie (przełączenie do trybu jądra). Kiedy jądro powraca do trybu użytkownika, sprawdza, czy są jakieś oczekujące sygnały (w tym te, które są używane do zabicia procesu, takie jak SIGTERM
i SIGKILL
). Oznacza to, że proces można zabić tylko po powrocie do trybu użytkownika.
Powodem, dla którego procesu nie można zabić w trybie jądra, jest to, że może on potencjalnie uszkodzić struktury jądra używane przez wszystkie inne procesy na tej samej maszynie (w ten sam sposób zabicie wątku może potencjalnie uszkodzić struktury danych używane przez inne wątki w tym samym procesie) .
Kiedy jądro musi zrobić coś, co może zająć dużo czasu (na przykład czekając na potok napisany przez inny proces lub czekając, aż sprzęt coś zrobi), zasypia, oznaczając siebie jako śpiącego i wywołując harmonogram, aby przełączył się na inny proces (jeśli nie ma procesu, który nie jest uśpiony, przełącza się na proces „fikcyjny”, który mówi procesorowi, aby nieco zwolnił i siedzi w pętli - pętli bezczynności).
Jeśli sygnał jest wysyłany do procesu uśpienia, należy go obudzić, zanim powróci do przestrzeni użytkownika, a tym samym przetworzy oczekujący sygnał. Tutaj mamy różnicę między dwoma głównymi rodzajami snu:
TASK_INTERRUPTIBLE
, przerywany sen. Jeśli zadanie jest oznaczone tą flagą, śpi, ale można je obudzić sygnałami. Oznacza to, że kod, który oznaczył zadanie jako uśpione oczekuje na możliwy sygnał, a po przebudzeniu sprawdzi go i wróci z wywołania systemowego. Po obsłużeniu sygnału wywołanie systemowe może zostać automatycznie ponownie uruchomione (i nie będę wchodził w szczegóły, jak to działa).
TASK_UNINTERRUPTIBLE
, nieprzerwany sen. Jeśli zadanie jest oznaczone tą flagą, nie spodziewa się, że zostanie obudzone przez coś innego niż to, na co czeka, ponieważ nie można go łatwo ponownie uruchomić lub programy oczekują, że wywołanie systemowe będzie atomowe. Można to również wykorzystać do snu, o którym wiadomo, że jest bardzo krótki.
TASK_KILLABLE
(wspomniany w artykule LWN, do którego prowadzi odpowiedź ddaa) to nowy wariant.
To odpowiada na twoje pierwsze pytanie. A co do drugiego pytania: nie da się uniknąć nieprzerywalnych uśpień, są one normalne (zdarza się na przykład za każdym razem, gdy proces czyta / zapisuje z / na dysk); jednak powinny trwać tylko ułamek sekundy. Jeśli trwają znacznie dłużej, zwykle oznacza to problem sprzętowy (lub problem ze sterownikiem urządzenia, który wygląda tak samo dla jądra), w którym sterownik urządzenia czeka, aż sprzęt wykona coś, co nigdy się nie wydarzy. Może to również oznaczać, że używasz NFS i serwer NFS jest wyłączony (czeka na przywrócenie serwera; możesz także użyć opcji „intr”, aby uniknąć problemu).
Wreszcie powodem, dla którego nie można odzyskać, jest ten sam powód, dla którego jądro czeka na powrót do trybu użytkownika, aby dostarczyć sygnał lub zabić proces: mogłoby to potencjalnie uszkodzić struktury danych jądra (kod oczekujący na przerwanie uśpienia może otrzymać błąd, który mówi mu aby powrócić do przestrzeni użytkownika, gdzie proces może zostać zabity; kod oczekujący na nieprzerywany tryb uśpienia nie oczekuje żadnego błędu).
TASK_UNINTERUPTIBLE
stan, gdy system nie jest w stanie bezczynności, zbierając w ten sposób na siłę dane i czekając na przesłanie, gdy superużytkownik wyjdzie? Byłaby to kopalnia złota dla hakerów do pobierania informacji, powrotu do stanu zombie i przesyłania informacji przez sieć w trybie bezczynności. Niektórzy mogą argumentować, że jest to jeden ze sposobów tworzeniaBlackdoor
uprawnień, które są, aby wchodzić i wychodzić z dowolnego systemu zgodnie z życzeniem. Jestem głęboko przekonany, że tę lukę można zapieczętować na dobre, eliminując `` TASK_UNINTERUPTIB