Apakah ada varian UNIX di mana proses anak meninggal dengan orang tuanya?

41

Saya telah mempelajari perilaku kernel Linux untuk beberapa waktu sekarang, dan selalu jelas bagi saya bahwa:

Ketika suatu proses mati, semua anak-anaknya diberikan kembali ke initproses (PID 1) sampai mereka akhirnya mati.

Namun, baru-baru ini, seseorang dengan pengalaman lebih dari saya dengan kernel mengatakan kepada saya bahwa:

Ketika proses keluar, semua anak-anaknya juga mati (kecuali jika Anda menggunakan NOHUPdalam kasus apa mereka kembali init).

Sekarang, meskipun saya tidak percaya ini, saya masih menulis program sederhana untuk memastikannya. Saya tahu saya tidak harus bergantung pada waktu ( sleep) untuk tes karena semuanya tergantung pada penjadwalan proses, namun untuk kasus sederhana ini, saya pikir itu sudah cukup.

int main(void){
    printf("Father process spawned (%d).\n", getpid());
    sleep(5);

    if(fork() == 0){
        printf("Child process spawned (%d => %d).\n", getppid(), getpid());
        sleep(15);
        printf("Child process exiting (%d => %d).\n", getppid(), getpid());
        exit(0);
    }

    sleep(5);
    printf(stdout, "Father process exiting (%d).\n", getpid());
    return EXIT_SUCCESS;
}

Ini adalah output program, dengan pshasil terkait setiap kali printfberbicara:

$ ./test &
Father process spawned (435).

$ ps -ef | grep test
myuser    435    392   tty1    ./test

Child process spawned (435 => 436).

$ ps -ef | grep test
myuser    435    392   tty1    ./test
myuser    436    435   tty1    ./test

Father process exiting (435).

$ ps -ef | grep test
myuser    436    1     tty1    ./test

Child process exiting (436).

Sekarang, seperti yang Anda lihat, ini berperilaku seperti yang saya harapkan. Proses yatim (436) diberikan kembali ke init(1) sampai mati.

Namun, apakah ada sistem berbasis UNIX di mana perilaku ini tidak berlaku secara default? Apakah ada sistem di mana kematian suatu proses segera memicu kematian semua anak-anaknya?

John WH Smith
sumber

Jawaban:

68

Ketika sebuah proses keluar, semua anak-anaknya juga mati (kecuali jika Anda menggunakan NOHUP dalam hal ini mereka kembali ke init).

Ini salah. Sangat salah. Orang yang mengatakan itu salah, atau membingungkan situasi tertentu dengan kasus umum.

Ada dua cara di mana kematian suatu proses secara tidak langsung dapat menyebabkan kematian anak-anaknya. Mereka terkait dengan apa yang terjadi ketika terminal ditutup. Ketika terminal hilang (secara historis karena garis serial terputus karena modem hangup, saat ini biasanya karena pengguna menutup jendela emulator terminal), sinyal SIGHUP dikirim ke proses pengendalian yang berjalan di terminal itu - biasanya, shell awal dimulai di terminal itu. Kerang biasanya bereaksi terhadap hal ini dengan keluar. Sebelum keluar, shell yang ditujukan untuk penggunaan interaktif mengirimkan HUP ke setiap pekerjaan yang mereka mulai.

Memulai pekerjaan dari shell dengan nohupmemecah sumber sinyal HUP kedua karena pekerjaan kemudian akan mengabaikan sinyal dan dengan demikian tidak akan diberitahu untuk mati ketika terminal menghilang. Cara lain untuk memecah propagasi sinyal HUP dari shell ke pekerjaan termasuk menggunakan shell yang disowndibangun jika memiliki (pekerjaan dihapus dari daftar pekerjaan shell), dan garpu ganda (shell meluncurkan anak yang meluncurkan anak sendiri dan segera keluar; shell tidak memiliki pengetahuan tentang cucunya).

Sekali lagi, pekerjaan yang dimulai di terminal mati bukan karena proses induknya (shell) mati, tetapi karena proses induknya memutuskan untuk membunuh mereka ketika disuruh membunuh mereka. Dan shell awal di terminal mati bukan karena proses induknya mati, tetapi karena terminalnya menghilang (yang mungkin atau mungkin tidak secara kebetulan karena terminal disediakan oleh emulator terminal yang merupakan proses induk shell).

Gilles 'SANGAT berhenti menjadi jahat'
sumber
1
Ada cara ketiga, sesuatu dengan kelompok kontrol. Yang saya tahu adalah systemd menggunakannya untuk menegakkan pembunuhan bersih.
o11c
5
@JanHudec Saya pikir Anda membingungkan nohupdengan disown. disownadalah builtin di beberapa shell yang menghapus pekerjaan yang sedang berjalan dari tabel pekerjaan (mengambil argumen seperti %1), dan efek samping utama yang bermanfaat dari itu adalah bahwa shell tidak akan mengirim SIGHUP ke subproses. nohupadalah utilitas eksternal yang mengabaikan SIGHUP (dan melakukan beberapa hal lain) kemudian memulai perintah yang diteruskan pada baris perintahnya.
Gilles 'SO- stop being evil'
@Gilles: Tidak, saya tidak, tetapi melihat strace nohupsebenarnya mengabaikan sinyal sebelum execperintah.
Jan Hudec
Terima kasih atas jawaban Anda! Saya sangat menyukai sedikit latar belakang sejarah tentang modem hang up. Saya mulai khawatir saya telah salah paham tentang kernel selama ini ...
John WH Smith
3
Juga harus dicatat bahwa program keluar ketika menerima SIGHUP karena penangan sinyal default untuk SIGHUP adalah untuk keluar. Tetapi setiap program dapat mengimplementasikan handler SIGHUP-nya sendiri yang dapat menyebabkannya tidak keluar ketika shell induk mengirimkannya SIGHUP.
Slebetman
12

Ketika sebuah proses keluar, semua anak-anaknya juga mati (kecuali jika Anda menggunakan NOHUP dalam hal ini mereka kembali ke init).

Ini benar jika prosesnya adalah pemimpin sesi. Ketika pemimpin sesi meninggal, SIGHUP dikirim ke semua anggota sesi itu. Dalam praktik itu berarti anak-anak dan keturunan mereka.

Suatu proses menjadikan dirinya sendiri pemimpin sesi dengan menelepon setsid. Kerang gunakan ini.

Dennis
sumber
Saya baru saja menjalankan tes tentang hal ini, tetapi saya tidak dapat mereproduksi perilaku yang Anda gambarkan ... Saya melahirkan suatu proses, memberinya sesi baru ( fork, membunuh proses induk, setsid), dan memasukkan anak lain ke dalam sesi baru ini. Namun, ketika proses orang tua (pemimpin sesi baru) meninggal, anak itu tidak menerima SIGHUP, dan terikat initsampai akhirnya keluar.
John WH Smith
Dari setpgid(2)manpage: Jika suatu sesi memiliki terminal pengendali, dan flag CLOCAL untuk terminal itu tidak diatur, dan terjadi hangup terminal, maka ketua sesi dikirim SIGHUP. Jika pemimpin sesi keluar, maka sinyal SIGHUP juga akan dikirim ke setiap proses dalam kelompok proses latar depan dari terminal pengendali.
ninjalj
1
@ninjalj Maka saya menduga jawaban ini valid jika dan hanya jika ketua sesi juga merupakan proses pengendalian terminal. Pemimpin sesi standar, independen dari terminal apa pun, tidak akan membunuh anak-anaknya. Apakah itu benar?
John WH Smith
-1

Jadi apa yang dikatakan poster di atas adalah, anak-anak tidak mati, orang tua membunuh mereka (atau mengirimi mereka sinyal di mana mereka berakhir). Jadi, Anda dapat memiliki apa yang Anda minta, jika Anda memprogram Orang Tua untuk (1) mencatat semua anak-anaknya, dan (2) mengirim sinyal ke semua anak-anaknya.

Inilah yang dilakukan Shell, dan seharusnya itulah yang dilakukan oleh orang tua Anda. Mungkin perlu untuk menangkap sinyal HUP pada orang tua sehingga Anda masih memiliki kontrol yang cukup untuk membunuh anak-anak.

marco
sumber
Banyak penyebab yang bisa membuat orang tua mati. Tidak ada cara untuk mencegah kelangsungan hidup anak-anak jika orang tua SIGKILL, misalnya.
Emil Jeřábek mendukung Monica
-1

Saya kehilangan sedikit jawaban yang sedikit berhubungan dengan orang tua yang sekarat: ketika sebuah proses menulis pada sebuah pipa yang tidak ada proses membaca lagi, ia mendapat SIGPIPE. Tindakan standar untuk SIGPIPE adalah penghentian.

Ini memang bisa menyebabkan proses mati. Bahkan, itu adalah cara standar di mana program yesmati.

Jika saya mengeksekusi

(yes;echo $? >&2)|head -10

pada sistem saya, jawabannya adalah

y
y
y
y
y
y
y
y
y
y
141

dan 141 memang 128 + SIGPIPE:

   SIGPIPE      13       Term    Broken pipe: write to pipe with no
                                 readers

dari man 7 signal.

pengguna86542
sumber
2
Tetapi proses membaca dari pipa belum tentu (atau bahkan biasanya) induknya. Jadi ini benar-benar kasus yang sangat berbeda dari apa yang ditanyakan.
Barmar