Sunday 3 February 2008

LINUX Çekirdeğini Anlamak – Süreçler Arası İletişim 4

Ali Rıza SARAL(1)


(1) Daniel P. Bovet, Marco Cesati, Understanding the Linux Kernel ‘den faydalanarak derlenmiştir.


18.1.4 Bir Borudan Okuyuş (Reading from a Pipe)
Bir borudan veri almak isteyen bir süreç, kendi dosya tanımlayıcısı olarak borunun okuyucu kanalı ile ilişkilendirilmiş tanımlayıcıyı belirleyerek bir oku() (read( )) sistem çağrısı çıkarır. Sonuç olarak, çekirdek, dosya işlem tablosunda uygun bir dosya nesnesi ile ilişkilendirilmiş bir oku (read) metodunu başlatır. Bir boru durumunda, oku (read) metodu için oku_boru_dişl (read_pipe_fops) tablosundaki bir girdi boru_oku() (pipe_read( )) fonksiyonuna işaret eder. boru_oku() (pipe_read( )) fonksiyonu çok ilişkilidir, çünkü POSIX standardı borunun okuyuş işlemlerine bir çok şart koşmuştur. Tablo 18-2 boru uzunluğu p olan(okunacak boru arabölgesindeki byteların sayısı) bir borudan n byte rica eden, oku() (read( )) sistem çağrısının umulan davranışını gösterir. Okuyuş işleminin tıkanmasız(nonblocking) olabileceğine dikkat ediniz: bu durumda işlem, var olan bütün bytelar kullanıcı adres boşluğuna[3] kopyalanır kopyalanmaz tamamlanır. Ayrıca, yalnız eğer boru boş ise ve borunun yazıcı kanalı ile ilişkilendirilmiş dosya nesnesini o anda hiçbir süreç kullanmıyor ise oku() (read( )) sistem çağrısı tarafından değer döndürülür.
[3] Tıkanmasız işlemler genellikle aç() (open( )) sistem çağrısı içinde O_TIKANMASIZ (O_NONBLOCK) bayrağını belirleyerek talep edilir. Bu yöntem açılamadıkları için borulara geçerli değildir; bir süreç yine de karşı düşen dosya tanımlayıcı üzerinde bir dkntl() (fcntl( )) sistem çağrısı yaparak tıkanmasız bir işlem yapılmasını şart koşabilir.

Tablo 18-2. Bir Borudan Byte’ların Okunuşu (Reading n Bytes from a Pipe)

Fonksiyon aşağıdaki işlemleri icra eder:
1. idüğüm(inode)'ün i_boy (i_size) alanına depolanmış olan boru boyunun 0 olup olmadığını belirler. Bu durumda, fonksiyonun geri dönüşünün zorunluluğunu veya başka bir süreç boruya yazı yazışını beklerken tıkanmasının zorunlu olup olmadığını belirler(Bakınız Tablo 18-2). G/Ç işleminin türü (tıkanarak ya da tıkanmasız) olacağı dosya nesnesinin d_bayraklar (f_flags) alanının O_TIKANMASIZ (O_NONBLOCK) bayrağı tarafından belirlenir. Eğer gerekirse, o andaki süreci, boru_idüğüm_bilgisi (pipe_inode_info) veri yapısının bekle(wait) alanının işaret ettiği bekleyiş kuyruğuna sokturup sonra da askıya almak için kesilebilir_bekle_durumunda() (interruptible_sleep_on()) fonksiyonunu başlatır.

2. boru_idüğüm_bilgisi (pipe_inode_info) veri yapısının kilit (lock) alanını sınar. Eğer boş değil ise,
başka bir süreç o anda boruya erişmektedir; bu durumda, ya o anki süreci askıya alır ya da okuyuş işleminin tipine göre (tıkanmasız ya da tıkayıcılı) sistem çağrısını sona erdirir.

3. lock alanını arttırır.

4. Borunun arabölgesinden kullanıcı adres boşluğuna istenen sayıda (ya da elde var olan bytelar kadar olanı, eğer arabölge çok küçük ise) byte’ı kopyalar.

5. lock alanını azaltır.

6. Borunun bekleyiş kuyruğundaki bütün süreçleri uyandırmak için uyandır_kesilebiliri() (wake_up_interruptible( )) ‘ı başlatır.

7. Kullanıcı adres boşluğuna kopyalanmış olan byte’ların sayısını geri döndürür.

18.1.5 Boruya yazış (Writing into a Pipe)
Bir boruya veri koymak dileyen bir süreç, kendi dosya tanımlayıcısı olarak borunun yazıcı kanalı ile ilişkili tanımlayıcıyı kendi dosya tanımlayıcısı olarak belirleyerek, bir yaz() (write( )) system çağrısı çıkarır. Çekirdek bu isteği uygun dosya nesnesinin yaz (write) yöntemini başlatarak tatmin eder; yaz_boru_dişl() (write_pipe_fops) tablosunda karşı düşen girdi boru_yaz() (pipe_write( )) fonksiyonuna işaret eder. Tablo 18-3, POSIX standardına göre, arabölgesinde u (unused) kullanılmamış byte’ı olan bir borunun içine n byte yazmak isteyen bir yaz (write( )) sistem çağrısının davranışını canlandırmaktadır. Standart özellikle küçük sayıda bytela ilgili yazıcı işlemlerin otomatik olarak ifa edilişini zorunlu kılar. Daha doğrusu, eğer iki ya da daha çok süreç boruya eş zamanlı yazıyorsalar, 4096’dan daha az (boru arabölgesi boyu) byte ile ilgili herhangi bir yazıcı işlem aynı boruya başka süreçler tarafından yapılan yazıcı işlemler ile içiçe geçirilmeden(interleave) bitmek zorundadır. Yine de, 4096 byte’tan daha uzun yazıcı işlemler gayrı-atomik olabilirler ve çağırıcı sürecin uyutuluşunu zorunlu kılabilirler.

Table 18-3. Bir Boruya n tane byte’ın yazılışı

Dahası, eğer bir borunun okuyucu süreci yoksa (yani idüğüm nesnesinin readers alanı 0 değerine sahipse) o boruya yazıcı bütün işlemler başarısız olmalıdır. O durumda, çekirdek yazıcı sürece bir -EPIPE hata kodu ile, bir SIGPIPE işareti gönderir, bu ise tanıdık “Kırık Boru” mesajına yol açar. pipe_write( ) fonksiyonu aşağıdaki işlemleri icra eder:

1. Borunun en azından bir okuyucu süreci olduğunu sınar. Eğer değilse, şuanki (current) sürece BORUİŞA (SIGPIPE) işaretini gönderir ve bir -EBORU (-EPIPE) değerini geri döndürür.

2. Borunun idüğümünün (inode) sys_write( ) fonksiyonu tarafından ayrılmış, i_sem semaforunu serbest bırakır ve aynı düğümün the i_atomik_yaz() (i_atomic_write) semaforunu ayırır. [4]

[4] i_sem semaforu çok sayıda sürecin bir dosya üzerinde yazış işlemleri başlatışını önler, ve dolayısıyla boru üzerinde de.

3. Yazılacak byteların sayısının borunun arabölge boyu içinde olup olmadığını kontrol eder:
a. Eğer öyle ise, yazış işlemi atomik olmak zorundadır. Dolayısıyla, arabölgenin yazılacak bütün byteları depolayabilecek yeterli serbest boşluğa sahip olduğunu kontrol eder.
b. Eğer byteların sayısı arabölge boyundan daha büyükse, bir parça serbest boşluk olduğu sürece işlem başlar. Dolayısıyla en azından 1 byte boş yer olduğunu sınar.

4. Eğer arabölge yeterli serbest boşluğa sahip değilse ve yazıcı işlem tıkayıcıysa, şu andaki süreci borunun bekleyiş kuyruğuna sokar ve borudan bir miktar veri okununcaya kadar onu askıya alır. i_atomik_yaz() (i_atomic_write) semaforun serbest bırakılmadığının farkına varınız, dolayısıyla başka hiçbir süreç boru üstünde yazıcı bir işlem başlatamaz. Eğer yazıcı işlem tıkanmasız ise, -ETEKRAR (-EAGAIN) hata kodunu geri döndürür.

5. pipe_inode_info veri yapısının lock alanını sınar. Eğer boş değilse, bir başka süreç o anda boruyu okuyordur, dolayısıyla ya o anki süreci askıya alır ya da yazış işleminin tıkayıcı veya tımasız oluşuna bağlı olarak yazışı hemen sona erdirir.

6. kilit (lock) alanını arttırır.

7. İstenen sayıda byte’i (eğer boru boyu çok kısa ise serbest byte sayısı kadarını) kullanıcı adres boşluğundan borunun arabölgesine taşır.

8. Eğer hala yazılışı gereken bytelar var ise 4. adıma gider.

9. İstenen bütün veri yazıldıktan sonra, kilit (lock) alanını azaltır.

10. Borunun bekleyiş kuyruğunda bekleyen bütün süreçleri uyandırmak için uyandır_kesilebiliri() (wake_up_interruptible( )) ‘ı başlatır.

11. i_atomic_write semaforu serbest bırakır ve i_sem semaforunu bağlar (böylece sys_write( ) ikincisini kolaylıkla serbest bırakabilir).

12. Borunun arabölgesine yazılan byteların sayısını geri döndürür.