Saturday 8 December 2007

LINUX Çekirdeğini Anlamak – Süreçler 2

Ali Rıza SARAL(1)

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

3.1.2.4 Süreç Listesi (The process list)
Verilmiş bir çeşit süreçlerin arasında etkili bir arayışa imkan sağlamak için (örn., çalışabilir halde olan bütün süreçler) çekirdek, bu süreçlerin bir çok listesini yaratır. Her liste süreç tanımlayıcılara işaretedicilerden oluşur.

Bir liste işaretedicisi(yani, herbir sürecin bir sonraki sürece işaret etmek için kullandığı alan) doğrudan süreç tanımlayıcı veri yapısı içine gömülüdür. görev_yapısı (task_struct)’nın C-dili tanımlanışına baktığınızda, tanımlayıcılar kendi üstlerine karışık bir tekrarçağıran (recursive) tavırla döner gibi gözükürler.

Yine de, bu kavram kendisinin bir başka gerçeklenişine bir işaret edici taşıyan bir veri yapısı olan bir listeden daha karışık değildir. Çembersel çift bağlı liste (bkz. Şekil 3-3) var olan bütün süreç tanımlayıcıları birbirlerine bağlar; buna süreç listesi adını vereceğiz.

Listeyi gerçekleştirmek için her süreç tanımlayıcının önceki_görev ve sonraki_görev (prev_task and next_task) alanları kullanılır. görev dizisinin ilk elemanı tarafından belirtilen(referenced) görevi-sıfırla (init_task) tanımlayıcısı listenin başıdır: bütün süreçlerin atasıdır(anchestor), ve one süreç0(process 0) ya da swapper adı verilir. görev_sıfırla(init_task )’nın önceki_görev (prev_task) alanı listeye eklenen en son süreç tanımlayıcıya işaret eder.


Şekil 3-3. Süreç listesi

BAĞLARI_KUR (SET_LINKS) ve BAĞLARI_KALDIR (REMOVE_LINKS) makroları süreç listesine bir süreç eklemek veya kaldırmak için kullanılır. Bu makrolar aynı zmanda sürecin ebevyn ilişkisininde çaresine bakar. her_görev_için (for_each_task) adı verilen bir başka kullanışlı makro bütün süreç listesini tarar.

Bu makro çekirdek programcısı çevrimi sağladıktan sonra gelen çevrim kontrol ibaresi (statement). görev_sıfırla (init_task) süreç tanımlayıcısının basitçe liste başı rolünü nasıl oynadığına dikkat ediniz. Makro görev_sıfırla (init_task)’dan sonraki göreve geçerek harekete başlar ve tekrar görev_sıfırla ’ya ulaşıncaya kadar devam eder.

3.1.2.5 GÖREV_ÇALIŞIYOR süreçlerinin listesi (The list of TASK_RUNNING processes)
MerkeziİşlemBirimi (CPU) üzerinde çalıştırmak için yeni bir süreç ararken, çekirdeğin yalnız çalıştırılabilir (runnable) süreçleri dikkate almaklığı gerekir(yani GÖREV_ÇALIŞIYOR (TASK_RUNNING) durumundaki süreçler) . Bütün süreç listesi taramak çok etkisiz olacağından, çalıştırış kuyruğu (runqueue) adı verilen bir çift bağlı çembersel liste geliştirilmiştir. Süreç tanımlayıcılar çalıştırış kuyruğu (runqueue) ’yu gerçekleştirmek için sonraki_çalışan ve önceki_çalışan (next_run and prev_run) alanlarını içerir.

Bir önceki durumda olduğu gibi, görev_sıfırla (init_task) süreç tanımlayıcısı liste başı rolünü oynar. sy_çalıyor (nr_running) değişkeni çalıştırılabilir süreçlerin toplam sayısını saklar. çalıştırış_kuyruğuna_ekle (add_to_runqueue( )) fonksiyonu bir sürec tanımlayıcıyı listenin başlangıcına ekler, çalıştırış_kuyruğundan_sil (del_from_runqueue( )) ise bir süreç tanımlayıcıyı listeden çıkartır.

Çalıştırım planlamak amacı ile, süreç tanımlayıcıyı başa ya da sona almak için iki fonksiyon, çalıştırış_kuyruğunda_başa_al ve çalıştırış_kuyruğunda_sona_al (move_first_runqueue( ) ve move_last_runqueue( )) sağlanmıştır.

Son olarak, süreci_uyandır() (wake_up_process( )) fonksiyonu bir süreci çalştırılabilir yapmak için kullanılır. Süreç halini GÖREV_ÇALIŞIYOR (TASK_RUNNING)’a ayarlar, süreci çalıştırış kuyruğuna sokmak için çalıştırışkuyruğuna_ekle() ( add_to_runqueue( ))’yi harekete geçirir ve sy_çalıyor (nr_running) ’i arttırır.

Süreç gerçek-zaman (real-time) olduğu veya şu anki süreçten çok daha büyük bir devinimsel öncelik(dynamic priority) sahibi olduğunda çalıştırım planlayıcıyı zorla harekete geçirir.

3.1.2.6 süreçkimliknosueşleştiriş tablosu ve zincirlenmiş listeler (The pidhash table and chained lists)
Bir çok durumda, çekirdek SüreçKimlikNosu (PID)’ndan süreç tanımlayıcı işaretedicisini çıkartabilmek zorundadır. Bu örneğin, öldür() (kill( )) sistem çağrısına hizmet ederken olur: P1 süreci bir başka sürece, P2, işaret göndermek istediğinde, P2’nin SüreçKimlikNo’sunu parametre olarak belirleyerek öldür() sistem çağrısını harekete geçirir.

Çekirdek süreç tanımlayıcı işaretedicisini SüreçKimlikNo’sundan çıkarır ve daha sonra P2 süreç tanımlayıcısından gelip beklemekte olan (pending) işaretleri kayıt eden veri yapısına işaretediciyi elde eder. Süreç listesini sıradan taramak ve süreç tanımlayıcıların pid alanlarını kontrol etmek başvurulabilir fakat hiç te etkin olmaz.

Arayışı hızlandırmak için, SÜREÇKİMLİKNOSUEŞLEŞTİRİŞ_SY (PIDHASH_SZ) sayısında elemandan oluşan bir süreçkimliknosueşleştiriş tablosu (pidhash hash table) ’a başvurulmuştur (PIDHASH_SZ genellikle GÖREV_SY (NR_TASKS)/4 ‘tür). Bu tablo haneleri süreç tanımlayıcı işaretedicilerini taşır.

SüreçKimlikNo’su süreçkimliknosu_eşleştirişfonksiyonu (pid_hashfn) makrosunu kullanarak bir tablo indexine dönüştürülür.





Şekil 3-4. Süreçkimliknosueşleştiriş tablosu ve zincirlenmiş listeler Zincirleyerek eşleştiriş
SüreçKimlikNo’larından tablo indexlerine doğrusal bir dönüştürüşe terih edilir, çünkü SüreçKimlikNo’su 0 ile 32767 arasında herhangi bir değeri alabilir. GÖREV_SY(NR_TASKS) , yani süreçlerin alabileceği en büyük sayı değeri genellikle 512 olduğundan, 32768 haneden oluşan bir tablo tanımlamak bir depo ziyanı olurdu.
SüreçKimNo_eşleştir (hash_ pid( ) ve SüreçKimNo_karşılıkBul (unhash_ pid( )) fonksiyonları süreçKimlikNoEşleştiriş tablosu (pidhash table) ’na süreç eklemek veya çıkarmak için kullanılır.
SüreçKimNo_ile_gorev_bul(find_task_by_pid( )) fonksiyonu işleştiriş tablosunu arar ve belirli bir SüreçKimlikNosu ile verilen bir sürecin süreç tanımlayıcı işaretedicisini geri verir (ya da eğer süreci bulmazsa boş bir işaret edici
3.1.2.7 Serbest görev hanelerinin listesi (The list of task free entries)
Her süreç yaratılışında ya da yok edilişnde gorev (task) dizisi güncelleştirilmek zorundadır. Diziye yeni bir hane eklenişi etkin bir şekilde yapılır:diziyi doğrusal olarak arayıp ilk serbest haneyi bulmaktansa, çekirdek ayrı bir çift bağlı, çembersel olmayan bir serbest haneler listesi tutar. görevdizisi_serbestlistesi (tarray_freelist) o listenin ilk elemanını içerir; listedeki her serbest hane bir başka serbest haneye işaret eder, listenin en son elemanı boş bir işaretedici içerir.
Bir süreç yok edildiğinde, gorev (task) dizisi içindeki karşı düşen eleman liste başına eklenir. Şekil 3-5’ te, eğer ilk eleman 0 olarak sayılırsa, görevdizisi_serbestlistesi (tarray_freelist) değişkeni 4. elemana işaret eder çünkü o son serbest bırakılan elemandır. Önceden, 2. ve 1. elemanlara karşı düşen süreçler o sıra ile yok edilmişler. 2. eleman şekilde gösterilmeyen bir başka serbest gorevler (tasks) elemanına işaret eder. Şekil 3-5. Bir serbest haneli görev dizisi örneği

Diziden bir hane yok edilişi de etkin bir şekilde yapılır. Her süreç tanımlayıcı p , p’ye işaret ediciyi taşıyan görev (task) hanesine işaret eden bir görevdizisi_işaretedicisi (tarray_ ptr) alanı içerir. serbest_gorevhanesi_al (get_free_taskslot( ) ve serbest_gorev_hanesi_ekle (add_free_taskslot( )) fonsiyonları serbest bir hane almak ya da serbest bırakmak için kullanılır.