Que doivent faire les shells interactifs dans les groupes de processus orphelins?

10

(Nouvelle publication sous Unix selon la suggestion de /programming/13718394/what-should-interactive-shells-do-in-orphaned-process-groups )

La courte question est, que doit faire un shell s'il se trouve dans un groupe de processus orphelin qui ne possède pas le tty? Mais je recommande de lire la longue question car c'est amusant.

Voici une façon amusante et passionnante de transformer votre ordinateur portable en radiateur portatif, en utilisant votre coque préférée (à moins que vous ne soyez un de ces bizarres tcsh):

#include <unistd.h>   
int main(void) {
    if (fork() == 0) {
        execl("/bin/bash", "/bin/bash", NULL);
    }
    return 0;
}

Cela amène bash à fixer le CPU à 100%. zsh et fish font de même, tandis que ksh et tcsh marmonnent quelque chose à propos du contrôle des tâches, puis quille, ce qui est un peu mieux, mais pas beaucoup. Oh, et c'est un contrevenant indépendant de la plate-forme: OS X et Linux sont tous deux touchés.

Mon (potentiellement mauvais) explication est la suivante: la coquille de l' enfant détecte qu'il est pas au premier plan: tcgetpgrp(0) != getpgrp(). Par conséquent , il essaie de s'arrêter: killpg(getpgrp(), SIGTTIN). Mais son groupe de processus est orphelin, car son parent (le programme C) était le leader et est décédé, et SIGTTINenvoyé à un groupe de processus orphelin est juste abandonné (sinon rien ne pourrait le redémarrer). Par conséquent, le shell enfant n'est pas arrêté, mais il est toujours en arrière-plan, il recommence donc tout de suite. Rincez et répétez.

Ma question est, comment un shell de ligne de commande peut-il détecter ce scénario, et quelle est la bonne chose à faire? J'ai deux solutions, dont aucune n'est idéale:

  1. Essayez de signaler le processus dont le pid correspond à notre ID de groupe. Si cela échoue ESRCH, cela signifie que nous sommes probablement orphelins.
  2. Essayez une lecture non bloquante d'un octet de /dev/tty. Si cela échoue EIO, cela signifie que nous sommes probablement orphelins.

(Notre problème de suivi est https://github.com/fish-shell/fish-shell/issues/422 )

Merci pour vos pensées!

ridicule_fish
la source

Réponses:

4

Je suis d'accord avec votre analyse et je pense qu'il semble que vous deviez détecter si votre groupe de processus est orphelin ou non.

tcsetattrest également censé retourner EIOsi le groupe de processus est orphelin (et nous ne bloquons / ignorons pas l'unité d' organisation SIGTT . Cela pourrait être une manière moins intrusive que readsur le terminal.

Notez que vous pouvez le reproduire avec:

(bash<&1 &)

Vous avez besoin de la redirection sinon stdin est redirigé vers / dev / null lors de l'exécution d'une commande en arrière-plan.

(bash<&1 & sleep 2)

Donne un comportement encore plus étrange, car vous vous retrouvez avec deux coquilles lisant depuis le terminal. Ils ignorent SIGTTINet le nouveau ne détecte pas, une fois qu'il est démarré, il n'est plus dans le groupe de processus de premier plan.

ksh93La solution n'est pas si mauvaise: ne parcourez que 20 fois (au lieu de l'infini) cette boucle avant d'abandonner.

Stéphane Chazelas
la source