16 Mart 2020 Pazartesi

Linux Sinyalleri

Not : Bu konu ile ilgili olarak POSIX Sinyalleri başlıklı yazıya göz atabilirsiniz.

Pending Signal Nedir ?
Eğer bir signal handler çalıştırılıyorsa aynı sinyalden 1 veya daha fazla gelse bile signal handler bir nevi bloke olduğu için tekrar çalıştırılmaz.

Yeni sinyaller için pending bayrağı kaldırılır. Bayrak bir sayaç değildir, yalnızca pending signal olduğunu belirtir. Çalışan signal handler bitince, pending bayrağı havadaysa signal handler bir kere daha çağırılır.


SIGILL (4)
Açıklaması şöyle
SIGILL is the signal for an illegal instruction at the processor, which happens very rarely. The default action after receiving SIGILL is terminating the program and writing a core dump. The signal ID of SIGILL is 4. You encounter SIGILL very rarely, and I have absolutely no idea how to generate it in your code except via sudo kill -s 4 <pid>.
C ile bu sinyali oluşturmak için şöyle yaparız.
main=6;
veya şöyle yaparız.
const main=6;
SIGBUS (7)
Bu sinyalin SIGSEGV'den farkı biraz anlamını kaybetmiş. Bence şöyle aklımda tutmayı daha uygun buldum. Eğer bir sanal adres varsa ve bu sanal adres izin verilen adres alanı dışındaysa bu hatayı alırız. Aşağıdaki örnek bu durumu gösteriyor. Dokunulmaması gereken bir alana dokunduğu için SIGBUS hatası veriyor.
void test(void *a)
{
    asm("mov %0, %%rbp\n\t"
        "mov 0(%%rbp), %%rdx\n\t"
        : : "r"(a) : "rbp", "rdx");
}

int main()
{
    test((void *)0x706a2e3630332d69);
    return 0;
}

SIGPIPE (13)
Kapatılmış olan pipe veya sockete veri yazmaya çalışınca gönderilen sinyal. Karşıdaki uygulamanın haber vermeden kapandığını anlamamızı sağlar.

SIGTERM (15)
SIGTERM uygulamaya nazikçe artık kapanması gerektiğini söylemektir. Java - Process.destroy() source code for Linux sorusunda da anlatıldığı gibi Process.destroy() metodu çağırılınca kapatılmak istenen uygulamaya bu sinyali gönderir. Aslında Java dokümanında "The subprocess represented by this Process object is forcibly terminated." denmesine rağmen benim anladığım kadarıyla bu sinyal göz ardı edilebilir.

SIGCHLD (17)
Bir uygulama kapanırken kendisini yaratan uygulamaya SIGCHLD sinyalini de gönderir. Aşağıda bunu gösteren bir şekil var.

Buradaki soruya verilen cevapta fork/exec ile çalıştırılan bir uygulamayı beklemek için örnek kod verilmiş.
Gerçi bence bu sinyalin esas kullanım alanı yukarıdaki örnekteki gibi child uygulamanın bitmesini beklemek değil de burada söylendiği gibi arka planda çalıştırılan bir uygulamanın bittiğinin algılanması olmalı.
Burada ise aynı bir kabukta olduğu gibi arka planda çalışan uygulama bitince zombie olmaması için waitpid() metodu ile bitiş sonucunun alınması örneği var.
Eğer bir üst uygulama çalıştırdığı alt uygulamanın sonucunu beklemeden kapanırsa, alt uygulama Linux'ta init tarafından sahiplenilir.

Bir başka açıklama ise burada.

SIGSTOP ve SIGCONT (18-19)
SIGSTOP bir uygulamayı duraklatmak için SIGCONT ise devam ettirmek için kullanılır. Bu sinyaller durdurulamazlar.
The SIGSTOP signal instructs the operating system to stop a process for later resumption.
Örnek:
kill -19 `cat /var/run/mypidfile` ; kill -18 `cat /var/run/mypidfile`

SIGTTIN (21)
Controlling terminalden farklı bir gruptaki uygulama terminale okuma/yazma işlemi başlatırsa bu sinyali alır ve suspend edilir.
SIGSYS (31)
Bad system call anlamına gelir.
Sinyaller ve Stack
Burada yazdığına göre sinyaller uygulamanın stack'i içinde çalıştırılıyor. Ancak arzu edilirse ayrı bir stack tanımlamak ta mümkün. Aslında cümlede küçük bir yanlışlık var. Process'ler stack sahibi değildirler. Thread'ler bir stack'e sahiptir. Cümleyi thread stack diye okursak sorun kalmıyor.
By default, the signal handler is invoked on the normal process stack.
It is possible to arrange that the signal handler uses an alternate stack;
see sigaltstack(2) for a discussion of how to do this and when it might
be useful.

Sinyal Set Metodları
Sinyal setini sıfırlayan ve değer atayan sigemptyset,sigfillset metodlarıdır.

sigemptyset
Bu metod verilen seti sıfırlar. Aynı memset gibi çalışır.Metodun imzası aşağıdaki gibidir.
int sigemptyset(sigset_t *set);  
Örnek:
sigset_t ss;
sigemptyset(&ss);

sigfillset


sigaddset
sigdelset
sigismember

Sinyal Yakalamak için Kullanılabilecek Metodlar
signal
Sinyali default handler'ına atamak için örnek:
signal(SIGINT, SIG_DFL);
SIG_DFL default handling demek.

sigaction
sigaction yazısına taşıdım.

sa_handler alanının kullanımı

sa_handler alanına SIG_IGN değerini atayarak sinyalin dikkate alınmaması sağlanabilir. Örnek:
//set struct action to ignore signal
struct sigaction action;    
action.sa_handler=SIG_IGN;//handler set to ignore the signal
action.sa_flags=0;
//registeration 
sigaction(SIGINT,&action,0);

sa_handler alanına SIG_DFL değerini atayarak sinyalin default handler'ının çağırılması sağlanabilir.

Bu kullanım şeklinde signal handler metoduna sinyalin numarası gelir.
Örnek:

void h(int sig)
{
}

struct sigaction s;
s.sa_handler = h;
sigemptyset (&s.sa_mask);
s.sa_flags = SA_RESTART; //ve diğer seçenekler
int r = sigaction (SIGUSR1, &s, NULL);
sa_sigaction alanının kullanımı
sigaction yazısına taşıdım.

Örnek:

void handler (int sig, siginfo_t * info, void * a)
{
    //Kullanıcı tarafından gönderilen sinyal
    if (info->si_code == SI_USER) {
    }
}

struct sigaction s;
s.sa_sigsion = handler;
s.sa_flags = SA_SIGINFO;
sigemptyset (&s.sa_mask);
sigaction (SIGRTMIN, &s, NULL);

sa_mask alanının kullanımı
sigaction yazısına taşıdım.

sig_atomic_t
Aşağıda shared bir sig_atomic_t kodu örneği var.
volatile sig_atomic_t interrupted=false; 
...
void signal_handler(int s)
{
   // ...
   interrupted=true;
}
...
while (!converged && !interrupted)
{
     // Perform computations
}
// Save file properly

Sinyalleri Bloke Etmek
SIG_SETMASK ilk listedeki sinyalleri bloke eder, ikinci listedekileri ise bloke edilmekten çıkarır. Eğer ikinci liste NULL verilirse önceden bloke edilmiş sinyalleri temizler ve sadece ilk listedekileri bloke eder.
Örnek:
sigset_t allSigs;
sigfillset(&allSigs);
sigprocmask(SIG_SETMASK, &allSigs, NULL);



Hiç yorum yok:

Yorum Gönder