UNIX Türevi Sistemlerde Proses ID Kavramı
Transkript
UNIX Türevi Sistemlerde Proses ID Kavramı
UNIX Türevi Sistemlerde Proses ID Kavramı Kaan Aslan 12 Kasım 2007 UNIX türevi sistemlerde her prosesin sistem genelinde tek olan bir id değeri vardır. Proses üzerinde işlem yapan POSIX fonksiyonları (tabi sistem fonksiyonları da) bizden prosesin id değerini ister, bu id değerini anahtar olarak kullanarak proses kontrol bloğuna erişir. Prosese ilişkin kritik bilgilerin büyük bölümünün proses kontrol bloğunda tutulduğunu biliyorsunuz. Örneğin prosese sinyal gönderen kill fonksiyonunun prototipi şöyledir: int kill(pid_t pid); görüldüğü gibi fonksiyon bizden sinyal gönderilecek prosesin id değerini istiyor. Fonksiyon aldığı bu pid değerinden hareketle prosesin kontrol bloğuna erişecek ve proses için sinyal teslim işlemini yapacaktır. Sistemdeki tüm proseslerin doğrudan ya da dolaylı üst prosesi olan init prosesinin id değeri 1’dir. UNIX türevi sistemler genellikle yeni yaratılan proses için sonraki ilk boş id değerini tahsis etmektedir. Örneğin init prosesinin id değeri 1 olduğuna göre, sonra yaratılan proseslere sırasıyla 2, 3, 4, ... id değerleri atanacaktır.[2] Sistem genelinde belli bir anda aynı id'ye sahip birden fazla proses bulunamaz. Şüphesiz, bir proses sonlandığında -eğer onun id’si yaşamakta olan bir proses grubuna ilişkin değilse- sistem artık o id’yi yeni yaratılacak prosesler için kullanabilmektedir. UNIX türevi sistemlerde proses id değeri pid_t türüyle temsil ediliyor. POSIX standartlarında pid_t türünün işaretli bir tamsayı türü olması gerektiği belirtilmiş, ancak hangi tür olarak typedef edileceği sistemi gerçekleştirenlerin isteğine bırakılmıştır. Pek çok UNIX türevi sistemde pid_t türü int olarak typedef edilmiştir.[1] Prosesin id değerinden proses kontrol bloğuna nasıl erişilmektedir? Sistemdeki tüm prosesleri tarayarak doğrusal bir arama yapmak yavaş bir yöntemdir. Pek çok sistemde bu dönüştürmenin hızlı yapılabilmesi için bir hash tablosu kullanılır. Örneğin tipik olarak hash tablosu bağlı listelerden oluşturulur (separate chaining). Proses id’si bir hash fonksiyonuna sokularak tablo indeksi elde edilir. Tabloda o indeksteki bağlı listede doğrusal arama yapılır. Linux sistemlerinde proses id’sinden proses kontrol bloğunun elde edilme yöntemi -diğer pek çok çekirdek özelliğinde olduğu- gibi versiyondan versiyona gittikçe iyileştirilmiştir. İlk versiyonlarda hash mekanizması kullanılmıyordu. Sistemdeki tüm prosesler uygun id’li olan bulunana kadar tek tek dolaşılıyordu (linear search). Daha sonra hash tablosu kullanılmaya başlandı. Örneğin, 2.4’lü çekirdeklerde kullanılan hash tablosu şöyledir: 1 Kaan Aslan Makale Arşivi – www.kaanaslan.net struct task_struct *pidhash[PIDHASH_SZ]; gördüğünüz gibi hash tablosu task_struct göstericilerinden oluşuyor. Yani hash tablosundaki bağlı liste düğümü olarak task_struct yapısının kendisi kullanılmıştır. Bağlı listelere ilişkin bağlar da task_struct yapısı içerisindeki pidhash_next ve pidhash_pprev elemanlarında tutulmaktadır: struct task_struct { ... struct task_struct *pidhash_next; struct task_struct **pidhash_pprev; ... }; Hash tablosunun görüntüsü aşağıdaki gibidir: 2.4’lü çekirdeklerdeki bu yaklaşım basit olmasına karşın aynı proses grubuna ilişkin proseslerin bulunması ya da aynı prosesin thread’lerinin bulunması yavaştı. Bunu kolaylaştırmak için 2.6’lı çekirdeklerde task_struct içerisinde 1 değil 4 ayrı bağ ve toplamda da 4 ayrı hash tablosu kullanılmaya başlanmıştır: static struct hlist_head *pid_hash[PIDTYPE_MAX]; Buradaki PIDTYPE_MAX değeri 4’tür. 4 ayrı hash tablosu sırasıyla proses id’ler, proses grup id’leri, thread grup id’leri ve oturum (session) grup id’leri için düzenlenmiştir. 2 Kaan Aslan Makale Arşivi – www.kaanaslan.net Proses kontrol bloğunda da her hash tablosu için ayrı bağlar (toplamda 4 tane) oluşturulmuştur: struct task_struct { ... struct pid pids[PIDTYPE_MAX]; ... }; struct pid { int nr; struct hlist_node pid_chain; struct list_head pid_list; }; 3 Kaan Aslan Makale Arşivi – www.kaanaslan.net Yapıdaki nr elemanı ilgili task_struct yapısına ilişkin pid numarasını, pid_chain aynı hash değerine sahip olan proseslerin liste bağını, pid_list ise aynı gruba ilişkin olan proseslerin liste bağını belirtir. Bu durumda örneğin, elimizde bir prosesin id’si varsa biz o prosesin tüm thread’lerini elde etmek için önce 1 numaralı hash tablosunda arama yaparız. İlgili task_struct nesnesini bulduktan sonra pid_list bağlı listesini dolaşırız. 4 ayrı hash tablosu tutulmasının nedeni türe göre hızlı arama yapmaktır. Aslında tek hash tablosu ve task_struct içerisinde 4’lü bağ da yeterlidir. Zaten 2.6’lı çekirdeklerin son versiyonlarına doğru yine fikir değiştirildiğini görüyoruz. İşte son versiyonlara doğru hash tablosu yine teke indirilmiştir. Bu yeni versiyonlarda task_struct içersinde yine 4 bağ vardır. CSD çekirdeğinde proseslerle thread’ler farklı veri yapılarında saklanır. Prosesler PROCESS_TABLE, thread’ler THREAD_TABLE yapılarıyla temsil edilmektedir. Yani proses kontrol bloğu kendi thread’lerini içerir. CSD çekirdeğinde Linux sistemlerinde olduğu gibi proseslerle thread’ler aynı veri yapısını (task_struct) kullanmazlar. CSD bu bakımdan Windows sistemlerindeki yaklaşıma daha yakındır. CSD çekirdeğinde proses id’sinden PROCESS_TABLE adresinin bulunması Linux’un 2.4 çekirdeğine benzer bir biçimde tek bir hash tablosu yoluyla yapılmaktadır. [1] Windows sistemlerinde proses id değeri ile prosesin handle değeri farklı anlamlara gelmektedir. Proses handle değeri HANDLE türüyle (32 ve 64 bit sistemlerde void * olarak typedef edilmiştir), id değeri ise DWORD türüyle temsil edilir. Prosesin handle değeri proses handle tablosunda bir indeks belirtirken prosesin id ise tıpkı UNIX türevi sistemlerde olduğu gibi sistem genelinde tek olan (unique) prosese özgü bir değerdir. Bu sistemlerde proses işlemlerinin çoğu prosesin handle değeri ile yapılır. [2] POSIX standartları yeni yaratılan proses için ilk boş id değerinin atanacağına ilişkin bir garanti vermemektedir. 4 Kaan Aslan Makale Arşivi – www.kaanaslan.net