Un processus peut-il être gelé temporairement sous Linux?

53

Je me demandais s'il y avait un moyen de geler un processus pendant un certain temps?

Ce que je veux dire, c'est que: est-il possible pour une application (fonctionnant probablement en tant que root) de suspendre l'exécution d'un autre processus en cours d'exécution (n'importe quel processus, à la fois l'interface graphique et la ligne de commande), puis de le reprendre plus tard? En d'autres termes, je ne souhaite pas que certains processus soient planifiés par le planificateur Linux pendant un certain temps.

Pal Szasz
la source

Réponses:

81

Voir ici

Il y a deux signaux qui peuvent suspendre l'exécution d'un processus. On est "gracieux", et on est "force".

Le "gracieux" est SIGTSTP, et son but est de "gentiment" demander au processus, s'il en a envie, de bien vouloir suspendre l'exécution jusqu'à ce qu'il reçoive un SIGCONT. Dans le cas de SIGTSTP, le processus peut ignorer SIGTSTP et continuer à exécuter de toute façon. Cela nécessite donc la coopération d'un programme conçu pour gérer SIGTSTP.

Le "forceful" est SIGSTOP, et son but est de suspendre tous les threads de l'espace utilisateur associés à ce processus. Il est tout aussi impossible pour le processus d’ignorer SIGSTOPque pour lui SIGKILL(le dernier tue le processus avec force).

Pour envoyer un signal arbitraire, y compris de ceux mentionnés ici, vous pouvez utiliser des programmes tels que kill, killallou pkill; ou utilisez l'appel système kill(2). Consultez les pages de manuel de votre système d'exploitation pour connaître les détails relatifs à la plate-forme / architecture / version et les errata concernant ce qui précède. Notez que le mot "tuer" dans toutes ces commandes et l'appel système est un mauvais nom impropre. Ces commandes ne sont pas conçues exclusivement pour mettre fin à des processus. Ils peuvent le faire en envoyant certains signaux. mais les signaux peuvent également être utilisés pour des fonctionnalités autres que la fin d'un processus. Par exemple, SIGSTOPseul le processus est suspendu et il ne s'agit que d'un des nombreux signaux pouvant être envoyés de cette façon.

Pour ajouter une condition de reprise automatique du processus une fois le délai écoulé, vous devez utiliser une sorte de processus de surveillance qui reste en cours d'exécution et définit un temporisateur afin de réactiver le processus de surveillance, qui appelle ensuite à kill(2)nouveau et envoie le SIGCONTsignal au processus arrêté, afin de demander au noyau de reprendre l'exécution. Notez que Linux possède plusieurs mécanismes de synchronisation avec différents degrés de précision et de précision. de plus, si votre système est très occupé, votre processus de surveillance risque de ne pas être réveillé bien après l'expiration de son délai, ce qui risque de retarder le réveil.

Si vous comptez sur une précision très précise de la suspension et de la reprise du processus suspendu, vous devrez peut-être exécuter votre programme de surveillance avec des autorisations en temps réel ( pour plus d'informations sur la manière de rendre votre processus en temps réel, reportez-vous à cette page de manuelsched_setscheduler(2) .) Vous pouvez également utiliser les temporisateurs haute résolution, une fonctionnalité du noyau Linux (disponible uniquement si votre matériel les prend en charge), en combinaison avec la planification en temps réel, pour obtenir une précision très précise, inférieure à la milliseconde, réveillez-vous et envoyez le signal pour reprendre très rapidement le processus surveillé.

Vous n'avez pas indiqué les technologies que vous êtes prêt à utiliser pour mettre cela en œuvre. Au minimum, vous aurez besoin d'au moins script bash, bien que vous ne puissiez pas obtenir un minutage très précis de cette façon. Voici un "script" bash (non testé, donc soyez prudent) qui est juste une preuve de concept de votre requête. Si vous avez besoin d'un timing précis, vous devrez écrire un programme, probablement en C / C ++ ou dans un autre langage natif, et utiliser la planification en temps réel et les horloges hr.

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

Notez que le script se terminera et que le script de contrôle se terminera, mais en raison du screencontrôle du processus de contrôle, il continuera à s'exécuter en arrière-plan pendant 10 secondes (en fonction de l'argument transmis à sleep), puis réveillera et poursuivra le processus enfant. Mais ce sera longtemps après la fin du script de contrôle. Si vous souhaitez attendre que le temps s'écoule de manière synchrone, il suffit d'omettre le deuxième appel screenet de coder de manière irréversible les méthodes veille et destruction dans le script de contrôle.

Vous pouvez tester que le processus est effectivement suspendu en exécutant

screen -rS child

après avoir démarré ce script. Vous ne verrez rien sur la console. Ensuite, une fois le délai écoulé (10 secondes), votre écran sera inondé de données base64 (caractères aléatoires de 0 à 9 et AF). Appuyez sur Ctrl + C pour quitter.

allquixotic
la source
Très bonne réponse très complète, y compris un extrait de PoC bash. Agréable!
fgysin
Si un processus est gelé au milieu d'une session réseau, comme une connexion TCP, cette session réseau peut-elle être corrompue ou abandonnée? Y at-il un comportement défini pour cela?
CMCDragonkai
@cmcdragonkai car, en tant que processus arrêté ne fonctionnant pas, il ne peut lire ni écrire dans aucun fd, mais le noyau continue à transférer des octets jusqu'à ce que sa mémoire tampon soit pleine dans une session TCP, c'est-à-dire qu'aucun transfert entre l'espace du noyau et l'espace utilisateur. processus de gel est différent vérifier https://www.kernel.org/doc/Documentation/power/freezing-of-tasks.txt
Nizam Mohamed
J'ai constaté que les connexions TCP peuvent continuer après avoir ramené le processus au premier plan (les délais d'attente sont spécifiques à l'application, il y a TCP Keepalive mais également au niveau de l'application). Les processus de congélation semblent signifier que l'ordinateur est en mode veille ou en veille prolongée. Est-ce correct?
CMCDragonkai le
Ce script n'a aucun effet sur les codes non coopératifs: gist.github.com/ceremcem/864dd94b52ffe7b18da29558df4f1f5b
ceremcem
14

Oui, vous pouvez le faire en envoyant un signal STOP à un processus pour le suspendre, puis un CONT pour continuer.

usage:

kill -STOP <pid>

kill -CONT <pid>

la source
11

Si vous avez une définition assez souple de "geler", vous pouvez vérifier la renicecommande.

Renice vous permet de modifier la priorité de planification des processus en cours d'exécution.

La valeur normale du processus normal est 0. L'augmentation de cette valeur rend le processus plus agréable, comme dans "Pourquoi ne pas y aller en premier". Tout en diminuant le rapport qualité-prix, le processus est moins agréable, comme dans «Ne me dérange pas, je suis pressé». La plage de valeur est comprise entre -20 et 19.

Tout le monde peut rendre ses processus plus agréables. Seul root peut rendre un processus moins agréable ou changer la gentillesse des processus d'un autre utilisateur.

Si vous définissez une valeur de processus agréable sur 19, celle-ci ne fonctionnera que si rien d'autre ne le souhaite.

Voici un exemple exécuté sur ma boîte Linux locale.

Utilisez ps -let regardez la colonne NI pour voir une valeur de traitement des processus.

-> ps -l
PID UID FS PPID C ADDITIF PRIVE SZ WCHAN ATS CMD
0 S 29190 402 31146 0 75 0 - 16547 wait pts / 0 bash
0 T 29190 1105 402 0 75 0 - 23980 pts d'arrivée / 0 vim
0 R 29190 794 402 0 76 0 - 15874 - pts / 0 ps

L'exécution renice +10sur le processus vim entraîne son exécution avec une priorité inférieure.

-> renice +10 -p 1105
1105: ancienne priorité 0, nouvelle priorité 10

-> ps -l
PID UID FS PPID C ADDITIF PRIVE SZ WCHAN ATS CMD
0 S 29190 402 31146 0 76 0 - 16547 wait pts / 0 bash
0 T 29190 1105 402 0 95 10 - 23980 pts d'arrivée / 0 vim
0 R 29190 1998 402 0 78 0 - 15874 - pts / 0 ps

En supposant que vous puissiez étirer le terme "freeze" pour signifier "ne déranger personne d'autre sur le système", vous pouvez écrire quelque chose comme:

renice 20 -p <pid d’intérêt>
dormir <certain temps>
renice 0 -p <pid d’intérêt>

(n'oubliez pas de l'exécuter en tant que root).


Notez que j'ai pris quelques libertés avec la ps -lsortie ci-dessus pour que les colonnes intéressantes apparaissent bien dans les petites cases bleues :)

Maurice
la source