Mengapa browser kromium terbunuh ketika saya menutup terminal meskipun tidak ada?

12

Pertanyaan ini sudah lama, dan saya masih belum jelas mengapa.


Pertanyaan asli pada tahun 2014:

Di tab Terminal Gnome, saya berlari

$ nohup chromium-browser &

Tetapi ketika saya menutup tab terminal, chromium-browserjuga keluar. Bukankah nohupseharusnya mencegah itu? Gilles berkata:

nohup dan ditolak keduanya dapat dikatakan untuk menekan SIGHUP, tetapi dengan cara yang berbeda. nohup membuat program mengabaikan sinyal pada awalnya (program dapat mengubah ini). nohup juga mencoba mengatur agar program tidak memiliki terminal pengendali, sehingga tidak akan dikirim SIGHUP oleh kernel ketika terminal ditutup. penolakan adalah murni internal ke shell; itu menyebabkan shell tidak mengirim SIGHUP ketika itu berakhir.

Jadi bukankah tidak membuat kromium-browser mengabaikan SIGHUP?

Saya melihat ini di executable lain juga, seperti dan Emacs (mode GUI). Tapi tidak pada xeyes.

Ini terjadi pada Ubuntu 12.04, 32-bit ketika pertanyaan diposting.


Pembaruan pada tahun 2015,

Sekarang saya menjalankan Ubuntu 14.04, dengan google-chromebukannya chromium-browserdiinstal. Hal yang sama yang terjadi pada chromium-browser sebelumnya juga terjadi pada google-chrome sekarang. nohup google-chrome 2>/dev/null &tidak menyimpannya agar tidak ditutup ketika tab terminal ditutup. /usr/bin/google-chromeadalah tautan ke skrip bash /opt/google/chrome/google-chrome. Mengapa nohupditerapkan pada skrip bash tidak berfungsi? Bagaimana kami bisa membuatnya bekerja pada skrip bash? Bagaimana dengan skrip Python?

Tim
sumber
1
Anda harus memberi tahu lebih banyak tentang lingkungan Anda. Saya tidak mereproduksi test case Anda.
jlliagre
Dengan executable lain mana Anda melihat ini? Cobalah sesuatu yang sederhana, misalnya xeyes.
Warren Young
@ WarrenYoung: Emacs (GUI). Tapi xyes bekerja.
Tim

Jawaban:

11

Ketika Anda menutup jendela Terminal GNOME, SIGHUP dikirim ke shell yang sedang dijalankan. Shell biasanya akan mengirim SIGHUP ke setiap grup proses yang diketahuinya dibuat - bahkan yang dimulai dengan nohup- dan kemudian keluar. Jika shell bash, itu akan melewatkan mengirim SIGHUP ke grup proses yang ditandai dengan pengguna disown.

Menjalankan perintah dengan nohupmembuatnya mengabaikan SIGHUP, tetapi prosesnya dapat mengubahnya. Ketika disposisi SIGHUP untuk suatu proses adalah default, maka jika menerima SIGHUP, proses tersebut akan dihentikan.

Linux menyediakan beberapa alat untuk memeriksa pengaturan sinyal proses yang sedang berjalan.

Skrip shell chromium-browser melakukan salah satu execdari aplikasi yang dikompilasi, jadi ID prosesnya tetap sama. Jadi untuk melihat pengaturan sinyalnya, saya berlari nohup chromium-browser &dan kemudian melihat /proc/$!/statusuntuk melihat disposisi sinyal.

SigBlk: 0000000000000000
SigIgn: 0000000000001000
SigCgt: 0000000180014003

Itu adalah angka hex. Ini menunjukkan bahwa SIGHUP tidak ditangkap dan tidak diabaikan. Hanya SIGPIPE (bit ke-13 di SigIgn) yang diabaikan. Saya melacak ini ke kode berikut :

// 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);
}

Meskipun ada komentar, sinyal yang diabaikan oleh orang tua tidak diabaikan. SIGHUP akan membunuh kromium.

Solusinya adalah melakukan apa yang ditunjukkan @ xx4h: gunakan disownperintah di bash Anda sehingga, jika bash harus keluar, itu tidak mengirim SIGHUP ke chromium-browsergrup proses. Anda dapat menulis fungsi untuk melakukan ini:

mychromium () { /usr/bin/chromium-browser & disown $!; }
Tandai Plotnick
sumber
Terima kasih. Sekarang saya mengerti sebagian besar apa yang Anda maksudkan. "Karena skrip tidak pernah mengatur ulang jebakan ini, biner krom sebenarnya disebut dengan disposisi SIGHUP yang diatur ke default." Dengan "setel ulang jebakan ini", apakah Anda bermaksud mengubah jebakan untuk SIGHUP kembali ke jebakan default, yang menghentikan proses? Bagaimana Anda "mengatur ulang perangkap ini"?
Tim
Oh, dengan "mengatur ulang jebakan ini", maksud saya "mengatur disposisi dari sinyal ini kembali ke cara sebelum script shell mengatur handler untuk itu". Jika shell melakukannya trap "" 1, itu akan membuat shell (dan anak-anaknya) mengabaikan SIGHUP. Saya akan mengklarifikasi ini.
Mark Plotnick
Terima kasih. Akan memeriksanya setelah klarifikasi Anda. Saya sekarang mencoba memahami daemon, nohup, disown, dan background, jadi saya kembali untuk meninjau kembali pertanyaan lama saya dan menjawab bahwa saya tidak mengerti. Kebingungan tentang nohup, disown dan background sebagian besar terpecahkan, dan saya terjebak dengan konsep daemon dan bagaimana cara meng-daemonisasi suatu proses (lihat di bawah). Saya hargai lagi jika Anda punya waktu untuk membantu lagi.
Tim
Saya melihat kode aplikasi kromium, dan ternyata kode C ++ dalam aplikasi me-reset SIGHUP ke default tanpa syarat. The trapperintah dalam shell script wrapper tidak mencegah hal ini, dan berjalan nohuptidak dapat mencegah hal ini. Saya akan merevisi jawaban saya untuk mencerminkan hal ini.
Mark Plotnick
3

Jika chromium-browseradalah sesuatu seperti google-chromemaka saya pikir yang paling masalah mungkin adalah bahwa chromium-browser tidakchromium tetapi bukan shell-wrapper yang menginisialisasi state kemudian execs chromium.

Dalam google-chromeinstalasi saya , biner sebenarnya terletak di /opt/google/chromedan pembungkusnya /usr/binhanyalah skrip shell yang mengatur banyak lingkungan tentang xdg-*default dan path absolut dan serupa sebelum mengganti dirinya dengan biner yang tepat.

Pada titik ini setiap sinyal yang nohupawalnya mungkin diabaikan atas nama skrip yang disebutnya sebagai anaknya akan berhenti menjadi masalah dan kecuali skrip pembungkusnya dengan hati-hati mengaturnya jika tidak (yang tidak ada) ctty diwarisi.

Cobalah file /usr/bin/chromium-browseruntuk memeriksa apakah itu skrip shell yang saya pikir benar. Jika demikian, pertimbangkan untuk menulis ulang agar lebih sesuai dengan Anda.

Saya dapat mengatakan bahwa melakukan saja google-chrome 2>/dev/null &membuatnya tetap terbuka untuk saya, tetapi saya tidak dapat mengingat apakah itu kemungkinan hasil modifikasi yang saya buat pada skrip - itu lebih dari setahun yang lalu.

mikeserv
sumber
Terima kasih. Hal yang sama yang terjadi chromium-browsersebelumnya juga terjadi google-chromesekarang. Saya belum chromium-browsermenginstal. nohup google-chrome 2>/dev/null &tidak menyimpannya agar tidak ditutup ketika tab terminal ditutup. google-chromeadalah skrip bash /opt/google/chrome/google-chrome. Mengapa nohup diterapkan pada skrip bash tidak berfungsi? Bagaimana kami bisa membuatnya bekerja pada skrip bash? Bagaimana dengan skrip Python?
Tim
Ya, memang berfungsi pada skrip, tetapi skrip hanya berjalan selama beberapa nano-detik sebelum digantikan oleh chromebiner yang sebenarnya .
mikeserv
Anda mengatakan dalam skrip ada execpada chromebiner yang sebenarnya ? Bagaimana cara saya memodifikasi skrip? Inilah saya/opt/google/chrome/google-chrome
Tim
@Tim - yeah - lihat bagian bawah? exec -a "$0" "$HERE/chrome" ... || exec -a "$0" "$HERE/chrome"... Di bagian atas $HEREdiatur ke nilai readlink $0 (yang merupakan jalur instalasi Anda untuk google-chrome) tetapi /opt/google/chrome/chromemerupakan biner - yang merupakan pengganti skrip itu sendiri.
mikeserv
@ Tim: Sejauh bagaimana - Anda bisa saja menjatuhkan yang execmungkin. Anda akan berakhir dengan tambahan pid (di luar 1000 lainnya) dan proses shell menunggu, tapi saya pikir itu sejauh itu. Atau kalau tidak Anda bisa mengganti dengan exec/ nohupmungkin. Semuanya tergantung pada apa yang chromeakan ditoleransi - tetapi harus bekerja seperti itu.
mikeserv