Sinyaller dahili olarak nasıl çalışır?


31

Genel olarak, süreçleri öldürmek için SIGKILL, SIGTSTPvb.

Ancak, belirli bir emri kimin verdiğini, belli bir işleme kimin yolladığını ve genel olarak sinyallerin işlemlerini nasıl gerçekleştirdiğini nasıl biliniyor? Sinyaller dahili olarak nasıl çalışır?


Soruyu anlamak biraz zor. Özür diliyorum ve saygısızlık etmek istemem. Bir süreci kimin öldürdüğünü emreden kimlerin komuta etmiş olabileceğini bilmek ister misiniz yoksa SIGKILL ve SIGSTP hakkında daha fazla şey öğrenmek ister misiniz?
pullsumo

@mistermister Kim bir süreci öldüren bir emri kimlerin yönettiğini bilmek isterdim?
Varun Chhangani

Yanıtlar:


35

50.000 ayak görünümü şöyledir:

  1. Çekirdek, dahili olarak (örneğin, SIGSEGVgeçersiz bir adrese erişildiğinde veya + SIGQUITtuşuna bastığınızda ) veya sistem çağrısı (veya bunlarla ilişkili birkaç tanesini kullanarak) kullanan bir program tarafından bir sinyal üretilir .Ctrl\kill

  2. Sistem çağrılarından biri tarafından kullanılıyorsa, çekirdek çağrı işleminin sinyali göndermek için yeterli ayrıcalıklara sahip olduğunu onaylar. Değilse, bir hata döndürülür (ve sinyal gerçekleşmez).

  3. İki özel sinyalden biriyse, çekirdek, hedef işlemden herhangi bir girdi olmadan koşulsuz olarak üzerinde hareket eder. İki özel sinyal SIGKILL ve SIGSTOP'tur. Varsayılan eylemler, engelleme sinyalleri vb. İle ilgili aşağıdakilerin tümü bu ikisi için önemli değildir.

  4. Daha sonra, çekirdek sinyalle ne yaptığını anlar:

    1. Her işlem için, her sinyalle ilişkili bir eylem vardır. Orada varsayılan bir gruptur ve programlar farklı olanlar kullanarak ayarlayabilirsiniz sigaction, signalvb Bunlar, "işlemini durdurmak", "bir core süreci öldürmek", "öldürme işlemi", "tümüyle görmezden" gibi şeyleri içerir vb.

    2. Programlar, sinyallerin sinyal bazında ("bloke") sinyallerini de kesebilir. Ardından sinyal engeli kaldırılana kadar beklemede kalır.

    3. Programlar, çekirdeğin bir işlem yapması yerine, sinyali işlemin eşzamanlı olarak ( sigwaitve diğerleri veya ile signalfd) veya eşzamansız olarak (işlemin ne yaptığını keserek ve belirtilen bir işlevi çağırarak) işleme iletmesini isteyebilir .

“Gerçek zamanlı sinyaller” adı verilen ve belirli bir anlamı olmayan ve ayrıca birden fazla sinyalin sıraya alınmasına izin veren ikinci bir sinyal seti vardır (normal sinyaller sinyal engellendiğinde her birinden birini sıraya koyar). Bunlar, iş parçacığının birbiriyle iletişim kurması için çok iş parçacıklı programlarda kullanılır. Örneğin, glibc’in POSIX thread uygulamasında birkaçı kullanılır. Farklı işlemler arasında iletişim kurmak için de kullanılabilirler (örneğin, bir fooctl programının foo daemonuna bir mesaj göndermesi için birkaç gerçek zamanlı sinyal kullanabilirsiniz).

50.000 olmayan bir görünüm için, man 7 signalçekirdeğin dahili dokümantasyonunu (veya kaynağını) deneyin .


"İki özel sinyal SIGKILL ve SIGSTOP" dır, öyleyse SIGCONT ne olabilir ...
Hauke ​​Laging

@HaukeLaging SIGCONT, SIGSTOP'u geri alan sinyaldir. Belgeler özel olarak listelenmiyor ... Teknik olarak bir sürecin yoksaymaya ayarlayıp ayarlamayacağından emin değilim, o zaman devam ettiremezsiniz (yalnızca SIGKILL).
derobert

22

Sinyal uygulaması çok karmaşık ve çekirdeğe özgüdür. Başka bir deyişle, farklı çekirdekler sinyalleri farklı şekilde uygulayacaktır. Basitleştirilmiş bir açıklama aşağıdaki gibidir:

Özel bir kayıt değerine dayanan CPU, bellekte aslında bir vektör tablosu olan bir "kesme tanımlayıcı tablosu" bulmayı beklediği bir adrese sahiptir. Her olası istisna için, sıfıra bölme veya INT 3 (debug) gibi bindirme gibi bir vektör vardır. CPU istisna ile karşılaştığında bayrakları ve mevcut komut göstergesini yığına kaydeder ve ardından ilgili vektör tarafından belirtilen adrese atlar. Linux'ta bu vektör her zaman bir istisna işleyicisinin olduğu çekirdeğe işaret eder. CPU şimdi yapıldı ve Linux çekirdeği devraldı.

Yazılımdan bir istisna da tetikleyebileceğinizi unutmayın. Örneğin, kullanıcı presler CTRL- C, o zaman bu çağrı, kendi özel durum işleyicisi çağıran çekirdeğe gider. Genel olarak, işleyiciye ulaşmanın farklı yolları vardır, ancak aynı temel şey ne olursa olsun gerçekleşir: içerik yığın üzerinde kaydedilir ve çekirdek istisna işleyicisi atlanır.

İstisna işleyicisi daha sonra hangi ipliğin sinyali alması gerektiğine karar verir. Eğer sıfıra bölünme gibi bir şey meydana gelirse, o zaman kolaydır: istisnaya neden olan iş parçacığı sinyali alır, ancak diğer sinyal türleri için karar çok karmaşık olabilir ve bazı olağandışı durumlarda az çok rastgele bir iplik sinyalini al.

Sinyali göndermek için önce çekirdeğin ne yaptığı, sinyal türünü belirten bir değer SIGHUPveya herhangi bir şekilde ayarlanır . Bu sadece bir tam sayı. Her işlem, bu değerin saklandığı "bekleyen bir sinyal" hafıza alanına sahiptir. Daha sonra çekirdek, sinyal bilgisiyle bir veri yapısı yaratır. Bu yapı varsayılan, görmezden gelebilecek veya işlenebilecek bir sinyal "yerleştirme" içerir. Daha sonra çekirdek kendi işlevini çağırır do_signal(). Bir sonraki aşama başlar.

do_signal()İlk karar verir o sinyali işleyecektir. Mesela, eğer bu bir ölümse , do_signal()öyküyü bitir, sadece süreci öldürür. Aksi takdirde, eğilime bakar. Eğilim varsayılan ise, do_signal()sinyali sinyale bağlı varsayılan bir politikaya göre kullanır. Eğilim işlüyse, kullanıcı programında söz konusu sinyali işlemek için tasarlanmış bir işlev olduğu ve bu işleve ilişkin göstergenin yukarıda belirtilen veri yapısında olacağı anlamına gelir. Bu durumda do_signal () başka bir çekirdek işlevi çağırır,handle_signal()daha sonra kullanıcı moduna geri dönme ve bu işlevi çağırma işleminden geçer. Bu devir işleminin detayları son derece karmaşık. Programınızdaki bu kod, işlevleri kullandığınızda genellikle programınıza otomatik olarak bağlanır signal.h.

Bekleyen sinyal değerini uygun bir şekilde inceleyerek, çekirdek işlemin tüm sinyalleri kullanıp kullanmadığını belirleyebilir ve eğer değilse, işlemin sinyale bağlı olarak uyku veya öldürme ya da başka bir harekete neden olabileceği uygun eylemde bulunacaktır.


15

Her ne kadar bu soru cevaplansa da, Linux çekirdeğinde ayrıntılı bir olay akışı göndermeme izin verin.
Bu tamamen Linux yayınlarından kopyalanır : Linux İşaretleri - İnternetteki “Linux yayınları” blogunda sklinuxblog.blogspot.in.

Sinyal Kullanıcı Alanı C Programı

Basit bir işaret kullanıcı alanı C programı yazmaya başlayalım:

#include<signal.h>
#include<stdio.h>

/* Handler function */
void handler(int sig) {
    printf("Receive signal: %u\n", sig);
};

int main(void) {
    struct sigaction sig_a;

    /* Initialize the signal handler structure */
    sig_a.sa_handler = handler;
    sigemptyset(&sig_a.sa_mask);
    sig_a.sa_flags = 0;

    /* Assign a new handler function to the SIGINT signal */
    sigaction(SIGINT, &sig_a, NULL);

    /* Block and wait until a signal arrives */
    while (1) {
            sigsuspend(&sig_a.sa_mask);
            printf("loop\n");
    }
    return 0;
};

Bu kod, SIGINT sinyali için yeni bir işleyici atar. SIGINT, Ctrl+ Ctuş kombinasyonunu kullanarak çalışan prosese gönderilebilir . Ne zaman Ctrl+ Co zaman basıldığında asenkron sinyal SIGINT göreve gönderilir. kill -INT <pid>Komutun başka bir terminale gönderilmesine de eşdeğerdir .

Bir yaparsanız kill -l(bu L, “liste” anlamına gelen bir küçük harf) , çalışan bir sürece gönderilen çeşitli sinyalleri öğreneceksiniz.

[root@linux ~]# kill -l
 1) SIGHUP        2) SIGINT        3) SIGQUIT       4) SIGILL        5) SIGTRAP
 6) SIGABRT       7) SIGBUS        8) SIGFPE        9) SIGKILL      10) SIGUSR1
11) SIGSEGV      12) SIGUSR2      13) SIGPIPE      14) SIGALRM      15) SIGTERM
16) SIGSTKFLT    17) SIGCHLD      18) SIGCONT      19) SIGSTOP      20) SIGTSTP
21) SIGTTIN      22) SIGTTOU      23) SIGURG       24) SIGXCPU      25) SIGXFSZ
26) SIGVTALRM    27) SIGPROF      28) SIGWINCH     29) SIGIO        30) SIGPWR
31) SIGSYS       34) SIGRTMIN     35) SIGRTMIN+1   36) SIGRTMIN+2   37) SIGRTMIN+3
38) SIGRTMIN+4   39) SIGRTMIN+5   40) SIGRTMIN+6   41) SIGRTMIN+7   42) SIGRTMIN+8
43) SIGRTMIN+9   44) SIGRTMIN+10  45) SIGRTMIN+11  46) SIGRTMIN+12  47) SIGRTMIN+13
48) SIGRTMIN+14  49) SIGRTMIN+15  50) SIGRTMAX-14  51) SIGRTMAX-13  52) SIGRTMAX-12
53) SIGRTMAX-11  54) SIGRTMAX-10  55) SIGRTMAX-9   56) SIGRTMAX-8   57) SIGRTMAX-7
58) SIGRTMAX-6   59) SIGRTMAX-5   60) SIGRTMAX-4   61) SIGRTMAX-3   62) SIGRTMAX-2
63) SIGRTMAX-1   64) SIGRTMAX

Ayrıca, belirli sinyalleri göndermek için aşağıdaki tuş kombinasyonunu kullanabilirsiniz:

  • Ctrl+ C- SIGINT'i hangi varsayılan eylemin uygulamayı sonlandırması gerektiğini gönderir.
  • Ctrl+ \  - SIGQUIT'e hangi varsayılan eylemin uygulama boşaltma çekirdeğini sonlandırmak olduğunu gönderir.
  • Ctrl+ Z- programı askıya alan SIGSTOP'u gönderir.

Yukarıdaki C programını derler ve çalıştırırsanız aşağıdaki çıktıları alırsınız:

[root@linux signal]# ./a.out
Receive signal: 2
loop
Receive signal: 2
loop
^CReceive signal: 2
loop

Hatta ile Ctrl+ Cveya kill -2 <pid>sürecin sona olmayacaktır. Bunun yerine sinyal işleyicisini yürütecek ve geri dönecektir.

Sinyal işleme nasıl gönderilir?

Sinyalin içselini bir işleme gönderir ve __send_signalfonksiyona dump_stack ile Jprobe koyarsak aşağıdaki çağrı izini görürüz:

May  5 16:18:37 linux kernel: dump_stack+0x19/0x1b
May  5 16:18:37 linux kernel: my_handler+0x29/0x30 (probe)
May  5 16:18:37 linux kernel: complete_signal+0x205/0x250
May  5 16:18:37 linux kernel: __send_signal+0x194/0x4b0
May  5 16:18:37 linux kernel: send_signal+0x3e/0x80
May  5 16:18:37 linux kernel: do_send_sig_info+0x52/0xa0
May  5 16:18:37 linux kernel: group_send_sig_info+0x46/0x50
May  5 16:18:37 linux kernel: __kill_pgrp_info+0x4d/0x80
May  5 16:18:37 linux kernel: kill_pgrp+0x35/0x50
May  5 16:18:37 linux kernel: n_tty_receive_char+0x42b/0xe30
May  5 16:18:37 linux kernel:  ? ftrace_ops_list_func+0x106/0x120
May  5 16:18:37 linux kernel: n_tty_receive_buf+0x1ac/0x470
May  5 16:18:37 linux kernel: flush_to_ldisc+0x109/0x160
May  5 16:18:37 linux kernel: process_one_work+0x17b/0x460
May  5 16:18:37 linux kernel: worker_thread+0x11b/0x400
May  5 16:18:37 linux kernel: rescuer_thread+0x400/0x400
May  5 16:18:37 linux kernel:  kthread+0xcf/0xe0
May  5 16:18:37 linux kernel:  kthread_create_on_node+0x140/0x140
May  5 16:18:37 linux kernel:  ret_from_fork+0x7c/0xb0
May  5 16:18:37 linux kernel: ? kthread_create_on_node+0x140/0x140

Yani ana fonksiyon sinyali göndermeyi gerektirir:

First shell send the Ctrl+C signal using n_tty_receive_char
n_tty_receive_char()
isig()
kill_pgrp()
__kill_pgrp_info()
group_send_sig_info() -- for each PID in group call this function
do_send_sig_info()
send_signal()
__send_signal() -- allocates a signal structure and add to task pending signals
complete_signal()
signal_wake_up()
signal_wake_up_state()  -- sets TIF_SIGPENDING in the task_struct flags. Then it wake up the thread to which signal was delivered.

Şimdi her şey ayarlandı ve task_structsüreç için gerekli değişiklikler yapıldı .

Sinyalin kullanımı

Sinyal, sistem çağrısından döndüğünde veya kesmeden dönüş yapıldığında bir işlem tarafından kontrol edilir / kullanılır. Sistem çağrısından dönüş dosyada var entry_64.S.

İşlev int_signal fonksiyonu denir entry_64.Solan işlevini çağırır do_notify_resume().

İşlevi kontrol edelim do_notify_resume(). Bu işlev şurada belirtilen TIF_SIGPENDINGbayrağın olup olmadığını kontrol eder task_struct:

 /* deal with pending signal delivery */
 if (thread_info_flags & _TIF_SIGPENDING)
  do_signal(regs);
do_signal calls handle_signal to call the signal specific handler
Signals are actually run in user mode in function:
__setup_rt_frame -- this sets up the instruction pointer to handler: regs->ip = (unsigned long) ksig->ka.sa.sa_handler;

SYSTEM çağrıları ve sinyalleri

“Yavaş” sistemler, örneğin okuma / yazma engelleme, işlemleri bekleme durumuna alma: TASK_INTERRUPTIBLEveya TASK_UNINTERRUPTIBLE.

Durumdaki bir görev, bir sinyal ile duruma TASK_INTERRUPTIBLEdeğiştirilecektir TASK_RUNNING. TASK_RUNNINGbir işlemin planlanabileceği anlamına gelir.

Gerçekleştirilirse, sinyal işleyicisi “yavaş” sistem çağrısı tamamlanmadan önce çalıştırılır. syscallVarsayılan olarak tamamlanmaz.

Eğer SA_RESTARTbayrak set, syscallsinyal işleyici bittikten sonra yeniden başlatılır.

Referanslar


Siteye katkıda bulunmaya çaba gösterdiğiniz için teşekkür ederiz, ancak (1) başka bir siteden materyal kopyalayacaksanız (kelime kelimesi, dilbilgisi ve harf hataları dahil olmak üzere mektup mektubu), yani, çok daha net. Kaynağın “Referans” olarak listelenmesi, gerektiğinde yeterli değildir. Blogun yazarı olmadıkça (K_K = sk?), Bu durumda ona bağlantı kurmanız gerekmez - ama eğer yaparsanız, bunun sizin olduğunu açıklamanız gerekir . … (Devam Ediyor)
G-Man

(Devam ediyor)… (2) Kaynağınız (kopyaladığınız blog) çok iyi değil. Sorunun sorulmasından bu yana dört yıl geçti; kopyalamak için daha iyi bir referans bulamadınız mı? (Özgün yazarsanız, üzgünüm.) Yukarıda belirtilen dilbilgisi ve noktalama işaretlerine ek olarak (ve genellikle özensiz ifadeler ve zayıf biçimlendirme), yanlış. (2a) Ctrl + Z, SIGSTOP'u değil, SIGTSTP'yi gönderir. (SIGTSTP, SIGTERM gibi takılabilir; SIGSTOP, SIGKILL gibi edemez.) ... (devamı)
G-Man 'eski durumuna Monica' Diyor

(Devam ediyor)… (2b) Kabuk, Ctrl + C sinyalini göndermiyor. Kabuğun sinyal göndermede rolü yoktur (kullanıcının killbir kabuk yerleşik olan komutu kullanması dışında ). (2c) }Bir işlevin kapanmasından sonraki noktalı virgüller , kesinlikle konuşmamakla birlikte, hatalar olsa da, gereksiz ve son derece sıradışıdırlar. (3) Her şey doğru olsa bile, bu sorunun cevabı çok iyi olmaz. (3a) Bu soru biraz belirsiz olsa da, oyuncuların (kullanıcılar ve süreç ) sinyalleri nasıl başlattıklarına (yani göndermelerine ) odaklanıyor gibi görünüyor . … (Devam ediyor)
G-Man

(Devam)… Cevap, çekirdek tarafından üretilen sinyallere (özellikle klavye tarafından üretilen sinyaller) ve alıcı işleminin sinyallere nasıl tepki verdiğine odaklanmış gibi görünüyor. (3b) Soru “Birisi süreçimi öldürdü - kim yaptı ve nasıl?” Düzeyinde görünüyor. Cevap, sinyal işleme API'sini, çekirdek rutinlerini, çekirdek hata ayıklamasını (Jprobe?), Çekirdek yığın izlerini ve çekirdek veri yapıları. IMO, bu uygun olmayan şekilde düşük bir seviyedir - özellikle bir okuyucunun bu içsel çalışmalar hakkında daha fazla bilgi edinebileceği herhangi bir referans sunmadığından.
G-Man

1
Bu benim kendi blogum. Kanal .. Bu çekirdek iç cevabı gramer iç değil.
K_K
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.