Güvenilir signal Fonksiyonlarıyla setjmp ve longjmp İşlemleri
Signal fonksiyonu içerisinde longjmp yapmak bilindiği gibi çok kullanılan bir yöntemdir.
Böylelikle programcı sanki process devam ediyormuş gibi işlemlerini sürdürebilir. Ancak
güvenilir signal fonksiyonlarında signal fonksiyonu çağrıldığı zaman signal fonksiyonunun
çağrılmasına yol açan ve sigaction fonksiyonunda belirtilen signal’lar bloke edilmektedir. Bu
durumda signal fonksiyonu içerisinde longjmp yapılırsa bu signal’lar bloke edilmiş bir
biçimde kalır. Halbuki asıl istenen setjmp yapıldığı noktadaki signal durumunun aktif hale
gelmesidir. setjmp yapıldığı durumdaki signal durumuna geri dönmek için sigsetjmp ve
siglongjmp fonksiyonları kullanılır. Bu fonksiyonların kullanımı tamamen setjmp ve longjmp
fonksiyonlarında olduğu gibidir. Tek farklılık kullanılan türün jmp_buf değil, sigjmp_buf
olmasıdır.
void sig_handler(int sno)
{
...
siglongjmp(...);
}
abort Fonksiyonu
abort fonksiyonu normal olmayan panik halinde yapılan sonlandırmalar için kullanılır. abort
bir standart C fonksiyonudur. Prototipi <stdlib.h> dosyası içerisindedir.
void abort(void);
abort fonksiyonu SIGABRT isimli signal’i yollamaktadır. İşletim sistemi bu signal’i
gönderdikten sonra eğer signal fonksiyonu set edilmemişse default davranış olarak processi
sonlandırır. Signal fonksiyonu set edilmişse, fakat signal fonksiyonu içerisinde longjmp ya da
exit yapılmamışsa yine işletim sistemi signal fonksiyonunu çağırdıktan sonra process'i
sonlandırmaktadır. Bu signal’da processin sonlandırılması ancak signal fonksiyonu içerisinde
longjmp yaparak mümkündür. abort fonksiyonunun stdio.h tamponları flush edip etmeyeceği
standartlara göre derleyicileri yazanlara bırakılmıştır. Ancak derleyicilerin çoğu abort
işleminde stdio.h tamponlarını flush etmemektedir.
Sınıf çalışması: SIGABRT signal’ini set ederek main içerisinde abort fonksiyonunu çağırınız.
/* sig.c */
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
void myHandler(int n)
{
printf("myHandler\n");
exit();
}
int main()
{
struct sigaction act = {myHandler, 0, 0};
if (sigaction(SIGABRT, &act, NULL) == -1) {
fprintf(stderr, "sigaction error...\n");
exit(1);
}
abort();
return 0;
}
Önemli signal’ler Üzerinde Açıklamalar
1) SIGKILL ve SIGSTOP signal’ları için signal fonksiyonu set edilemez. Bu iki signal da
processi sonlandırmaktadır. SIGSTOP, SIGKILL signal’ından farklı olarak core dosyası
oluşturmaktadır. Bu signal’lar ignore da edilemezler. Dolayısıyla bir processi sonlandırmanın
en etkin yolu SIGKILL ya da SIGSTOP kullanmaktır. (Shell üzerinde kill komutunun default
gönderdiği signal SIGKILL değil, SIGTERM signal’ıdır.)
2) Processi sonlandırmak için kullanılan diğer signal’lar SIGTERM ve SIGQUIT
signal’larıdır. Bu signal’lara ilişkin signal fonksiyonları set edilebilir. Aralarındaki fark
SIGQUIT signal’ının signal fonksiyonu set edilmemişse core dosyası oluşturmasıdır.
3) SIGTSPT signal’ı klavyeden stop tuşu olarak tespit edilen tuşa basıldığında processe
gönderilir. Process çizelge dışı bırakılır ve askıda bırakılır. Bu tuş genellikle Ctrl+Z tuşudur.
Bu biçimde askıda bırakılan processler SIGCONT signal’ı gönderilerek tekrar çizelgeye
alınırlar. Programcı SIGTSPT signal’ını işleyebilir.
4) SIGSEGV signal’i sayfalama hatası yani tahsis edilmemiş bellek bölgesine erişildiğinde
çağrılır. Bu signal’a ilişkin signal fonksiyonu yazılabilir. Ancak yazılsa bile signal fonksiyonu
içerisinde exit ya da longjmp yapılmadıktan sonra process sonlandırılır. Aslında bu mesajın
işlenmesinden sonra processin sonlandırılıp sonlandırılmayacağı sisteme bağlıdır.
Sınıf çalışması: SIGSEGV signal’ini set ederek bir gösterici hatası yapınız.
#include <stdio.h>
#include <signal.h>
void myHandler(int n)
{
printf("myHandler\n");
exit();
}
int main()
{
int *p = NULL;
struct sigaction act = {myHandler, 0, 0};
if (sigaction(SIGSEGV, &act, NULL) == -1) {
fprintf(stderr, "sigaction error...\n");
exit(1);
}
*p = 10;
return 0;
}
5) Bir alt process sonlandırıldığında üst processe SIGCHLD signal’i gönderilir. Bu signal’ın
default durumunda hiçbir şey yapılmaz. Tipik olarak programcı bu signal’ı set ederek wait
fonksiyonu ile alt processi zombie olmaktan kurtarır. Şüphesiz bu signal fonksiyonunun
içerisinde wait kullanmak yalnızca zombilik durumunu ortadan kaldırır. Yoksa wait
fonksiyonunun asıl işlevi alt processin sonlanmasını beklemektir. (Zaten üst process daha
önce sonlandığında init processinin alt processi sonlandırması bu şekilde olmaktadır.)