Pourquoi le navigateur Chrome est-il tué lorsque je ferme le terminal malgré rien?

12

Cette question est ancienne et je ne comprends toujours pas pourquoi.


Question initiale en 2014:

Dans un onglet Gnome Terminal, j'ai couru

$ nohup chromium-browser &

Mais lorsque je ferme l'onglet du terminal, il chromium-browserse ferme également. N'est-ce pas nohupcensé empêcher ça? Gilles a dit:

on peut dire que nohup et renié suppriment SIGHUP, mais de différentes manières. nohup oblige le programme à ignorer le signal initialement (le programme peut changer cela). nohup essaie également de faire en sorte que le programme ne dispose pas d'un terminal de contrôle, afin qu'il ne soit pas envoyé SIGHUP par le noyau lorsque le terminal est fermé. l'aveuglement est purement interne à la coquille; il empêche le shell d'envoyer SIGHUP lorsqu'il se termine.

Donc, rien ne fait-il que Chrome-Browser ignore SIGHUP?

Je vois cela sur d'autres exécutables, tels que et Emacs (mode GUI). Mais pas sur xeyes.

Cela se produit sur Ubuntu 12.04, 32 bits lorsque la question a été publiée.


Mise à jour en 2015,

Maintenant, j'utilise Ubuntu 14.04, avec google-chromeau lieu d'être chromium-browserinstallé. La même chose qui est arrivée à Chrome-Browser auparavant arrive également à Google-Chrome maintenant. nohup google-chrome 2>/dev/null &ne l'empêche pas d'être fermé lorsque l'onglet du terminal est fermé. /usr/bin/google-chromeest un lien vers un script bash /opt/google/chrome/google-chrome. Pourquoi nohuple script bash ne fonctionne-t-il pas? Comment pouvons-nous le faire fonctionner sur les scripts bash? Et les scripts Python?

Tim
la source
1
Vous devriez en dire plus sur votre environnement. Je ne reproduis pas votre cas de test.
jlliagre
Avec quels autres exécutables voyez-vous cela? Essayez quelque chose de simple, par exemple, comme xeyes.
Warren Young
@WarrenYoung: Emacs (GUI). Mais xeyes fonctionne.
Tim

Réponses:

12

Lorsque vous fermez une fenêtre de terminal GNOME, un SIGHUP est envoyé au shell qu'il exécutait. Le shell envoie généralement un SIGHUP à chaque groupe de processus qu'il sait qu'il a créé - même ceux qui ont commencé par nohup- puis quitte . Si le shell est bash, il sautera l'envoi d'un SIGHUP à n'importe quel groupe de processus avec lequel l'utilisateur a marqué disown.

L'exécution d'une commande avec nohupfait ignorer SIGHUP, mais le processus peut changer cela. Lorsque la disposition de SIGHUP pour un processus est la valeur par défaut, alors s'il reçoit un SIGHUP, le processus sera interrompu.

Linux fournit quelques outils pour examiner les paramètres de signal d'un processus en cours.

Le script shell chrome-browser fait une execde l'application compilée, donc son ID de processus reste le même. Donc, pour voir ses paramètres de signal, j'ai couru nohup chromium-browser &, puis regardé /proc/$!/statuspour voir la disposition du signal.

SigBlk: 0000000000000000
SigIgn: 0000000000001000
SigCgt: 0000000180014003

Ce sont des nombres hexadécimaux. Cela montre que SIGHUP n'est pas pris et n'est pas ignoré. Seul SIGPIPE (le 13e bit de SigIgn) est ignoré. J'ai tracé cela au code suivant :

// Setup signal-handling state: resanitize most signals, ignore SIGPIPE.
void SetupSignalHandlers() {
  // Sanitise our signal handling state. Signals that were ignored by our
  // parent will also be ignored by us. We also inherit our parent's sigmask.
  sigset_t empty_signal_set;
  CHECK(0 == sigemptyset(&empty_signal_set));
  CHECK(0 == sigprocmask(SIG_SETMASK, &empty_signal_set, NULL));

  struct sigaction sigact;
  memset(&sigact, 0, sizeof(sigact));
  sigact.sa_handler = SIG_DFL;
  static const int signals_to_reset[] =
      {SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV,
       SIGALRM, SIGTERM, SIGCHLD, SIGBUS, SIGTRAP};  // SIGPIPE is set below.
  for (unsigned i = 0; i < arraysize(signals_to_reset); i++) {
    CHECK(0 == sigaction(signals_to_reset[i], &sigact, NULL));
  }

  // Always ignore SIGPIPE.  We check the return value of write().
  CHECK(signal(SIGPIPE, SIG_IGN) != SIG_ERR);
}

Malgré le commentaire, les signaux ignorés par le parent ne le sont pas . Un SIGHUP tuera le chrome.

La solution consiste à faire ce que @ xx4h indique: utilisez la disowncommande dans votre bash pour que, si bash doit quitter, il n'envoie pas SIGHUP au chromium-browsergroupe de processus. Vous pouvez écrire une fonction pour ce faire:

mychromium () { /usr/bin/chromium-browser & disown $!; }
Mark Plotnick
la source
Merci. Maintenant, je viens de comprendre surtout ce que vous vouliez dire. "Puisque le script ne réinitialise jamais ce piège, le binaire de chrome réel est appelé avec la disposition de SIGHUP définie par défaut." Par «réinitialiser ce piège», voulez-vous dire que le piège pour SIGHUP est rétabli par défaut, ce qui met fin au processus? Comment "réinitialisez-vous ce piège"?
Tim
Oh, par "réinitialiser ce piège", je voulais dire "remettre la disposition de ce signal à la façon dont il était avant que le script shell ne lui définisse un gestionnaire". Si le shell le faisait trap "" 1, cela le ferait (et ses enfants) ignorer SIGHUP. Je vais clarifier cela.
Mark Plotnick
Merci. Le vérifiera après votre clarification. J'essaie maintenant de comprendre le démon, le nohup, le reniement et l'arrière-plan, alors je suis revenu pour revoir mes anciennes questions et réponses que je n'avais pas comprises. Les confusions à propos de nohup, désavoué et arrière-plan sont pour la plupart résolues, et je suis coincé avec le concept de démon et comment démoniser un processus (voir ci-dessous). J'apprécie encore si vous avez le temps d'aider à nouveau.
Tim
J'ai regardé le code de l'application chrome, et il s'avère que le code C ++ dans l'application réinitialise SIGHUP par défaut sans condition. Les trapcommandes dans l'encapsuleur de script shell n'empêchent pas cela, et l'exécution nohupne peut pas empêcher cela. Je vais réviser ma réponse pour refléter cela.
Mark Plotnick
3

Si chromium-browserc'est quelque chose comme google-chromeça, je pense que le problème le plus probable est que ce chromium-browser n'est pas le cas,chromium mais c'est plutôt un shell-wrapper qui initialise l'état, puis execs chromium.

Dans mon google-chromeinstallation, le binaire est situé dans /opt/google/chromeet le wrapper /usr/binn'est qu'un script shell qui configure beaucoup d'environnement concernant les xdg-*valeurs par défaut et les chemins absolus et similaires avant de se remplacer par le binaire proprement dit.

À ce stade, tous les signaux qui nohuppourraient avoir initialement ignoré au nom du script qu'il a appelé en tant qu'enfant cesseront de compter et à moins que le script wrapper ne prenne soin de l'arranger autrement (ce qui n'est pas le cas), le ctty est hérité.

Essayez file /usr/bin/chromium-browserde vérifier s'il s'agit bien du script shell. Si oui, pensez à le réécrire pour mieux vous convenir.

Je peux dire que le fait de le google-chrome 2>/dev/null &garder ouvert pour moi, mais je ne me souviens pas si c'est le résultat probable des modifications que j'ai apportées au script - c'était il y a plus d'un an.

mikeserv
la source
Merci. La même chose chromium-browserqu'avant s'est également produite google-chromeaujourd'hui. Je ne l'ai pas chromium-browserinstallé. nohup google-chrome 2>/dev/null &ne l'empêche pas d'être fermé lorsque l'onglet du terminal est fermé. google-chromeest un script bash /opt/google/chrome/google-chrome. Pourquoi nohup appliqué à un script bash ne fonctionne-t-il pas? Comment pouvons-nous le faire fonctionner sur les scripts bash? Et les scripts Python?
Tim
Eh bien, il fait le travail sur le script, mais le script ne fonctionne que pour quelques nano-secondes avant d' être remplacé par le réel chromebinaire.
mikeserv
dites-vous dans le script qu'il y a execsur le chromebinaire actuel ? Comment puis-je modifier le script? Voici mon/opt/google/chrome/google-chrome
Tim
@Tim - ouais - voyez le bas? exec -a "$0" "$HERE/chrome" ... || exec -a "$0" "$HERE/chrome"... En haut $HEREest défini sur la valeur de readlink $0 (qui est votre chemin d'installation pour google-chrome) mais /opt/google/chrome/chromeest le binaire - qui est ce que le script se remplace.
mikeserv
En ce qui concerne: @ Tim que comment va - vous pouvez simplement lâcher execprobablement. Vous vous retrouverez avec un pid supplémentaire (au-delà de ses 1000 autres) et un processus shell en attente, mais je pense que c'est l'étendue de cela. Ou bien vous pourriez remplacer execw / nohuppeut - être. Tout dépend surtout de ce qui chromesera toléré - mais cela devrait fonctionner comme ça.
mikeserv