Jak rozpocząć proces w stanie zawieszenia w systemie Linux?

19

Praktycznie potrzebuję procesu, który zachowuje się tak, jakbym naciskał Ctrl+Zzaraz po jego rozpoczęciu.

Mamy nadzieję, że można to zrobić za pomocą skryptu powłoki.

(Wiedząc, że wynikowy PID byłby świetny, żebym mógł kontynuować proces później).

java.is.for.desktop
źródło

Odpowiedzi:

7

Po rozpoczęciu procesu możesz wysłać go do SIGSTOP, aby go zawiesić. Aby wznowić, wyślij SIGCONT. Myślę, że ten mały skrypt może ci pomóc

#!/bin/bash
$@ &
PID=$!
kill -STOP $PID
echo $PID
wait $PID

Uruchamia proces (polecenie wyślij jako parametr), zawiesza go, drukuje identyfikator procesu i czeka na zakończenie.

promienisty
źródło
1
Zmodyfikowałem go, aby kontynuować na końcu: [enter] #!/bin/bash [enter] $@ & [enter] PID=$! [enter] kill -STOP $PID [enter] echo "Suspended: $PID, press ENTER to continue it" [enter] read [enter] kill -CONT $PID [enter] wait $PID [enter]echo
java.is.for.desktop
7
Właśnie dlatego wiesz, że podproces może zakończyć się, zanim zdążysz wysłać do niego sygnał STOP.
MikeyB,
16
Kolejny dzień na wyścigach.
ctrl-alt-delor
23

Z jakiego środowiska tworzysz proces?

Jeśli robisz to ze środowiska takiego jak kod C, możesz rozwidlić (), a następnie w dziecku wysłać do siebie SIGSTOP przed exec (), uniemożliwiając dalsze wykonanie.

Bardziej ogólnym rozwiązaniem (prawdopodobnie najlepszym) byłoby utworzenie kodu pośredniczącego, który to robi. Zatem program pośredniczący:

  • Weź argumenty składające się z prawdziwej nazwy programu i argumentów
  • wyślij do siebie SIGSTOP
  • exec () prawdziwy program z odpowiednimi argumentami

Zapewni to, że unikniesz jakichkolwiek warunków wyścigowych związanych z zbyt dużym wyprzedzeniem nowego przetwarzania, zanim będziesz mógł wysłać do niego sygnał.


Przykład dla powłoki:

#!/bin/bash
kill -STOP $$
exec "$@"

I używając powyższego kodu:

michael@challenger:~$ ./stopcall.sh ls -al stopcall.sh

[1]+  Stopped                 ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ jobs -l
[1]+ 23143 Stopped (signal)        ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ kill -CONT 23143; sleep 1
-rwxr-xr-x 1 michael users 36 2011-07-24 22:48 stopcall.sh
[1]+  Done                    ./stopcall.sh ls -al stopcall.sh
michael@challenger:~$ 

jobs -lPokazuje PID. Ale jeśli robisz to z powłoki, nie potrzebujesz bezpośrednio PID. Możesz po prostu: kill -CONT %1(zakładając, że masz tylko jedną pracę).

Robisz to z więcej niż jedną pracą? Pozostawiono jako ćwiczenie dla czytelnika :)

MikeyB
źródło
Miałem nadzieję to zrobić ze skryptu powłoki ...
java.is.for.desktop
Świetnie, więc ponieważ chcesz to zrobić ze skryptu powłoki, użyj programu pośredniczącego.
MikeyB,
20

Odpowiedź MikeyB jest poprawna. Od tego pytania na temat superużytkownika, oto bardziej zwięzła wersja:

( kill -SIGSTOP $BASHPID; exec my_command ) &

Aby to zrozumieć, należy zrozumieć, w jaki sposób procesy są uruchamiane w execsystemie uniksowym: wywołanie systemowe zastępuje aktualnie działający program nowym , zachowując istniejący PID. Więc drodze niezależny proces jest tworzony jest pierwszy fork, a następnie exec, zastępując program uruchomiony w procesie potomnym z żądanego programu.

Składniki tego polecenia powłoki to:

  1. Nawiasy (...)rozpoczynają podpowłokę: kolejne wystąpienie BASH.
  2. killKomenda wysyła sygnał STOP, aby ten proces, co stawia go w stanie zawieszenia.
  3. Gdy tylko zezwolisz na kontynuowanie procesu (wysyłając mu CONTsygnał), execpolecenie powoduje, że zamienia się ono na żądany program. my_commandzachowuje oryginalny PID podpowłoki.
  4. Możesz użyć tej $!zmiennej, aby uzyskać PID procesu.
nibot
źródło
2
Podoba mi się ten, ponieważ jest zasadniczo poprawny (tyle, że musiałem go użyć -s STOPzamiast -SIGSTOP). Wciąż zastanawiam się, dlaczego to musi być $BASHPIDzamiast $$? (Może naprawdę nie rozumiem różnicy).
Hibou57
1
Dla $$vs $BASHPIDsprawdzam, że ten ostatni to PID podpowłoki, a nie ten pierwszy. Jest zabawny problem: zastosowanie końcówki w skrypcie bash najczęściej kończy się niepowodzeniem, a ja muszę zrobić coś takiego: PID=$!; ps -p $PID; kill -s CONT $PID;… kończy się niepowodzeniem, jeśli usunę ps -p $PIDczęść: proces wydaje się zniknąć (zabity?) Bez nigdzie komunikatu o błędzie . Z interaktywnej powłoki jest OK, problem pochodzi tylko ze skryptu. To zbyt tajemnicze.
Hibou57
Próbowałem użyć tego rozwiązania do wyświetlenia listy deskryptorów plików mojej komendy. ( goo.gl/cNbUE8 ), ale deskryptory są nadal takie same, bez względu na to, co to moja komenda.
rasty.g
Aby zobaczyć opcje zamiany $BASHPIDna pociski inne niż bash, zobacz tutaj
Jakob