Penanganan sinyal dengan banyak utas di Linux

119

Di Linux, apa yang terjadi ketika sebuah program (yang mungkin memiliki banyak utas) menerima sinyal, seperti SIGTERM atau SIGHUP?

Utas mana yang memotong sinyal? Bisakah beberapa utas mendapatkan sinyal yang sama? Apakah ada utas khusus yang didedikasikan sepenuhnya untuk menangani sinyal? Jika tidak, apa yang terjadi di dalam utas yang menangani sinyal? Bagaimana eksekusi dilanjutkan setelah rutinitas penangan sinyal selesai?


sumber

Jawaban:

35

Ini sedikit berbeda, berdasarkan versi kernel Linux yang Anda gunakan.

Dengan asumsi 2.6 posix thread, dan jika Anda berbicara tentang OS yang mengirim SIGTERM atau SIGHUP, sinyal dikirim ke proses, yang diterima dan ditangani oleh thread root. Dengan menggunakan utas POSIX, Anda juga dapat mengirim SIGTERM ke utas individu, tetapi saya curiga Anda bertanya tentang apa yang terjadi ketika OS mengirim sinyal ke proses.

Di 2.6, SIGTERM akan menyebabkan utas anak keluar "dengan bersih", sedangkan 2.4, utas turunan dibiarkan dalam keadaan tidak pasti.

Alan
sumber
Dan apa yang terjadi di dalam utas root ketika sinyal diterima? Katakanlah saya menulis penangan sinyal khusus untuk SIGUSR1, dan sekarang saya mengirim sinyal itu ke proses. Utas root akan mendapatkan sinyal itu. Mungkin itu di tengah beberapa fungsi pada saat itu. Apa yang akan terjadi?
1
jika Anda memiliki pengaturan penangan, ini akan diperlakukan sebagai interupsi, dan aliran program akan berhenti dan penangan khusus Anda akan dijalankan. Setelah dijalankan, kontrol akan kembali, dengan asumsi Anda belum melakukan apa pun untuk mengubah aliran normal (keluar dll).
Alan
Perhatikan bahwa ini khusus untuk SIGUSR1, yang IIRC tidak mengganggu panggilan sistem. Jika Anda mencobanya dengan SIGINT misalnya, ini dapat mengganggu pembacaan aliran, dan ketika Anda kembali ke pembacaan, aliran dapat mengembalikan kesalahan yang telah diinterupsi.
Alan
10
Saya agak bingung tentang apa yang dimaksud dengan "root thread". Apakah ini berarti handler untuk SIGTERM akan selalu berjalan di thread utama, atau dapatkah ia berjalan di thread mana pun?
Stephen Nutt
3
Jawaban ini , yang menyatakan bahwa utas arbitrer dipilih untuk menangani sinyal, bertentangan dengan jawaban Anda.
pengguna202729
135

pthreads(7) menjelaskan bahwa POSIX.1 membutuhkan semua utas dalam proses berbagi atribut, termasuk:

  • disposisi sinyal

POSIX.1 juga membutuhkan beberapa atribut agar berbeda untuk setiap utas, termasuk:

complete_signalRutin kernel Linux memiliki blok kode berikut - komentarnya cukup berguna:

/*
 * Now find a thread we can wake up to take the signal off the queue.
 *
 * If the main thread wants the signal, it gets first crack.
 * Probably the least surprising to the average bear.
 */
if (wants_signal(sig, p))
        t = p;
else if (!group || thread_group_empty(p))
        /*
         * There is just one thread and it does not need to be woken.
         * It will dequeue unblocked signals before it runs again.
         */
        return;
else {
        /*
         * Otherwise try to find a suitable thread.
         */
        t = signal->curr_target;
        while (!wants_signal(sig, t)) {
                t = next_thread(t);
                if (t == signal->curr_target)
                        /*
                         * No thread needs to be woken.
                         * Any eligible threads will see
                         * the signal in the queue soon.
                         */
                        return;
        }
        signal->curr_target = t;
}

/*
 * Found a killable thread.  If the signal will be fatal,
 * then start taking the whole group down immediately.
 */
if (sig_fatal(p, sig) &&
    !(signal->flags & SIGNAL_GROUP_EXIT) &&
    !sigismember(&t->real_blocked, sig) &&
    (sig == SIGKILL || !p->ptrace)) {
        /*
         * This signal will be fatal to the whole group.
         */

Jadi, Anda tahu bahwa Anda bertanggung jawab atas ke mana sinyal dikirimkan:

Jika proses Anda telah menetapkan disposisi sinyal ke SIG_IGNatau SIG_DFL, maka sinyal tersebut diabaikan (atau default - kill, core, atau abaikan) untuk semua utas.

Jika proses Anda telah menetapkan disposisi sinyal ke rutinitas penangan tertentu, Anda dapat mengontrol utas mana yang akan menerima sinyal dengan memanipulasi masker sinyal utas tertentu menggunakan pthread_sigmask(3). Anda dapat menominasikan satu utas untuk mengelola semuanya, atau membuat satu utas per sinyal, atau campuran apa pun dari opsi ini untuk sinyal tertentu, atau Anda bergantung pada perilaku default kernel Linux saat ini dalam mengirimkan sinyal ke utas utama.

Beberapa sinyal, bagaimanapun, adalah khusus menurut signal(7)halaman manual:

Sinyal dapat dihasilkan (dan dengan demikian menunggu) untuk proses secara keseluruhan (misalnya, ketika dikirim menggunakan kill (2) ) atau untuk utas tertentu (misalnya, sinyal tertentu, seperti SIGSEGV dan SIGFPE, dihasilkan sebagai konsekuensi dari eksekusi instruksi bahasa mesin tertentu diarahkan ke thread, seperti juga sinyal yang ditargetkan pada thread tertentu menggunakan pthread_kill (3) ). Sinyal yang diarahkan pada proses dapat dikirim ke salah satu utas yang saat ini tidak memiliki sinyal yang diblokir. Jika lebih dari satu utas memiliki sinyal yang tidak diblokir, maka kernel memilih utas arbitrer untuk mengirimkan sinyal.

sarnold
sumber