Bloke Edilmiş Signal’ların İfade Edilmesi
POSIX signal fonksiyonları hangi signal’ların bloke edileceğini belirlemek için sigset_t isimli
bir tür kullanırlar. Eğer POSIX sisteminde toplam 32 tane signal var ise sigset_t şöyle typedef
edilmiş olabilir:
typedef unsigned long sigset_t;
Bu durumda her bit ilgili signal’ın bloke edilip edilmeyeceğini belirtebilir. Signal sayısı
POSIX standartlarında tam olarak belirlenmemiştir, bu nedenle bloke edilmiş signal’ların
nasıl belirleneceği de signal sistemini tasarlayanlara bırakılmıştır. sigset_t türü bir dizi ya da
yapı olabilir. sigset_t madem ki soyut bir türdür, o halde hangi signal’ların bloke edileceği
yardımcı fonksiyonlarla belirlenmelidir. POSIX sistemlerinde bunun için beş fonksiyon
bulunmaktadır:
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);
sigemptyset fonksiyonu tüm signal’ları bloke edilmemiş biçimde belirler.
sigfillset fonksiyonu bütün signal’ların bloke olduğu belirlemesini yapar.
sigaddset fonksiyonu belirli bir signal’ı bloke kümesine katar.
sigdelset fonksiyonu belirli bir signal’ı bloke kümesinden çıkartır.
sigismember fonksiyonu ilgili signal’ın bloke edilip edilmediği bilgisini verir. İlk dört
fonksiyon başarılı ise 0 değerine, başarısız ise –1 değerine geri dönerler. sigismember
fonksiyonunun geri dönüş değeri eğer signal bloke edilmiş ise 1, edilmemiş ise 0 değeridir.
Şüphesiz bu fonksiyonlar aslında bir bloke belirlemesi yapmazlar, yalnızca sigset_t türünden
bir nesnenin içerisinde set işlemleri yaparlar.
sigprocmask Fonksiyonu
Bu fonksiyon belirlenen signal’ları bloke eder ya da onların blokesini çözer.
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
Fonksiyonun birinci parametresi SIG_BLOCK, SIG_UNBLOCK ya da SIG_SETMASK
olabilir. Fonksiyonun üçüncü parametresi her zaman eski bloke durumunu vermektedir.
SIG_SETMASK ikinci parametresi ile belirtilen signal bloke kümesindeki signal’ları bloke
eder. Örneğin geçici süre bütün signal’ları bloke edip bunları eski haline getirmek isteyelim:
sigset_t nset, oset;
sigfillset(&nset);
sigprocmask(SIG_SETMASK, &nset, &oset);
// ...
sigprocmask(SIG_SETMASK, &oset, NULL);
Görüldüğü gibi fonksiyonun ikinci ve üçüncü parametreleri istenirse NULL geçilebilir.
NULL geçmek o işlemin yapılmayacağını belirtir. Örneğin ikinci parametre NULL geçilirse
ve üçüncü parametre geçilmezse o andaki signal bloke durumu elde edilir.
Birinci parametre SIG_BLOCK olarak girilirse ikinci parametrede belirtilen bloke kümesi o
andaki bloke edilmiş signal’lar kümesine katılır. Örneğin o andaki bloke kümesine hiç
dokunmadan 17 numaralı signal’ı blokeye eklemek için şu yapılabilir:
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset, 17);
sigprocmask(SIG_BLOCK, &sset, NULL);
Nihayet birinci parametre SIG_UNBLOCK ise ikinci parametrede kümeye katılmış olan
signal’lar bloke olmaktan çıkartılır. Örneğin 17 numaralı signal’ı bloke olmaktan çıkartmak
isteyelim:
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset, 17);
sigprocmask(SIG_UNBLOCK, &sset, NULL);
Sınıf Çalışması: Bir program yazınız. Programın başında SIGINT signal’ını bloke ediniz,
sonra belirli miktar sleep işlemi uygulayınız. Sonra tekrar bu signal’ı açınız ve durumu
inceleyiniz. SIGINT signal’ı için bir signal fonksiyonu yazılmalıdır.
İstenilen signal’ların bloke edilmesi kavramı klasik UNIX System V’lerde yoktu. Signal’ların
bloke edilmesi özellikle signal fonksiyonunun kullandığı bazı veri yapılarının seri hale
getirilmesinde faydalı olmaktadır.
sigaction Fonksiyonu
Güvenilir olmayan signal fonksiyonlarında signal oluştuğunda çağırılacak fonksiyon signal
fonksiyonu ile set edilmektedir. Güvenilir POSIX signal mekanizmasında bu işlem sigaction
fonksiyonu ile yapılmaktadır.
int sigaction(int signo,
const struct sigaction *act,
struct sigaction *oact);
Fonksiyonun birinci parametresi set edilecek signal numarasıdır. sigaction yapısı şöyledir:
struct sigaction {
void (*sa_handler)(int);
sigset_t sa_mask;
int sa_flags;
};
Yapının sa_handler elemanı signal oluştuğunda çağırılacak fonksiyonu belirtir. sa_mask
elemanı signal oluştuğunda çağırılacak fonksiyonun çalışması sırasında hangi signal’ların
bloke edileceğini belirtir. Bir signal oluştuğunda normal olarak signal fonksiyonu süresince o
signal’ın kendisi otomatik bloke edilmektedir. Burada buna ek olarak başka hangi signal’ların
da bloke edileceği belirtilmektedir. Yapının son elemanı ek birtakım özellikleri belirlemek
için kullanılır. Bu eleman 0 olarak geçilirse bu ek belirlemelerden vazgeçilmiş olunur.
Örneğin buradaki belirlemelerden biri yavaş sistem fonksiyonları signal ile kesildiğinde bu
sistem fonksiyonlarının otomatik olarak yeniden çağırılıp çağırılmayacağı ile ilgilidir
(SA_RESTART). Default olarak çağırılmamaktadır. Örneğin SA_RESETHAND tıpkı eski
sistemlerde olduğu gibi signal oluştuğunda signal’ın SIG_DFL’ye çekilmesini sağlar. Yapının
birinci elemanı şüphesiz SIG_DFL ve SIG_IGN değerlerini alabilir.
sigaction fonksiyonunun üçüncü parametresi önceki sigaction yapısını vermektedir. Bu
fonksiyon da başarılı durumda 0 değerine, başarısız durumda –1 değerine geri döner. Örneğin,
SIGUSR1 signal’ını set etmek isteyelim, signal fonksiyonu çalışırken SIGINT signal’ını da
bloke edelim.
struct sigaction sa;
sa.sa_handler = MyHandler;
sigemptyset(&sa.sa_mask);
sigaddset(&sa.sa_mask, SIGINT);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGUSR1, &sa, NULL) == -1) {
fprintf(stderr, “Cannot set sigaction...\n”);
exit(1);
}
sigaction fonksiyonunda bloke edilmesi istenen signal’lar yalnızca signal oluştuğunda
çağırılacak fonksiyon çalıştırılırken etkilidir. Signal bittiğinde eski duruma otomatik dönülür.
sigprocmask fonksiyonunda belirlenen signal’lar bloke kaldırılmadığı sürece etkili olurlar.
sigsuspend Fonksiyonu
Bazen sigprocmask fonksiyonu ile belirli signal'lar bloke edilip sonra pause işlemi ile
bekleme yapılır. Ancak bu iki işlem atomik olarak yapılmadığından bu arada başka bir signal
gelerek pause fonksiyonunun sonsuza kadar beklemesine yol açabilir. sigsuspend fonksiyonu
sigprocmask fonksiyonundan sonra pause fonksiyonunun çağırıldığı durumlarda bu işlemleri
atomik olarak yapar.
sigsuspend fonksiyonu hangi durumlarda gereklidir? sigprocmask ile bir signal’ın blokesinin
kaldırıldığını ve pause ile beklendiğini düşünelim. sigprocmask ile pause çağırmaları arasında
bu signal oluşursa pause sonsuza kadar bekleyebilir. İşte sigsuspend bu iki işlemi atomik
olarak yapmaktadır. Bu durumda,
sigprocmask(SIG_UNBLOCK, &sset, NULL);
pause();
ile
sigsuspend(&sset);
atomiklik dışında eşdeğerdir.
int sigsuspend(const sigset_t *sset);
Fonksiyon parametresiyle belirtilen signal kümesini bloklama bakımından set eder ve atomik
bir biçimde pause işlemi yapar. Örneğin;
sigset_t oset, nset;
// ...
sigprocmask(SIG_SETMASK, &nset, &oset);
// ...
sigsuspend(&oset);
Burada muhtemelen programcı bazı signal’leri bloke etmiş ve gerekli birtakım işlemler
yapmıştır. En sonunda da blokeyi çözerek signal oluşana kadar process’i çizelge dışına
çıkartmıştır.