Üye Kayıt Üye Giriş

SIGUSR1 ve SIGUSR2 Signal'ları


SIGUSR1 ve SIGUSR2 Signal'ları

 

Normal olarak signal'lar belirli olaylar gerçekleştiğinde oluşur. Örneğin klavyede Ctrl + C
tuşuna basıldığında ya da alarm zamanı tükendiğinde oluşur. İstisna olarak SIGUSR1 ve
SIGUSR2 numaralı signal'lar herhangi bir yazılım ya da donanım olayına bağlı değildir. Bu
signal'lar programlama yoluyla, yani kill fonksiyonu ile oluşturulur. Bu signal'lar sayesinde
bir program çalışırken dışarıdan müdahale ile programın işleyişinde değişiklikler yapılması
mümkün olabilir.


Sınıf Çalışması: Bir alt process yaratınız (fork ile), alt process'te SIGUSR1 signal'ını set
ediniz. Üst process'ten kill fonksiyonu ile alt process'e SIGUSR1 signal'ını göndererek alt
process'in bunu işlemesini sağlayınız. Alt process'e SIGUSR1 signal'ı gönderildiğinde alt
process kendini sonlandırmalıdır.


/* signal2.c */
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
void OnExit(int sNo);
int main()
{
pid_t pid;
if ((pid = fork()) < 0) {
perror("fork");
exit(EXIT_FAILURE);
}
C ve Sistem Programcıları Derneği 90
if (pid == 0) {
if (signal(SIGUSR1, OnExit) == SIG_ERR) {
perror("signal");
exit(EXIT_FAILURE);
}
pause();
}
sleep(1); // child process’in signal fonksiyonunu
// işleyebilmesi için süre
if (kill(pid, SIGUSR1) == -1)
printf("kill basarisiz oldu\n");
if (wait(NULL) == -1)
printf("wait basarisiz oldu\n");
printf("Parent prog finised\n");
return 0;
}
void OnExit(int sNo)
{
printf("Child Prog finised\n");
exit(10);
}


sleep Fonksiyonu
Bu fonksiyon parametresiyle belirtilen saniye kadar ya da herhangi bir signal oluşana kadar
process’i çizelge dışı bırakır.


unsigned int sleep(unsigned int seconds);
Fonksiyonun parametresi beklenecek saniye miktarıdır. Fonksiyon eğer bir signal nedeniyle
process uyandırılmışsa kalan zaman miktarına, zaman dolması nedeniyle uyandırılmışsa 0
değerine geri döner. Prototipi <unistd.h> dosyası içerisindedir.
sleep fonksiyonun bazı sistemlerde alarm ve SIGALRM signal’leri kullanılarak yazılmış
olabilir. Ancak bu tür yazımların çeşitli problemleri vardır. signal fonksiyonunun içsel olarak
yazılması daha anlamlıdır.


Alarm signal ve pause fonksiyonları kullanılarak bir sleep fonksiyonu kusurlu bir biçimde
aşağıdaki gibi yazılabilir.


#include <stdio.h>
#include <unistd.h>
void sig_alrm(int n);
unsigned int mysleep(unsignde seconds)
{
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
return seconds;
alarm(seconds);


/*
* task switch bu noktada oluşursa ve alarm fonksiyonuna
* parametre olarak verilen seconds süresinden daha sonra
* process'e tekrar sıra geldiğinde signal gelmiş olur,
* fakat signal’in oluştuğu anda henüz pause fonksiyonu
* çağrılmamış olduğu için signal’i kaçırmış oluruz.
*/
pause();
return alarm(0);
}
void sig_alrm(int n)
{
return;
}


Buradaki en önemli kusur alarm ile pause fonksiyonlarının arasında process’ler arası geçiş
oluşması ve sistemin yüklü olduğu bir durumda alarm ile belirtilen zamanın pause
fonksiyonundan önce tükenmesidir. Görüldüğü gibi sleep fonksiyonunu pause fonksiyonunun
süreli versiyonudur.


longjmp İşlemleri


C’de goto deyiminin etiketi fonksiyon faaliyet alanında olmalıdır. Yani goto ile başka bir
fonksiyona dallanılamaz. Bunun için setjmp ve longjmp fonksiyonları kullanılır. Bu
fonksiyonlar standart C fonksiyonlarıdır.


Başka bir fonksiyona dallanmanın en önemli problemi stack dengelemesinin yapılması ve
bazı yazmaçların saklanmasıdır. Aslında daha önceki bir noktaya dallanmak demek o
noktadaki CPU yazmaçlarının değerlerinin yeniden yüklenmesi demektir. Tipik setjmp ve
longjmp fonksiyonları şöyle tasarlanır:


1) longjmp ile ancak daha önce geçilmiş olan bir bölgeye dönülebilir. İşte setjmp fonksiyonu
o andaki CPU yazmaçlarının değerlerini parametresiyle belirlenen bir yapıya yerleştirir.
2) longjmp yapıldığında bu fonksiyon CPU yazmaçlarının değerlerini yükleyerek setjmp
yapılan noktaya geçilmesini sağlar.


Bu fonksiyonların prototipleri <setjmp.h> dosyası içerisindedir.
int setjmp(jmp_buf pos);
void longjmp(jmp_buf pos, int val);


longjmp yapıldığında akış setjmp fonksiyonunun içerisine döner. Eğer setjmp longjmp ile geri
dönüyorsa longjmp’nin ikinci parametresiyle, longjmp nedeniyle geri dönmüyorsa 0 ile geri
döner. Böylece programcı setjmp noktasında fonksiyonun geri dönüş değerine bakarak akışın
ilk geçiş nedeniyle mi yoksa longjmp nedeniyle mi setjmp’den döndüğünü tespit edebilir.


jmp_buf g_pos;
if (setjmp(g_pos) == 0) {
/* setjmp ilk geçiş nedeniyle geri dönüyor */
...
}
else {
C ve Sistem Programcıları Derneği 92
/* setjmp longjmp nedeniyle geri dönüyor */
...
}
int setjmp(jmp_buf pos)
{


1) CPU yazmaçlarını pos’a yaz.


2) pos.retval = 0 yap
RETURN:


3) return pos.retval = 0 yap


}
void longjmp(jmp_buf pos, int n)
{
pos.retval = n;
// ...
}
/* Örnek */
#include <stdio.h>
#include <unistd.h>
#include <setjmp.h>
#include <stdlib.h>
int func(void);
jmp_buf g_pos;
int main()
{
printf(“begins...\n”);
if (setjmp(g_pos) != 0) {
printf(“After jump...\n”);
exit(1);
}
func();
printf(“normal finish...\n”);
}
int func(void)
{
printf(“Func...,\n”);
if (getchar() == ‘j’)
longjmp(g_pos, 1);
}
/*
* typedef struct _jmp_buf jmp_buf[1];
*/


signal oluştuğunda çağrılan fonksiyon içerisinde longjmp yapmak

Bilindiği gibi bir process çalışırken process’ler arası geçiş oluştuğunda işletim sistemi o anda
çalışmakta olan process’in yazmaç bilgilerini process handle alanında bir bölgeye yazar.
Böylelikle process yeniden kalınan yerden çalışmaya devam edebilir. Bir signal oluştuğunda
işletim sistemi kod adresini (yani CS:EIP) saklayarak signal fonksiyonuna aynı yazmaç
takımıyla dallanır. signal fonksiyonu normal sonlandırılırsa akış işletim sistemine döner.
İşletim sistemi bu noktada saklamış olduğu orijinal kod adresini (CS:EIP) process handle
alanına geri yazar. Eğer signal fonksiyonu geri dönmezse örneğin longjmp yapılmışsa işletim
sisteminin eski kod adresini yükleme gibi bir olanağı kalmaz. Böylece process sanki normal
çalışmasındaymış gibi o noktadan çalışmaya devam eder. Sonuç olarak signal fonksiyonu
içersinde longjmp yapmak bir probleme yol açmaz.


sleep fonksiyonu daha güvenli aşağıdaki gibi yazılabilir.


jmp_buf pos;
void sig_alrm(int signo)
{
longjmp(pos, 1);
}
unsigned mysleep(unsigned seconds)
{
if (signal(SIGALRM, sig_alrm) == SIG_ERR)
return seconds;
if (setjmp(pos) == 0) {
alarm(seconds);
pause();
}
return alarm(0);
}

 

 

Bilgisayar Dershanesi Ders Sahibi;
Bilgisayar Dershanesi

Yorumlar

Yorum Yapabilmek İçin Üye Girişi Yapmanız Gerekmektedir.

ETİKETLER