Apa yang harus dilakukan shell interaktif dalam kelompok proses yatim?

10

(Posting ulang di unix sesuai saran di /programming/13718394/what-should-interactive-shells-do-in-orphaned-process-groups )

Pertanyaan singkatnya adalah, apa yang harus dilakukan shell jika berada dalam grup proses yatim yang tidak memiliki tty? Tapi saya sarankan membaca pertanyaan panjang karena itu lucu.

Berikut ini adalah cara yang menyenangkan dan menarik untuk mengubah laptop Anda menjadi pemanas ruang portabel, menggunakan cangkang favorit Anda (kecuali Anda salah satu dari orang aneh tcsh):

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

Ini menyebabkan bash untuk mematok CPU pada 100%. zsh dan ikan melakukan hal yang sama, sementara ksh dan tcsh menggumamkan sesuatu tentang kontrol pekerjaan dan kemudian melunasi, yang sedikit lebih baik, tetapi tidak banyak. Oh, dan itu adalah pelaku platform agnostik: OS X dan Linux sama-sama terpengaruh.

Saya (berpotensi salah) penjelasan adalah sebagai berikut: shell anak mendeteksi tidak di latar depan: tcgetpgrp(0) != getpgrp(). Oleh karena itu mencoba untuk menghentikan sendiri: killpg(getpgrp(), SIGTTIN). Tetapi grup prosesnya adalah yatim piatu, karena induknya (program C) adalah pemimpin dan meninggal, dan SIGTTINdikirim ke grup proses yatim hanya dibatalkan (jika tidak, tidak ada yang bisa memulainya lagi). Oleh karena itu, shell anak tidak berhenti, tetapi masih di latar belakang, jadi ia melakukan semuanya lagi, segera. Bilas dan ulangi.

Pertanyaan saya adalah, bagaimana shell baris perintah dapat mendeteksi skenario ini, dan apa hal yang benar untuk dilakukan? Saya punya dua solusi, yang keduanya tidak ideal:

  1. Cobalah memberi tanda proses yang pidnya cocok dengan ID grup kami. Jika itu gagal ESRCH, itu berarti kita mungkin yatim piatu.
  2. Coba baca non-pemblokiran satu byte dari /dev/tty. Jika itu gagal EIO, itu berarti kita mungkin yatim piatu.

(Masalah kami pelacakan ini adalah https://github.com/fish-shell/fish-shell/issues/422 )

Terima kasih atas pemikiran anda!

ridiculous_fish
sumber

Jawaban:

4

Saya setuju dengan analisis Anda dan saya setuju sepertinya Anda harus mendeteksi apakah grup proses Anda yatim piatu atau tidak.

tcsetattrjuga dimaksudkan untuk kembali EIOjika grup proses menjadi yatim (dan kami tidak memblokir / mengabaikan SIGTT OU . Itu mungkin cara yang kurang mengganggu daripada readdi terminal.

Perhatikan bahwa Anda dapat mereproduksinya dengan:

(bash<&1 &)

Anda memerlukan pengalihan jika tidak stdin diarahkan ke / dev / null saat menjalankan perintah di latar belakang.

(bash<&1 & sleep 2)

Memberikan perilaku yang lebih aneh, karena Anda berakhir dengan dua cangkang membaca dari terminal. Mereka mengabaikan SIGTTINdan yang baru tidak mendeteksi, setelah dimulai tidak lagi dalam kelompok proses latar depan.

ksh93Solusi ini tidak terlalu buruk: hanya naik hingga 20 kali (bukannya tanpa batas) melalui loop itu sebelum menyerah.

Stéphane Chazelas
sumber