Daemon Oluşturma
Daemon prosesler, direkt olarak kullanıcının kontrolünde çalışmayan, arka planda (background) hizmet veren proseslerdir. Genellikle, sistem açılırken başlatılıp kapanana kadar çalışmaktadırlar. Sistemimizde çok sayıda daemon çalışmaktadır, birkaç bilindik deamon örneği aşağıdaki gibidir.
crond: Komutların belirlenen zamanda çalışmasını sağlar.
sshd: Uzak makinalardan sisteme oturum açılmasına olanak sağlar.
httpd: Web sayfalarını sunar.
nfsd: Ağ üzerinden dosya paylaşımını sağlar.
Not: Daemon prosesler, bir zorunluluk olmamasına karşın, genellikle d harfi ile sonlanacak şekilde isimlendirilirler.
Bir prosesin daemon olarak çalışabilmesi için aşağıdaki gibi bir yol izlenebilir.
Ayar dosyalarının okunması veya gerekli sistem kaynaklarının elde edilmesi gibi başlangıç işlemleri, proses gerçek anlamda daemon olmadan önce yapılmalıdır. Bu sayede, alınan hatalar kullanıcıya bildirilebilir ve proses uygun bir hata kodu ile sonlandırılabilir.
Üst prosesi (parent process) init olan, arka planda çalışan bir proses oluşturulmalıdır. Bu amaçla, proses içinde önce fork işlemi yapılarak bir alt proses oluşturulmalı, sonrasında üst proses exit ile sonlandırılmalıdır.
Yoluna devam eden proses içinde setsid fonksiyonu çağrılarak yeni bir oturum (session) açılmalı ve prosesin terminal (controlling terminal) ile ilişkisi kesilmelidir.
Üst prosesten miras alınan tüm açık dosya betimleyicileri (file desriptor) kapatılmalı.
Standart giriş, çıkış ve hata mesajları /dev/null aygıtına yönlendirilmeli.
Prosesin çalışma dizini değiştirilmeli.
Daemon oluşturmanın detaylarına geçmeden önce, yukarıda da bahsettiğimiz oturum kavramına değinmek istiyoruz.
Oturum (Session)
Kullanıcılar, bir terminal üzerinden sisteme giriş yaptıktan sonra (login) kabuk programı (shell) üzerinden birçok uygulamayı çalıştırabilmektedirler. Kullanıcı sistemden çıktığında bu prosesler kapatılmalıdır. İşletim sistemi bu prosesleri, oturum (session) ve proses grupları şeklinde gruplandırır. Her bir oturum proses gruplarından oluşmaktadır. Bu durumu aşağıdaki gibi tasvir edebiliriz.
Oturumdaki proseslerin girdilerini aldıkları ve çıktılarını gönderdikleri terminal kontrol terminali (controlling terminal) olarak isimlendirilmektedir. Bir kontrol terminali aynı anda yalnız bir tane oturum ile ilişkili olabilir. Bir oturumun ve içindeki proses gruplarının kimlik (ID) numaraları bulunmaktadır, bu kimlik numaraları oturum ve proses grup liderlerinin proses kimlik numaralarıdır (PID). Bir alt proses üst prosesiyle aynı grubu paylaşmaktadır. Pipe mekanizmasıyla haberleştirilen proseslerde ilk proses, proses grup lideri olmaktadır. Basit bir örnek üzerinden bu duruma daha yakından bakalım.
test.c:
Hangi terminal üzerinde olduğumuza baktıktan sonra, uygulamayı çalıştırabiliriz.
Uygulamamız önplanda çalıştığından, başka bir terminal üzerinden prosesimizle ilgili bilgilere aşağıdaki gibi ulaşabiliriz.
ps çıktısındaki kısaltmalar ve anlamları aşağıdaki gibidir.
Kısaltma
Anlamı
PID
Proses Kimliği (Process ID)
PPID
Üst Proses Kimliği (Parent Process ID)
PGID
Proses Grup Kimliği (Process Group ID)
SID
Oturum Kimliği (Session ID)
TT
Terminal
Prosesimizin, proses ve grup kimliklerinin aynı olduğunu görüyoruz, bu durumda proses kendi grubunun lideri durumundadır. Oturum kimlik değerinin ise 8703 olduğunu görmekteyiz. Prosesimizin oturum kimliği, oturum liderinin kimlik değeri (PID) olduğundan, bu kimliğin hangi prosese ait olduğunu aşağıdaki gibi bulabiliriz.
Terminale giriş yaptıktan sonra ilk çalışan kabuk prosesisin oturum lideri olduğunu görüyoruz. Kabuk prosesisin tüm kimlik değerlerinin aynı olduğuna dikkat ediniz.
Şimdi bir prosesi nasıl deamon yapabileceğimize daha yakından bakalım.
Daemon Proses Oluşturma
GNU C kütüphanesi, daemon isimli bir fonksiyon barındırmasına karşın bu fonksiyon POSIX standartlarında yer almamaktadır. daemon fonksiyon kodu, glibc ana dizininde misc/daemon.c dosyasında bulunmaktadır. Burada benzer bir fonksiyonu nasıl oluşturabileceğimizi inceleyeceğiz. Bu amaçla aynı arayüze sahip _daemon isimli bir fonksiyonu adım adım oluşturacağız. Daemon olarak çalışacak uygulama kodunu test.c, daemon fonksiyonunu adım adım oluşturacağımız kodu ise daemon.c olarak isimlendirelim.
Daemon oluşturmak için yapılması gerekenleri maddelerken, üst prosesi init olan arka planda çalışan bir prosese ihtiyacımız olduğundan bahsetmiştik. Şu haliyle _daemon
kodumuz, bir alt proses oluşturmakta ve sonrasında üst prosesi öldürmektedir. Bu durumda yeni prosesimiz init prosesinin alt prosesi olacak ve arkaplanda çalışmaya devam edecektir. Uygulamanın hemen sonlanmasını engellemek için test.c içinde getchar fonksiyonlarını kullandık. Şimdi uygulamayı derleyip prosesin _deamon çağrılmadan önce ve sonrasındaki durumunu inceleyelim.
Uygulamayı çalıştıralım herhangi bir tuşa basmaksızın başka bir terminale geçelim.
Prosesimizle ilgili değerlerin aşağıdaki gibi olduğunu görmekteyiz. Bu durumda henüz _daemon fonksiyonu çağrılmamış durumdadır.
STAT alanına baktığımızda prosesimizin çalışabilir durumda ama çizelge dışında bir olayın gerçekleşmesini bekleğini ve önplanda çalıştığını görüyoruz. STAT alanıyla ilgili bazı kısaltmalar ve anlamları aşağıdaki gibidir.
Kısaltma
Anlamı
S
Bir olayın gerçekleşmesi için uykuda bekleniyor
T
Uygulama durdurulmuş
s
Oturum lideri
+
Uygulama önplanda çalışıyor
Uygulamamızın üst prosesinin beklediğimiz üzere kabuk olduğunu görmekteyiz.
Şimdi uygulamamızı çalıştırdığımız terminale dönelim ve _daemon fonksiyonunun çağrılması için bir enter tuşuna basalım. Tekrar diğer terminal üzerinde proses bilgilerine bakalım.
İlk olarak STAT alanında + karakterini görmediğimiz için yeni alt prosesin arkaplanda çalıştığını söyleyebiliriz. Şimdi prosesin üst prosesinin kim olduğunu bakalım.
Artık prosesimizin üst prosesisin, geleneksel init yerine kullanılan, upstart prosesi olduğunu görmekteyiz (Ubuntu kullanıyorsanız).
Şimdi bir sonraki adıma geçebiliriz. Bir sonraki adımda yeni bir oturum açılması ve prosesin kontrol terminaliyle ilişkisinin kesilmesi gerektiğini söylemiştik. Bu amaçla setsid fonksiyonu kullanılmaktadır. _daemon fonksiyonumuza bu çağrıyı ekleyelim. Eklenecek kod parçası aşağıdaki gibidir.
_daemon çağrılmadan önceki durumu incelediğimiz için artık test.c kodundaki ilk getchar fonksiyonunu kaldırabiliriz.
test.c:
Uyulamayı yeniden derleyelim çalıştırdıktan sonra incelemelerimizi yaptığımız terminale geçelim. Prosesimizin yeni durumu aşağıdaki gibidir.
TT alanındaki ?
işareti prosesimizin artık bir terminale bağlı olmadığını göstermektedir. Bu durumda terminalin sonlanması durumunda prosesimiz yoluna devam edecek veya terminal üzerinden herhangi bir sinyal gönderilemeyecektir. Prosesimiz PID, PGID ve SID değerlerinin aynı olduğuna dikkat ediniz, prosesimiz artık oturum lideri durumundadır.
Sonrasında geçirdiğimiz argümanın değerine göre, çalışılan dizini root dizin olarak değiştiriyoruz. _daemon fonksiyonuna aşağıdaki kod parçasını ekleyebilirsiniz.
Bir sonraki adımda ise, geçirilen argümana göre, tüm dosya betimleyicileri kapatılabilmektedir. _daemon fonksiyonuna aşağıdaki kodu ekliyoruz.
Tüm dosya betimleyicileri kapatıldıktan sonra, daemon tarafında açılan yeni dosyalar sırasıyla 0
, 1
ve 2
dosya betimleyicileri ile gösterilecektir. Bu durumda örneğin kod içindeki printf komutları 2. açılan dosyaya yönlenmiş olacaktır. Bunu önlemek için ilk 3 betimleyicinin /dev/null aygıtını göstermesi sağlanmıştır. Yeni bir dosya açıldığında betimleyici olarak dosya betimleyici tablosundaki en küçük değerin verileceği garanti altına alınmıştır. Bu durumda open çağrısından sonra /dev/null aygıtı için 0 numaralı betimleyici tahsis edilecektir. dup fonksiyonlarıyla da sıradaki 1 ve 2 numaralı betimleyicilerin /dev/null aygıtını göstermesi sağlanmıştır. Bu durumda _daemon fonksiyonunun son hali aşağıdaki gibi olacaktır.
Örnek olarak, sshd uygulamasının daemon olarak çalışmaya başlatıldığı kod parçası aşağıdaki gibidir.
Last updated
Was this helpful?