Saturday 15 December 2007

LINUX Çekirdeğini Anlamak - Süreçler 5

3.3 Süreçleri yaratış (Creating Processes)
Unix işletim sistemi kullanıcılarını memnun etmek için yüklü bir şekilde süreç yaratmağa başvurur. Örnek olarak, kabuk(shell) süreci kullanıcı ne zaman bir komut verirse kabuğun bir başka kopyasını çalıştıran yeni bir süreç yaratır. Geleneksel Unix sistemleri bütün süreçlere aynı şekilde muamele eder: ebeveyn süreç tarafından sahip olunan kaynaklar katlanır, ve bir kopyası çocuk sürece verilir.

Bu yaklaşım, süreç yaratışı çok yavaş ve verimsiz kılar, çünkü ebeveyn sürecinin bütün adres alanını kopyalamağı gerektirir. Çocuk süreç ebeveynine ait kaynakların tümünü okumak ya da değiştirmek ihtiyacını nadiren duyar; bir çok durumda, hemen bir çalıştırve() (execve( )) komutu verir ve o kadar dikkatli olarak yaratılmış adres alanını siliverir. Çağdaş Unix çekirdekleri bu sorunu üç ayrı mekanizma ile çözer:

•Yazarken Kopyala (Copy On Write) tekniği ebeveyn ve çocuğun aynı fiziki sayfaları okuyuşlarına olanak verir. Ne zaman biri fiziki sayfaya yazmağa kalkışırsa, çekirdek onun içeriğini yazan sürece atanmış olan yeni bir fiziksel sayfaya kopyalar.

• Hafifsıklet süreçler hem ebeveynin hem de çocuğun süreç başına yaratılan bir çok çekirdek veri yapısını paylaşmalarına olanak sağlar, sayfalayış (paging) tabloları (ve dolayısıyla bütün Kullanıcı Çalışış Türü adres alanı (User Mode address space) ) ve açık dosya tabloları gibi.

• vdallan() (vfork( )) sistem çağrısı ebeveyninin bellek adres alanını paylaşan bir süreç yaratır.
Çocuğun ihtiyaç duyduğu verinin ebeveyn tarafından üstüne yazılmaması için, ebeveynin çalıştırılışı çocuk bitinceye ya da çocuk yeni bir program çalıştırıncaya kadar engellenir.

3.3.1 Kopyala(), dallan(), ve vdallan() Sistem Çağrıları (The clone( ), fork( ), and vfork( ) System Calls)
Hafifsıklet süreçler Linux tarafından __kopyala() (__clone( )) adlı bir fonksiyon kullanarak yaratılırlar, dört tane parametre kullanan:

fn Yeni süreç tarafından çalıştırılan bir fonksiyon belirler; fonksiyondan geri dönüldüğünde, çocuk sona erer. Fonksiyon bir tam sayı (integer) döndürür, çocuk sürecinin bitiş kodunu temsil eden.

Arg fn( ) fonksiyonuna geçirilen veriye işaret eden bir işaret edici.

Bayraklar (Flags) Çeşitli bilgiler. Alçak byte çocuk bittiğinde ebeveyn sürece gönderilecek işaret (signal) sayısını belirler; İŞAÇOCUK (SIGCHLD) işareti genellikle seçilir. Kalan 3 byte bir grup kopyalayış bayrağını (clone flags) şifreler (encode), çocuk ile ebeveyn arasında paylaşılan kaynakları belirleyen. Bayraklar, kuruluklarında aşağıdaki anlamlara sahiptir:

KOPYA_SB (CLONE_VM) Sanal bellek tanımlayıcı ve bütün sayfa tabloları.
KOPYA_DS (CLONE_FS) :Kök kütüphaneyi ve şu anda çalışılan kütüphaneyi belirleyen tablo.
KOPYA_DOSYALAR (CLONE_FILES) : Açık dosyaları belirleyen tablo.
KOPYA_İŞAMUA (CLONE_SIGHAND) : İşaret muamele edicileri belirleyen tablo. KOPYA_SURECKIMLIKNO (CLONE_PID) : Süreç kimlik nosu.
KOPYA EİZLE (CLONE_PTRACE) : Eğer bir eizle() (ptrace()) sistem çağrısı ebeveyn sürecin izlenmesine(traced) neden oluyorsa, çocuğu da izlenecektir.
KOPYA_VDALLAN (CLONE_VFORK) : vdallan() (vfork( )) sistem çağrısı için kullanılır.
Çocuk_yığını (child_stack) çocuk sürecin esp kayıtına (esp register) atanacak olan Kullanıcı Çalışış Türü yığın işaret edicisini belirler.
3.3.2 Çekirdek Bağları (Kernel Threads)
Geleneksel Unix sistemleri bazı kritik görevleri arada çalışan süreçlere atar, disk tamponlarını yazmak, kullanılmayan sayfa çerçevelerini değiştirmek (swapping out unused page frames), ağ bağlantılarına hizmet vermek ve diğerleri gibi. Gerçekten, bu görevleri katı doğrusal üslupta yerine getirmek etkin olmaz; hem işlevleri hem de eğer arkaplanda çalışırlarsa son kullanıcı süreçleri daha iyi yanıt alır.

Bazı sistem süreçleri yalnız Çekirdek Çalışım Türünde koştukları için, çağdaş işletim sistemleri işlevlerini çekirdek bağlarına (kernel threads) atarlar, gereksiz Kullanıcı Çalışım Türü ile ağırlaşmayan. Linux’ta çekirdek bağları alışımış süreçlerden şu açılarda farklıdır:

• Her çekirdek bağı tek bir özel çekirdek fonksiyonunu çaıştırır, alışılmış süreçler ise çekirdek fonksiyonlarını yalnız sistem çağrıları içinden çalıştırır.

• Çekirdek bağları yalnız Kernel Çelrşrm Türünde koşarlar, alışılmış süreçler ise bazan Çekirdek bazan Kullanıcı Çalışım Türünde koşarlar.

• Çekirdek bağları yalnız Çekirdek Çalışım Türünde çalıştıkları için, yalnız SAYFA_ÖTELEYİŞİ (PAGE_OFFSET) ’ten büyük doğrusal adresleri kullanırlar. Alışılmış süreçler, öte yandan, yalnız 4 gigbyte doğrusal adres kullanırlar, Kullanıcı ay da Çekirdek Çalışım Türlerinden her birinde.

3.3.2.1 Bir çekirdek bağı yaratmak (Creating a kernel thread)
çekirdek_bağı() (kernel_thread()) fonksiyonu yeni bir çekirdek bağı yaratır ve yalnız bir başka çekirdek bağı tarafından çalıştırılabilir. …
3.3.2.2 Süreç 0 (Process 0)
Bütün süreçlerin atası veya tarihsel nedenlerle değiştirici süreç (swapper process) adı verilen
Süreç0 (process0), Linux’un başlatılış aşamasında çekirdeği_başlat() (start_kernel()) fonksiyonunca sıfırdan yaratılan bir çekirdek bağıdır.

3.3.2.3 Süreç 1 (Process 1)
Süreç tarafından yaratılan çekirdek bağı sıfırdan-başlat() (init()) fonksiyonunu çalıştırır, o da çekirdek_bağı() (kernel_thread( )) fonksiyonunu dört defa çalıştırarak sıradan çekirdek görevleri için gerekli dört çekirdek bağını başlatır.

kernel_thread(bdflush, NULL, CLONE_FS CLONE_FILES CLONE_SIGHAND);
kernel_thread(kupdate, NULL, CLONE_FS CLONE_FILES CLONE_SIGHAND);
kernel_thread(kpiod, NULL, CLONE_FS CLONE_FILES CLONE_SIGHAND);
kernel_thread(kswapd, NULL, CLONE_FS CLONE_FILES CLONE_SIGHAND);