Czy proces może zostać tymczasowo zamrożony w systemie Linux?

53

Zastanawiałem się, czy istnieje sposób na zablokowanie jakiegoś procesu na określony czas?

Mam na myśli to, że: czy jedna aplikacja (prawdopodobnie działająca jako root) może wstrzymać wykonywanie innego już uruchomionego procesu (dowolnego procesu, zarówno GUI, jak i wiersza poleceń), a następnie wznowić go później? Innymi słowy, nie chcę, aby niektóre procesy były planowane przez program planujący dla systemu Linux na określony czas.

Pal Szasz
źródło

Odpowiedzi:

81

Zobacz tutaj

Istnieją dwa sygnały, które mogą zawiesić wykonanie procesu. Jeden jest „pełen wdzięku”, a drugi „silny”.

Ten „pełen wdzięku” jest SIGTSTP, a jego celem jest „ładnie” poprosić proces, jeśli ma na to ochotę, o zawieszenie wykonania do czasu otrzymania SIGCONT. W takim przypadku SIGTSTPproces może zignorować SIGTSTP i kontynuować wykonywanie mimo to, więc wymaga to współpracy programu, który jest zaprojektowany do obsługi SIGTSTP.

„Mocny” jest SIGSTOP, a jego celem jest zawieszenie wszystkich wątków przestrzeni użytkownika powiązanych z tym procesem. Zignorowanie procesu jest tak samo niemożliwe, jak zignorowanie SIGSTOPgo SIGKILL(ten ostatni silnie zabija proces).

Aby wysłać dowolny sygnał, w tym każdy z wymienionymi tutaj, można korzystać z programów takich jak kill, killalllub pkill; lub użyj wywołania systemowego kill(2). Zobacz strony systemu operacyjnego, aby uzyskać szczegółowe informacje na temat platformy / architektury / wersji oraz erratę dotyczące któregokolwiek z powyższych. Zauważ, że słowo „zabij” we wszystkich tych poleceniach i wywołanie systemowe jest złym błędem. Te polecenia nie są przeznaczone wyłącznie do przerywania procesów. Mogą to zrobić, wysyłając określone sygnały; ale sygnały mogą być również wykorzystane do funkcji innych niż zakończenie procesu. Na przykład SIGSTOPtylko zawiesza proces i jest to tylko jeden z kilku sygnałów, które można wysłać w ten sposób.

Aby dodać warunek automatycznego wznawiania procesu po upływie określonego czasu, należy użyć pewnego rodzaju procesu monitorowania, który pozostaje uruchomiony i ustawia licznik czasu w celu wznowienia procesu monitorowania, który następnie z kolei wywołuje kill(2)ponownie i wysyła SIGCONTsygnał do zatrzymanego procesu, aby zażądać od jądra wznowienia wykonywania. Zauważ, że Linux ma kilka mechanizmów synchronizacji z różnymi stopniami dokładności i precyzji; ponadto, jeśli twój system jest bardzo zajęty, proces monitorowania może się nie obudzić, dopóki nie upłynie czas jego licznika, a zatem budzenie może się opóźnić.

Jeśli zależy na bardzo dokładną precyzją zawieszenia i wznowienia zawieszonego procesu, może być konieczne, aby uruchomić program z uprawnieniami do monitorowania w czasie rzeczywistym (patrz ten podręcznik na sched_setscheduler(2)informacje na temat dokonywania procesu w czasie rzeczywistym). Możesz także użyć Timerów o wysokiej rozdzielczości, funkcji jądra Linuksa (która jest dostępna tylko wtedy, gdy twój sprzęt zapewnia ich obsługę), w połączeniu z planowaniem w czasie rzeczywistym, aby uzyskać bardzo dokładną, poniżej milisekundową precyzję taktowania, a następnie Obudź się i wyślij sygnał, aby bardzo szybko wznowić monitorowany proces.

Nie wskazałeś, z których technologii chcesz skorzystać, aby to wdrożyć. Co najmniej będziesz potrzebował przynajmniej bashowych skryptów, chociaż nie będziesz w stanie uzyskać bardzo precyzyjnego timingu w ten sposób. Oto „skrypt” bashowy (niesprawdzony, więc bądź ostrożny), który jest tylko dowodem koncepcji twojego zapytania. Jeśli potrzebujesz dokładnego pomiaru czasu, będziesz musiał napisać program, prawdopodobnie w C / C ++ lub innym języku ojczystym, i używać harmonogramów w czasie rzeczywistym i hrtimerów.

#!/bin/bash
#This is the process you want to suspend.
screen -mdS child bash -c "cat /dev/urandom | base64"
#This is the process ID of the child process
THEPID=$(screen -list | grep child | cut -f1 -d'.' | sed 's/\W//g')
#Send SIGSTOP to the child process.
kill -SIGSTOP ${THEPID}
#Now it is suspended. This process will sleep for 10 seconds asynchronously, then resume the process.
screen -mdS monitor bash -c "sleep 10; kill -SIGCONT ${THEPID}"

Zauważ, że skrypt zakończy się, a skrypt kontrolny zakończy się, ale ze względu na screenkontrolowanie procesu monitorowania, będzie on nadal działał w tle przez 10 sekund (na podstawie przekazanego argumentu sleep), a następnie obudzi się i będzie kontynuował proces potomny. Ale to potrwa długo po zakończeniu skryptu sterującego. Jeśli chcesz synchronicznie czekać na upływ czasu, po prostu pomiń drugie wywołanie screeni zakoduj uśpienie i zabij do skryptu sterującego.

Możesz sprawdzić, czy proces faktycznie zawiesił się, uruchamiając

screen -rS child

po uruchomieniu tego skryptu. Nic nie zobaczysz na konsoli. Następnie, po upływie czasu (10 sekund), ekran zostanie zalany danymi base64 (losowe znaki od 0-9 i AF). Naciśnij Ctrl + C, aby wyjść.

allquixotic
źródło
Bardzo dobra bardzo kompletna odpowiedź, w tym fragment bash PoC. Miły!
fgysin
Jeśli proces zostanie zawieszony w trakcie sesji sieciowej, jak połączenie TCP, to kiedy będzie kontynuowany, czy sesja sieciowa może zostać uszkodzona lub zerwana? Czy jest to określone zachowanie?
CMCDragonkai
@cmcdragonkai, ponieważ ponieważ zatrzymany proces nie jest uruchomiony, nie może czytać ani zapisywać na żadnym fd, ale jądro przesyła bajty, dopóki bufor nie zapełni się w sesji TCP, tzn. nie ma transferu między przestrzenią jądra a przestrzenią użytkownika. Procesy zamrażania są inne, sprawdź https://www.kernel.org/doc/Documentation/power/freezing-of-tasks.txt
Nizam Mohamed
Przekonałem się, że połączenia TCP mogą być kontynuowane po przeniesieniu procesu z powrotem na pierwszy plan (limity czasu są specyficzne dla aplikacji, istnieje utrzymywanie TCP, ale także utrzymywanie poziomu aplikacji). Procesy zamrażania wydają się oznaczać, gdy komputer znajduje się w trybie hibernacji lub uśpienia. Czy to prawda?
CMCDragonkai
Ten skrypt nie ma wpływu na kody niewspółpracujące: gist.github.com/ceremcem/864dd94b52ffe7b18da29558df4f1f5b
ceremonie
14

Tak, możesz to zrobić, wysyłając sygnał STOP do procesu, aby go zawiesić, a następnie CONT, aby kontynuować.

stosowanie:

kill -STOP <pid>

kill -CONT <pid>

źródło
11

Jeśli masz odpowiednio luźną definicję „zamrożenia”, możesz sprawdzić renicepolecenie.

Renice pozwala zmienić priorytet planowania uruchomionych procesów.

Normalna wartość ładna procesu wynosi 0. Zwiększenie wartości miłej powoduje, że proces jest ładniejszy, jak w „dlaczego nie zaczynasz”. Zmniejszenie wartości przyjemnej powoduje, że proces jest mniej przyjemny, ponieważ „zejdź mi z drogi, spieszy mi się”. Dobry zakres wartości wynosi od -20 do 19.

Każdy może uprzyjemnić swoje procesy. Tylko root może sprawić, że proces będzie mniej przyjemny lub zmienić upodobania innych użytkowników.

Jeśli ustawisz wartość Nicei na 19, uruchomi się ona tylko wtedy, gdy nic innego w systemie nie będzie tego chciało.

Oto przykład działający na moim lokalnym systemie Linux.

Użyj ps -li spójrz na kolumnę NI, aby zobaczyć dobrą wartość procesów.

-> ps -l
FS UID PID PPID C PRI NI ADDR SZ WCHAN TTY CMD
0 S 29190 402 31146 0 75 0 - 16547 czekać pkt / 0 uderzenia
0 T 29190 1105 402 0 75 0 - 23980 wykończenie pkt / 0 vim
0 R 29190 794 402 0 76 0 - 15874 - pkt / 0 ps

Uruchamianie renice +10procesu vim powoduje, że działa on z niższym priorytetem.

-> renice +10 -p 1105
1105: stary priorytet 0, nowy priorytet 10

-> ps -l
FS UID PID PPID C PRI NI ADDR SZ WCHAN TTY CMD
0 S 29190 402 31146 0 76 0 - 16547 czekać pkt / 0 uderzenia
0 T 29190 1105 402 0 95 10 - 23980 wykończenie pkt / 0 vim
0 R 29190 1998 402 0 78 0 - 15874 - pkt / 0 ps

Zakładając, że możesz rozciągnąć „zamrożenie”, co oznacza „nie przeszkadzać innym osobom w systemie”, możesz napisać coś takiego:

renice 20 -p <pid of interest>
spać <określony czas>
renice 0 -p <pid of interest>

(pamiętaj, aby uruchomić go jako root).


zwróć uwagę, że skorzystałem z pewnych wolności z powyższym ps -lwyjściem, aby uzyskać interesujące kolumny, które ładnie wyświetlą się w małych niebieskich polach :)

Maurice
źródło