Qu'est ce qu'un sans coupure processus?
Parfois, chaque fois que j'écris un programme sous Linux et qu'il se bloque à cause d'un bug, il devient un processus ininterrompu et continue à fonctionner pour toujours jusqu'à ce que je redémarre mon ordinateur (même si je me déconnecte). Mes questions sont:
- Qu'est-ce qui fait qu'un processus devient ininterrompu?
- Comment puis-je empêcher que cela se produise?
- C'est probablement une question stupide, mais est-il possible de l'interrompre sans redémarrage de mon ordinateur?
6 réponses
Un processus ininterrompu est un processus qui se trouve être dans un appel système (fonction du noyau) qui ne peut pas être interrompu par un signal.
Pour comprendre ce que cela signifie, Vous devez comprendre le concept d'un appel système interruptable. L'exemple classique est read()
. Il s'agit d'un appel système qui peut prendre beaucoup de temps (secondes) car il peut potentiellement impliquer la rotation d'un disque dur ou des têtes mobiles. Pendant la plupart de ce temps, le processus sera en sommeil, bloquant sur le matériel.
Pendant que le processus dort dans l'appel système, il peut recevoir un signal asynchrone unix (par exemple, SIGTERM), alors ce qui suit se produit:
- les appels système se terminent prématurément et sont configurés pour retourner-EINTR dans l'espace utilisateur.
- Le gestionnaire de signal est exécuté.
- si le processus est toujours en cours d'exécution, il obtient la valeur de retour de l'appel système, et il peut faire le même appel à nouveau.
Le retour anticipé de l'appel système permet à l'utilisateur code spatial pour modifier immédiatement son comportement en réponse au signal. Par exemple, se terminant proprement en réaction à SIGINT ou SIGTERM.
D'autre part, certains appels système ne peuvent pas être interrompus de cette manière. Si le système appelle des stands pour une raison quelconque, le processus peut rester indéfiniment dans cet état inkillable.
LWN a publié un bel article {[21] } qui a touché ce sujet en juillet.
Pour répondre à la question initiale:
Comment empêchez cela de se produire: déterminez quel pilote vous cause des problèmes, et arrêtez d'utiliser, ou devenez un pirate du noyau et corrigez-le.
Comment tuer un processus ininterrompu sans redémarrer: faire en sorte que l'appel système se termine. Souvent la manière la plus efficace de le faire sans frapper l'interrupteur d'alimentation est de tirer le cordon d'alimentation. Vous pouvez également devenir un pirate du noyau et faire en sorte que le pilote utilise TASK_KILLABLE, comme expliqué dans l'article LWN.
Lorsqu'un processus est en mode utilisateur, il peut être interrompu à tout moment (passage en mode noyau). Lorsque le noyau renvoie au mode utilisateur, il vérifie s'il y a des signaux en attente (y compris ceux qui sont utilisés pour tuer le processus, tels que SIGTERM
et SIGKILL
). Cela signifie qu'un processus ne peut être tué qu'au retour en mode utilisateur.
La raison pour laquelle un processus ne peut pas être tué en mode noyau est qu'il pourrait potentiellement corrompre les structures du noyau utilisées par tous les autres processus dans le même machine (de la même manière tuer un thread peut potentiellement corrompre les structures de données utilisées par d'autres threads dans le même processus).
Lorsque le noyau a besoin de faire quelque chose qui pourrait prendre beaucoup de temps (attendre sur un tuyau écrit par un autre processus ou attendre que le matériel fasse quelque chose, par exemple), il dort en se marquant comme sleeping et en appelant le planificateur pour passer à un autre processus (s'il n'y a pas de processus non-sleeping, ralentir un peu et se trouve dans une boucle de la boucle d'inactivité).
Si un signal est envoyé à un processus en veille, il doit être réveillé avant qu'il ne retourne dans l'espace utilisateur et traite ainsi le signal en attente. Ici, nous avons la différence entre les deux principaux types de sommeil:
-
TASK_INTERRUPTIBLE
, le sommeil interruptible. Si une tâche est marquée avec ce drapeau, elle dort, mais peut être réveillée par des signaux. Cela signifie que le code qui a marqué la tâche comme dormant attend un signal possible, et après wakes up vérifiera et reviendra de l'appel système. Une fois le signal traité, l'appel système peut potentiellement être redémarré automatiquement (et je n'entrerai pas dans les détails sur la façon dont cela fonctionne). -
TASK_UNINTERRUPTIBLE
, le sommeil ininterrompu. Si une tâche est marqué avec ce drapeau, il n'attend pas d'être réveillé par rien d'autre que ce qu'il attend, soit parce qu'il ne peut pas facilement être redémarré, ou parce que les programmes attendons l'appel système atomique. Cela peut également être utilisé pour dort connu pour être très court.
TASK_KILLABLE
(mentionné dans l'article LWN lié à la réponse de ddaa) est une nouvelle variante.
Ceci répond à votre première question. En ce qui concerne votre deuxième question: vous ne pouvez pas éviter les sleeps ininterrompus, ils sont une chose normale (cela arrive, par exemple, chaque fois qu'un processus lit/écrit depuis/vers le disque); cependant, ils ne devraient durer qu'une fraction de seconde. Si elles durent beaucoup plus longtemps, cela signifie généralement un problème matériel (ou un pilote de périphérique problème, qui ressemble au noyau), où le pilote de périphérique attend que le matériel fasse quelque chose qui n'arrivera jamais. Cela peut également signifier que vous utilisez NFS et que le serveur NFS est en panne (il attend que le serveur récupère; vous pouvez également utiliser l'option" intr " pour éviter le problème).
Enfin, la raison pour laquelle vous ne pouvez pas récupérer est la même raison pour laquelle le noyau attend le retour en mode utilisateur pour délivrer un signal ou tuer le processus: cela pourrait corrompre les données du noyau structures (le code en attente sur un sommeil interruptible peut recevoir une erreur qui lui indique de retourner dans l'espace utilisateur, où le processus peut être tué; le code en attente sur un sommeil ininterrompu n'attend aucune erreur).
Les processus ininterrompus attendent généralement des E / S suite à une erreur de page.
Considérez ceci:
- le thread essaie d'accéder à une page qui n'est pas dans le noyau (soit un exécutable qui est chargé à la demande, une page de mémoire anonyme qui a été échangée, ou un fichier mmap ()'D qui est chargé à la demande, qui sont à peu près la même chose)
- Le noyau est maintenant (en train de) le charger dans
- le processus ne peut pas continuer tant que la page n'est pas disponible.
Le le processus / tâche ne peut pas être interrompu dans cet état, car il ne peut gérer aucun signal; si c'était le cas, une autre erreur de page se produirait et elle serait de retour là où elle se trouvait.
Quand je dis "processus", je veux vraiment dire "tâche", qui sous Linux (2.6) se traduit à peu près par "thread" qui peut ou non avoir une entrée individuelle de "groupe de threads" dans /proc
Dans certains cas, il peut attendre longtemps. Un exemple typique de ceci serait où le fichier exécutable ou mmap D est sur un réseau système de fichiers où le serveur a échoué. Si l'E / S réussit finalement, la tâche continuera. Si elle échoue finalement, la tâche obtiendra généralement un SIGBUS ou quelque chose.
Est-il possible qu'un programme puisse être écrit pour initier un processus qui passe dans un état TASK_UNINTERUPTIBLE
chaque fois que le système n'est pas dans un état inactif, collectant ainsi de force des données, en attendant de transmettre une fois le super utilisateur quitte? Ce serait une mine d'or pour les pirates pour récupérer des informations, revenir à l'état zombie, et transmettre des informations via le réseau au ralenti. Certains peuvent faire valoir que c'est une façon de créer un Blackdoor
pour les pouvoirs qui sont, pour entrer et sortir de n'importe quel système comme désiré. Je je crois fermement que cette échappatoire peut être scellée pour de bon, en éliminant l'état TASK_UNINTERUPTIBLE
.
Je vois cela comme un problème de sécurité grave mais subtile pour les systèmes Linux, qui ont une réputation de sécurité, grâce à l'autonomisation du super utilisateur. Je travaille ma façon de devenir un pirate du noyau, cependant, je pense qu'il y a des pirates du noyau là-bas qui peuvent résoudre cette débâcle.
À votre 3ème question:
Je pense que vous pouvez tuer les processus ininterrompus en exécutant
sudo kill -HUP 1
.
Il redémarrera init sans mettre fin aux processus en cours d'exécution et après l'avoir exécuté, mes processus ininterrompus ont disparu.
Si vous parlez d'un processus "zombie" (qui est désigné comme "zombie" dans la sortie ps), alors il s'agit d'un enregistrement inoffensif dans la liste des processus qui attend que quelqu'un récupère son code de retour et il pourrait être ignoré en toute sécurité.
Pourriez-vous décrire ce que et "processus ininterrompu" est pour vous? Est-ce qu'il survit au "kill -9" et chugs heureusement le long? Si c'est le cas, alors il est coincé sur certains syscall, qui est coincé dans un conducteur, et vous êtes coincé avec ce processus jusqu'à redémarrez (et parfois il est préférable de redémarrer bientôt) ou le déchargement du pilote pertinent (ce qui est peu probable). Vous pouvez essayer d'utiliser "strace" pour savoir où votre processus est bloqué et l'éviter à l'avenir.