È possibile congelare temporaneamente un processo in Linux?


53

Mi chiedevo se c'è un modo per bloccare un processo per un certo periodo di tempo?

Quello che voglio dire è che: è possibile per un'applicazione (probabilmente in esecuzione come root) sospendere l'esecuzione di un altro processo già in esecuzione (qualsiasi processo, sia la GUI che la riga di comando) e poi riprenderlo in seguito? In altre parole, non voglio che determinati processi vengano programmati dallo scheduler di Linux per un certo periodo di tempo.

Risposte:


81

Vedi qui

Esistono due segnali che possono sospendere l'esecuzione di un processo. Uno è "aggraziato" e l'altro è "forte".

Quello "grazioso" è SIGTSTP, e il suo scopo è quello di "piacevolmente" chiedere al processo, se ne ha voglia, di sospendere l'esecuzione fino a quando non riceve un SIGCONT. Nel caso di SIGTSTP, il processo può ignorare SIGTSTP e continuare comunque l'esecuzione, quindi ciò richiede la cooperazione di un programma progettato per gestire SIGTSTP.

Quello "forte" è SIGSTOP, e il suo scopo è quello di sospendere tutti i thread dello spazio utente associati a quel processo. È altrettanto impossibile che il processo ignori SIGSTOPcome lo è ignorarlo SIGKILL(quest'ultimo uccide il processo con forza).

Per inviare un segnale arbitrario, compresa qualsiasi di quelli menzionati qui, è possibile utilizzare programmi come kill, killallo pkill; o usa la chiamata di sistema kill(2). Vedi le manpage del tuo sistema operativo per dettagli sulla piattaforma / architettura / dipendenti dalla versione ed errori relativi a quanto sopra. Si noti che la parola "kill" in tutti questi comandi e syscall è un termine improprio. Questi comandi non sono progettati, esclusivamente, per terminare i processi. Essi possono farlo inviando certuni dei segnali; ma i segnali possono anche essere usati per funzionalità diverse dalla conclusione di un processo. Ad esempio, SIGSTOPsospende solo il processo ed è solo uno dei numerosi segnali che possono essere inviati in questo modo.

Per aggiungere una condizione per riprendere automaticamente il processo dopo che è trascorso un periodo di tempo, sarà necessario utilizzare una sorta di processo di monitoraggio che rimane in esecuzione e imposta un timer per riattivare il processo di monitoraggio, che a sua volta chiama di kill(2)nuovo e invia il SIGCONTsegnale al processo arrestato, al fine di richiedere al kernel di riprendere l'esecuzione. Nota che Linux ha diversi meccanismi di temporizzazione con vari gradi di accuratezza e precisione; inoltre, se il tuo sistema è molto occupato, il tuo processo di monitoraggio potrebbe non essere attivato fino a quando il suo timer non è scaduto, e quindi la sveglia potrebbe essere ritardata.

Se si dipende da molto accurata precisione di sospensione e ripresa del processo di sospensione, potrebbe essere necessario eseguire il programma di monitoraggio con le autorizzazioni in tempo reale (si veda questa pagina di manuale su sched_setscheduler(2)per informazioni su come rendere il vostro processo in tempo reale). Puoi anche usare i timer ad alta risoluzione, una funzione del kernel Linux (che è disponibile solo se il tuo hardware fornisce supporto per loro), in combinazione con la pianificazione in tempo reale, per ottenere una precisione molto precisa, inferiore al millisecondo, sveglia e invia il segnale per riprendere il processo monitorato molto rapidamente.

Non hai indicato quali tecnologie sei disposto a utilizzare per implementarlo. Come minimo, avrai bisogno almeno degli script bash, anche se non sarai in grado di ottenere un tempismo molto preciso in quel modo. Ecco uno "script" bash (non testato, quindi fai attenzione) che è solo una prova del concetto della tua query. Se hai bisogno di un tempismo preciso, dovrai scrivere un programma, probabilmente in C / C ++ o in un'altra lingua nativa, e utilizzare la programmazione in tempo reale e hrtimer.

#!/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}"

Si noti che lo script terminerà e lo script di controllo verrà terminato, ma a causa del screencontrollo del processo di monitoraggio, continuerà a essere eseguito in background per 10 secondi (in base all'argomento passato a sleep), quindi riattivare e continuare il processo figlio. Ma questo passerà molto tempo dopo la fine dello script di controllo. Se si desidera attendere in modo sincrono il tempo che deve trascorrere, è sufficiente omettere la seconda chiamata screene codificare il sonno e uccidere nello script di controllo.

È possibile verificare che il processo si interrompa effettivamente eseguendo

screen -rS child

dopo aver avviato questo script. Non vedrai nulla sulla console. Quindi una volta scaduto il timer (10 secondi), inonderà lo schermo di dati base64 (caratteri casuali da 0-9 e AF). Premi Ctrl + C per uscire.


Ottima risposta molto completa incluso frammento di bash PoC. Bello!
fgysin,

Se un processo viene bloccato nel mezzo di una sessione di rete come una connessione TCP, quando viene continuato, la sessione di rete potrebbe essere danneggiata o interrotta? C'è un comportamento definito per questo?
CMCDragonkai

@cmcdragonkai perché poiché il processo interrotto non è in esecuzione, non può leggere o scrivere su alcun fd, ma il kernel continua a trasferire byte fino a quando il suo buffer non è pieno in una sessione TCP, cioè nessun trasferimento tra spazio del kernel e spazio utente. i processi di congelamento sono diversi controllare https://www.kernel.org/doc/Documentation/power/freezing-of-tasks.txt
Nizam Mohamed,

Ho scoperto che le connessioni TCP possono continuare dopo aver riportato il processo in primo piano (i timeout sono specifici dell'applicazione, c'è TCP keepalive ma anche keepalive a livello di applicazione). Processi di blocco, sembra significare quando il computer è in modalità di sospensione o sospensione. È giusto?
CMCDragonkai,

Questo script non ha effetto sui codici non cooperativi: gist.github.com/ceremcem/864dd94b52ffe7b18da29558df4f1f5b
ceremcem,

14

Sì, puoi farlo inviando un segnale di STOP a un processo per sospenderlo e quindi un CONT per continuare.

utilizzo:

kill -STOP <pid>

kill -CONT <pid>

11

Se hai una definizione sufficientemente libera di "blocco", puoi dare un'occhiata al renicecomando.

Renice consente di modificare la priorità di pianificazione dei processi in esecuzione.

Il normale valore di processo è 0. L'aumento del valore di valore rende il processo più piacevole, come in "perché non vai per primo". Diminuendo il valore piacevole, il processo diventa meno piacevole, come in "togliti di mezzo, sono di fretta". L'intervallo di valori è compreso tra -20 e 19.

Chiunque può rendere i propri processi più belli. Solo il root può rendere un processo meno piacevole o cambiare la gentilezza dei processi di un altro utente.

Se si imposta un buon valore di processi su 19, verrà eseguito solo quando nient'altro sul sistema lo desidera.

Ecco un esempio eseguito sul mio box Linux locale.

Utilizzare ps -le guardare la colonna NI per vedere un buon valore di processi.

-> ps -l
FS UID PID PPID C PRI NI ADDR SZ WCHAN TTY CMD
0 S 29190 402 31146 0 75 0 - 16547 attendere pts / 0 bash
0 T 29190 1105 402 0 75 0 - 23980 finitura punti / 0 vim
0 R 29190 794 402 0 76 0 - 15874 - punti / 0 ps

L'esecuzione renice +10sul processo vim provoca l'esecuzione con una priorità inferiore.

-> renice +10 -p 1105
1105: vecchia priorità 0, nuova priorità 10

-> ps -l
FS UID PID PPID C PRI NI ADDR SZ WCHAN TTY CMD
0 S 29190 402 31146 0 76 0 - 16547 attendere pts / 0 bash
0 T 29190 1105 402 0 95 10 - 23980 finitura punti / 0 vim
0 R 29190 1998 402 0 78 0 - 15874 - punti / 0 ps

Supponendo che si possa allungare "congelare" per significare "non disturbare nessun altro sul sistema", si potrebbe scrivere qualcosa come:

renice 20 -p <pid of interest>
sleep <certo periodo di tempo>
renice 0 -p <pid di interesse>

(ricorda di eseguirlo come root).


nota che ho preso alcune libertà con l' ps -loutput sopra per ottenere le colonne interessanti da mostrare bene nelle piccole caselle blu :)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.