Bölüm 2: İşletim Sistemi Yapıları
Giriş
Öğrenme Çıktıları
İşletim sisteminin sunduğu servisleri; süreç, adres uzayı, dosya, bağlama ve boru hattı kavramlarını açıklamak.
Kullanıcı kipinden çekirdek kipine geçişi, parametre aktarımını ve temel POSIX çağrılarını adım adım izlemek.
Monolitik, katmanlı, mikroçekirdek, modüler, hibrit ve exokernel yapılarını güçlü ve zayıf yönleriyle karşılaştırmak.
Hipervizör türlerini, konteynerleri, bağlayıcı/yükleyiciyi ve önyükleme sürecini tanımak.
Giriş
Neden Yapı Önemli?
- İşletim sistemi; süreç, bellek, dosya, G/Ç ve ağ yönetimi gibi çok sayıda bileşenden oluşur.
- Bu bileşenlerin nerede çalışacağına (çekirdek / kullanıcı kipi) ve nasıl haberleşeceğine (fonksiyon çağrısı / mesaj) dair stratejiye işletim sistemi yapısı denir.
- Yapı; karmaşıklığı yönetmeyi, değişikliği, hata ayıklamayı ve taşınabilirliği doğrudan etkiler.
Servisler
İşletim Sistemi Servisleri
Servislere kullanıcı arayüzleri ve programlar tarafından sistem çağrıları üzerinden erişilir (Silberschatz, Şekil 2.1’den uyarlanmıştır).
Servisler
Servisler Kime Hizmet Eder?
- Arayüz: komut satırı, GUI, dokunmatik, sesli.
- Program yürütme: yükle, çalıştır, normal / hatalı sonlandır.
- G/Ç işlemleri: program aygıta doğrudan değil OS üzerinden erişir.
- Dosya sistemi: oluştur, sil, oku, yaz, ara, izinler.
- İletişim: paylaşılan bellek veya mesaj aktarımı (yerel / ağ).
- Hata algılama: donanım, aygıt ve program hataları.
- Kaynak ayırma: CPU, bellek, depolama birden çok sürece paylaştırılır.
- Kaynak izleme (accounting): kim, ne kadar kaynak kullandı; günlük kayıtları.
- Koruma: süreçler birbirine ve çekirdeğe zarar veremez.
- Güvenlik: kimlik doğrulama, yetkilendirme, dış saldırılara karşı savunma.
ls, cp, ps, paket yöneticisi, derleyici, dosya yöneticisi…Temel Kavramlar
Süreç (Process)
- Süreç, yürütülmekte olan bir programdır; program diskteki pasif dosya, süreç onun etkin örneğidir.
- Her süreçle ilişkili: adres uzayı (kod, veri, yığın), yazmaçlar (PC, SP), açık dosyalar, alarmlar, ilişkili süreçler ve diğer kaynaklar.
- OS bu bilgileri süreç tablosunda tutar; askıya alınan süreç, PCB sayesinde kaldığı yerden devam eder.
- Süreçler birbirleriyle IPC (süreçler arası iletişim) ile haberleşebilir.
Temel Kavramlar
Süreç Ağacı
Bir süreç fork() ile çocuk süreçler oluşturabilir; çocuklar da kendi çocuklarını oluşturur. Sonuç bir ağaçtır.
Başlangıçta yalnızca A süreci vardır. Linux’ta tüm ağacın kökü PID 1 olan systemd (veya init) sürecidir.
A süreci iki kez fork() çağırır: B ve C, A’nın çocuklarıdır (A onların atasıdır).
B süreci D, E ve F olmak üzere üç çocuk oluşturur. pstree -p komutu bu ağacı gösterir.
Temel Kavramlar
Adres Uzayı ve Bellek Kesimleri
- Adres uzayı: bir sürecin kullanabildiği adresler kümesi (0 … max). x86-64 Linux’ta kullanıcı alanı 128 TiB’dir.
- Bellekte aynı anda çok sayıda süreç bulunur; OS onları birbirinden ve çekirdekten korur.
- Metin: makine kodu; salt okunur, aynı programı çalıştıran süreçler ve tüm iş parçacıkları paylaşır.
- Veri + BSS: global ve static değişkenler. Öbek: çalışma anında ayrılan dinamik bellek. İkisi de sürecin iş parçacıklarınca paylaşılır.
- Yığın: parametreler, yerel değişkenler, dönüş adresleri; her iş parçacığının kendi yığını vardır.
- Fiziksel bellekten büyük adres uzayları sanal bellek ile mümkündür (Bölüm 9).
Temel Kavramlar
Dosyalar ve Dizin Hiyerarşisi
- Dosya: verileri kalıcı olarak saklayan adlandırılmış birim (metin, resim, video, program…).
- OS disk bloklarını ve aygıt ayrıntılarını gizler; temiz bir soyutlama sunar.
- Dosyalar dizin ağacında tutulur. Yol adı mutlak (
/home/ali/notlar.txt) veya çalışma dizinine göre göreli (ali/notlar.txt) olabilir. - Açılan dosyaya küçük bir tamsayı, dosya tanıtıcı (fd) verilir; 0, 1, 2 = stdin, stdout, stderr.
- Özel dosyalar: aygıtlar dosya gibi görünür. Blok (
/dev/sda,/dev/nvme0n1) ve karakter (/dev/tty, seri port) aygıtları.
Temel Kavramlar
Dosya Sistemini Bağlama (mount)
Bağlamadan önce USB bellekteki dosya sistemi ayrı bir ağaçtır; ona hiçbir yol adıyla erişilemez.
mount, yeni dosya sisteminin kökünü mevcut ağaçtaki bir bağlama noktasına (boş dizin /mnt) iliştirir.
Bağlandıktan sonra USB’deki dosyalar hiyerarşinin parçasıdır. Windows’ta bunun yerine genellikle sürücü harfleri (C:, D:) kullanılır.
Temel Kavramlar
mount Komutu ve Seçenekleri
$ lsblk # diskleri ve bölümleri listele $ sudo mount /dev/sdb1 /mnt # sdb1'i /mnt dizinine bağla $ sudo mount -o ro /dev/sdb1 /mnt # salt okunur (read-only) bağla $ sudo mount -o remount,rw /mnt # okuma-yazma olarak yeniden bağla $ findmnt /mnt # bağlama bilgisini göster $ sudo umount /mnt # bağlantıyı kaldır
ro / rwSalt okunur ya da okuma-yazma bağlama. Kurtarma ve adli inceleme için ro güvenlidir.
/etc/fstabAçılışta otomatik bağlanacak dosya sistemleri burada (veya systemd mount birimlerinde) tanımlanır.
Takılan USB bellek udisks2 tarafından kendiliğinden /run/media/… altına bağlanır.
Temel Kavramlar
Boru Hattı (pipe)
- İki süreci bağlayan, çekirdekte tamponlanan tek yönlü bir bayt kanalıdır; süreçler onu dosya gibi
read/writeile kullanır. - Anonim:
pipe()ile oluşur, ata-çocuk süreçler arasında. Adlandırılmış (FIFO):mkfifoile dosya sisteminde adı vardır, ilgisiz süreçler kullanabilir.
$ ls -l | grep "notlar"
Kabuk önce pipe(fd) çağırır: çekirdek bir tampon ve iki uç açar (fd[0] okuma, fd[1] yazma).
Kabuk iki kez fork eder; dup2 ile ls’in stdout’u yazma ucuna, grep’in stdin’i okuma ucuna yönlendirilir.
ls listeyi boruya yazar, grep okur ve yalnızca “notlar” içeren satırları terminale yazar.
Akış denetimi çekirdekte: tampon dolunca yazan, boşken okuyan bloke olur. ls bitip yazma ucu kapanınca grep dosya sonu (EOF) görür.
Temel Kavramlar
Kilitlenme (Deadlock)
- Kümedeki her süreç, başka bir sürecin tuttuğu kaynağı beklerse hiçbiri ilerleyemez: kilitlenme.
- Trafikte dört yönden kavşağa girip birbirini bekleyen araçlar gibi. Ayrıntılar Bölüm 7’de.
Kareden sürece ok: kaynak o süreçte. Süreçten kareye ok: süreç o kaynağı istiyor (kesikli = ileride isteyecek).
Koruma
Çift Kip: Kullanıcı ve Çekirdek
- CPU’daki mod biti hangi kipte çalışıldığını gösterir. G/Ç, zamanlayıcıyı ayarlama, kesmeleri kapatma, sayfa tablolarını değiştirme gibi ayrıcalıklı komutlar yalnızca çekirdek kipinde çalışır.
- Kullanıcı kipinde ayrıcalıklı komut denenirse donanım tuzak üretir, OS süreci sonlandırır. x86’da halkalar 0–3 (Linux ve Windows yalnızca 0 ve 3’ü kullanır), ARM’da EL0–EL3; sanallaştırma için ek bir kip vardır.
Kullanıcı süreci kullanıcı kipinde kendi kodunu çalıştırır.
Bir sistem çağrısı (veya kesme / istisna) tuzak üretir: mod biti 0 olur, CPU çekirdekteki sabit giriş noktasına atlar.
Çekirdek, istenen hizmeti tam ayrıcalıkla yürütür.
İş bitince özel dönüş komutu mod bitini 1 yapar ve kullanıcı koduna döner.
Süreç, sistem çağrısından sonraki komuttan devam eder; sonuç bir yazmaçtadır.
Koruma
Zamanlayıcı (Timer)
- Amaç: bir sürecin sonsuz döngüye girip CPU’yu hiç bırakmamasını önlemek.
- OS sayaca bir değer yükler; bu, ayrıcalıklı bir komuttur.
- Fiziksel saatin her darbesinde sayaç azalır; sıfır olunca kesme üretilir ve OS kontrolü yeniden kazanır.
- OS, zaman dilimini dolduran süreci keser ve CPU’yu başka sürece verir (kesintili zamanlama). Süreci sonlandırmak ancak CPU süresi sınırı (ör.
RLIMIT_CPU) aşılırsa söz konusudur. - Linux’ta düzenli tik 100–1000 Hz’dir; boşta tik üretmeyen tickless (NO_HZ) kip enerji kazandırır.
OS, A’yı çalıştırmadan önce sayaca 3 yükler.
Her saat darbesinde sayaç bir azalır: 2.
Sayaç 1; A hâlâ CPU’da.
Sayaç 0: zamanlayıcı kesmesi. CPU çekirdek kipine geçer, kesme işleyicisi çalışır.
Zamanlayıcı A’nın dilimi dolduğu için B’yi seçer ve sayacı yeniden yükler.
Sistem Çağrıları
Sistem Çağrısı Nedir?
- Programların işletim sistemi servislerine (dosya, bellek, süreç, zaman, ağ…) erişmek için kullandığı tanımlı arayüz.
- Uygulama tarafından istenir, çekirdek tarafından çekirdek kipinde yürütülür.
- Programcı çoğunlukla çağrıları doğrudan değil bir API üzerinden kullanır: POSIX (glibc, musl), Windows API, Java API. API taşınabilirlik ve kolaylık sağlar.
- Çağrı kümesi sistemden sisteme değişir: Linux x86-64’te yaklaşık 370 çağrı vardır. Temel kavramlar ise ortaktır.
strace(Linux),dtruss(macOS) ve Process Monitor (Windows) bir programın yaptığı çağrıları gösterir.
Sistem Çağrıları
API → Sistem Çağrısı Arayüzü → Çekirdek
Uygulama libc’deki open() sarmalayıcısını çağırır; sarmalayıcı çağrı numarasını yazmaca koyar ve tuzak komutunu çalıştırır.
Çekirdekteki sistem çağrısı arayüzü, numarayı sistem çağrısı tablosunda indis olarak kullanır (x86-64 Linux: open = 2).
Tablodaki gösterici çekirdekteki gerçeklemeye götürür: yol çözülür, izinler denetlenir, açık dosya kaydı oluşturulur.
Sonuç (ilk boş tanıtıcı: 0, 1, 2 dolu olduğundan 3) kullanıcıya döner. Not: güncel glibc open()’u aslında openat (257) ile gerçekler.
Sistem Çağrıları
Örnek: Bir Dosyayı Başka Dosyaya Kopyalamak
Kullanıcıdan ad almak bile iki çağrı ister: ekrana istem yaz (write), klavyeden oku (read).
Aynı işlem çıktı dosyası için tekrarlanır.
open başarısız olursa (dosya yok, izin yok) −1 döner; program hata mesajı yazıp çıkar.
open(…, O_WRONLY | O_CREAT | O_EXCL): dosya zaten varsa hata verir.
Asıl iş: read 0 (dosya sonu) dönene kadar okunan baytlar write ile yazılır.
Her açık dosya close ile kapatılır.
Kullanıcıya bilgi verilir.
exit ile süreç sonlanır. Böyle basit bir program bile onlarca çağrı yapar; strace -c cp a b ile sayılabilir.
Sistem Çağrıları
read(fd, buffer, nbytes) Çağrısının 11 Adımı
1–3: Parametreler yığına itilir (Tanenbaum’un örneğindeki tarihsel 32-bit x86 kuralı). x86-64’te ilk altı parametre yazmaçlarla aktarılır.
4: Kütüphanedeki read() sıradan bir fonksiyon gibi çağrılır; dönüş adresi yığına girer.
5: Kütüphane çağrı numarasını çekirdeğin beklediği yazmaca koyar (Linux x86-64: rax = 0).
6: Tuzak komutu (x86-64: syscall) çalışır; CPU çekirdek kipine geçip çekirdekteki sabit adrese atlar.
7: Çekirdek çağrı numarasına bakar ve sistem çağrısı tablosu üzerinden doğru işleyiciye dallanır.
8: İşleyici fd’den buffer’a en çok nbytes bayt kopyalar. Veri hazır değilse süreç bloke olur, CPU başka sürece verilir.
9: İş bitince kontrol kullanıcı kipine, tuzaktan sonraki komuta döner; sonuç (okunan bayt sayısı) yazmaçtadır.
10: Kütüphanedeki read() kullanıcı programına döner.
11: Program parametreleri yığından temizler (SP artırılır) ve sonraki komutla devam eder.
Sistem Çağrıları
Sistem Çağrılarında Parametre Aktarımı
- Yazmaçlar: en hızlı yol; Linux en çok 6 parametreyi böyle aktarır.
- Bellekte blok / tablo: parametreler bellekte, adresi yazmaçta (şekil). Örn.
clone3(struct clone_args *). - Yığın: program parametreleri iter, OS çeker.
| x86-64 Linux | Görev |
|---|---|
rax | çağrı numarası; dönüşte sonuç |
rdi, rsi, rdx | 1., 2., 3. parametre |
r10, r8, r9 | 4., 5., 6. parametre (C kuralındaki rcx yerine r10) |
syscall | çekirdeğe geçiş; rcx ve r11 bozulur |
| ARM64 | x8 = numara, x0–x5 parametre, svc #0 |
errno’ya yazar ve çağırana −1 verir.Sistem Çağrıları
Kod İzleme: write() ile Ekrana Yazmak
#include <unistd.h> // write() #include <string.h> // strlen() int main(void) { const char *msg = "Merhaba, Dünya!\n"; size_t len = strlen(msg); // 17 bayt ssize_t n = write(1, msg, len); // 1: stdout if (n == -1) return 1; // hata return 0; }
msg, salt okunur veri kesimindeki dizgeyi gösterir.
“Merhaba, ” 9 + “Dünya” 6 (ü, UTF-8’de 2 bayt) + “!” ve “\n” 2 = 17 bayt. Sabit 15 yazılsaydı çıktı “Merhaba, Dünya” olarak kesilirdi.
libc sarmalayıcısı: rax=1 (write), rdi=1, rsi=msg, rdx=17; ardından syscall.
Çekirdek kipinde sys_write, 17 baytı fd 1’in bağlı olduğu terminale aktarır.
Kullanıcı kipine dönüş: n = 17, yazılan bayt sayısı. Daha küçük olabilir (kısmi yazma).
n −1 değil, hata yok. Hata olsaydı −1 döner ve errno ayarlanırdı.
main 0 döndürür; libc exit_group(0) çağrısıyla süreci sonlandırır.
Sistem Çağrıları
Kod İzleme: read() ve Bloke Olma
#include <unistd.h> #include <stdio.h> int main(void) { char buf[100]; ssize_t n = read(0, buf, sizeof(buf)); if (n == -1) { perror("okuma hatası"); return 1; } write(1, buf, n); // tam n bayt return 0; }
buf yığında ayrılır; içeriği ilklenmemiştir.
fd 0 = stdin (klavye). Henüz satır yok: süreç bloke olur, zamanlayıcı başka süreci çalıştırır.
Kullanıcı “selam” yazıp Enter’a basar; terminal sürücüsü karakterleri ekrana yansıtır ve satırı tamponlar.
Satır tamamlanınca 6 bayt buf’a kopyalanır, süreç uyanır, read 6 döndürür. Sona '\0' eklenmez.
n = 6, hata yok; perror atlanır.
write tam 6 baytı yazar. buf bir C dizgisi olmadığından printf("%s", buf) hatalı olurdu.
Program 0 ile sonlanır.
Sistem Çağrıları
Standart C Kütüphanesi ve Sistem Çağrıları
Program printf’i çağırır; bu bir sistem çağrısı değil, kullanıcı kipinde çalışan bir kütüphane fonksiyonudur.
libc metni biçimler ve stdout tamponuna koyar. Terminalde tampon satır tamponludur; dosyaya/boruya yönlendirilince tam tamponludur.
“\n” geldiği için libc write(1, tampon, 8) sistem çağrısını yapar; çekirdek baytları terminale aktarır.
write 8 döndürür, printf de çağırana döner. strace ./merhaba yalnızca write’ı gösterir, printf’i göstermez.
Sistem Çağrıları
Sistem Çağrısı Türleri
oluştur, sonlandır, yükle, bekle, sinyal
fork, execve, exit, waitpid, killoluştur, sil, aç, kapat, oku, yaz, öznitelik
open, read, write, close, stataygıt iste / bırak, oku, yaz, denetle
ioctl, read, write, mmapsaat, tarih, sistem ve süreç bilgisi
getpid, uname, clock_gettimebağlantı kur, mesaj gönder/al, paylaşılan bellek
pipe, socket, sendmsg, shm_openizinleri al / ayarla, kullanıcı kimliği
chmod, chown, umask, setuidWindows karşılıkları: CreateProcess, ReadFile, DeviceIoControl, GetSystemTime, CreatePipe, SetFileSecurity… (Silberschatz, Şekil 2.8)
Sistem Çağrıları
POSIX Çağrıları: Süreç Yönetimi
| Çağrı | Açıklama |
|---|---|
pid = fork() | Atanın kopyası olan bir çocuk süreç oluşturur. |
pid = waitpid(pid, &statloc, options) | Bir çocuğun sonlanmasını bekler; çıkış durumunu statloc’a yazar. |
s = execve(name, argv, envp) | Sürecin bellek görüntüsünü yeni programla değiştirir; başarılıysa geri dönmez. |
exit(status) | Süreci sonlandırır, durumu ataya iletir. |
errno ayarlanır. pid: süreç kimliği, s: dönüş kodu. Windows’ta tek bir CreateProcess çağrısı, fork + execve işini birlikte yapar.Sistem Çağrıları
fork(): Süreç Oluşturma
Çocuk, atanın adres uzayının kopyasını alır: aynı kod, aynı değişken değerleri, aynı açık dosyalar; ama ayrı bir adres uzayında çalışır.
Ata süreçte x = 5. Süreç pid = fork(); satırına gelir.
fork bir kez çağrılır, iki kez döner: atada çocuğun PID’si (1001), çocukta 0. Hata olursa yalnızca atada −1 döner.
Çocuk x = 6 yazınca yalnızca kendi kopyası değişir; atada x hâlâ 5. Modern OS’lar sayfaları yazılana dek paylaşır (copy-on-write), kopyalama ertelenir.
Sistem Çağrıları
Kod İzleme: Basit Bir Kabuk
#define TRUE 1 while (TRUE) { /* sonsuza dek */ type_prompt(); /* istemi yaz */ read_command(command, parameters); if (fork() != 0) { /* ata süreç */ waitpid(-1, &status, 0); } else { /* çocuk süreç */ execve(command, parameters, 0); } }
Kabuk istemi yazar ve kullanıcıyı bekler.
Kullanıcı ls yazar; komut ve parametreler ayrıştırılır.
fork kabuğun kopyasını oluşturur. Atada sonuç 1045 (≠ 0), çocukta 0’dır.
Ata waitpid(-1, …) ile herhangi bir çocuğun bitmesini bekler; bloke olur.
Çocuk execve ile kendini ls programıyla değiştirir (PID aynı kalır); ls çıktısını yazar. Gerçek kabuklar komutu PATH’te arar.
ls exit(0) ile biter; atanın waitpid’i döner, status çıkış durumunu içerir.
Döngü başa döner, yeni istem yazılır.
Sistem Çağrıları
POSIX Çağrıları: Dosya Yönetimi
| Çağrı | Açıklama |
|---|---|
fd = open(file, how, …) | Dosyayı okuma, yazma veya ikisi için açar (gerekirse oluşturur). |
s = close(fd) | Açık dosyayı kapatır. |
n = read(fd, buffer, nbytes) | Dosyadan tampona en çok nbytes bayt okur. |
n = write(fd, buffer, nbytes) | Tampondan dosyaya veri yazar. |
position = lseek(fd, offset, whence) | Dosya konum göstericisini taşır (SEEK_SET, SEEK_CUR, SEEK_END). |
s = stat(name, &buf) | Dosyanın durum bilgisini (boyut, izinler, zamanlar) alır. |
fd: dosya tanıtıcı, n: bayt sayısı, position: dosya başına göre konum. Güncel Linux ayrıca openat, pread/pwrite, statx sunar.
Sistem Çağrıları
POSIX Çağrıları: Dizin Yönetimi ve Diğerleri
| Çağrı | Açıklama |
|---|---|
s = mkdir(name, mode) | Yeni bir dizin oluşturur. |
s = rmdir(name) | Boş bir dizini siler. |
s = link(name1, name2) | name1’in gösterdiği dosyaya name2 adlı yeni bir dizin girdisi oluşturur. |
s = unlink(name) | Bir dizin girdisini siler. |
s = mount(special, name, flag) | Bir dosya sistemini bağlar (Linux: mount(src, hedef, tür, bayrak, veri)). |
s = umount(special) | Bir dosya sisteminin bağlantısını kaldırır. |
s = chdir(dirname) | Çalışma dizinini değiştirir. |
s = chmod(name, mode) | Dosyanın koruma (izin) bitlerini değiştirir. |
s = kill(pid, signal) | Bir sürece sinyal gönderir (yalnızca öldürmek için değil). |
seconds = time(&seconds) | 1 Ocak 1970 00:00 UTC’den (Unix epoch) bu yana geçen saniye. |
32-bit time_t 19 Ocak 2038’de taşar (2038 sorunu); güncel sistemler 64-bit time_t kullanır.
Sistem Çağrıları
link ve unlink: Bir Dosya, İki Ad
UNIX’te dizin, (i-düğüm numarası, ad) çiftlerinden oluşan bir tablodur. Dosyanın asıl bilgisi i-düğümdedir (inode).
Başlangıç: /usr/jim/memo 70 numaralı i-düğümü gösterir; bağlantı sayısı 1.
link("/usr/jim/memo", "/usr/ast/note"): /usr/ast’a aynı i-düğümü (70) gösteren yeni girdi eklenir. Veri kopyalanmaz; sayı 2 olur.
unlink("/usr/jim/memo") yalnızca girdiyi siler; dosya note adıyla yaşar. Sayı 0 olunca (ve açık tutan kalmayınca) blokları serbest kalır.
Sistem Çağrıları
UNIX Çağrılarının Win32 API Karşılıkları
| UNIX | Win32 |
|---|---|
fork | CreateProcess |
waitpid | WaitForSingleObject |
execve | (yok: CreateProcess) |
exit | ExitProcess |
open | CreateFile |
close | CloseHandle |
read | ReadFile |
write | WriteFile |
lseek | SetFilePointerEx |
stat | GetFileAttributesEx |
| UNIX | Win32 |
|---|---|
mkdir | CreateDirectory |
rmdir | RemoveDirectory |
link | CreateHardLink |
unlink | DeleteFile |
mount | SetVolumeMountPoint |
umount | DeleteVolumeMountPoint |
chdir | SetCurrentDirectory |
chmod | (yok: ACL, SetFileSecurity) |
kill | (yok: TerminateProcess) |
time | GetSystemTime |
ntdll.dll’deki Nt… fonksiyonları (ör. NtCreateFile) yapar. Bu çağrıların numaraları sürümden sürüme değiştiği ve belgelenmediği için programlar API’yi kullanır. Tanenbaum 3e’de “yok” görünen link ve mount karşılıkları bugün mevcuttur.Yapılar
İşletim Sistemi Yapıları: Genel Bakış
Bir yerleşim değil, düzenleme ilkesidir: bileşenler hiyerarşik katmanlara ayrılır (THE, MULTICS halkaları).
Ayrı bir eksen: donanımın kendisi sanallaştırılır, üzerinde birden çok işletim sistemi çalışır.
Yapılar
Basit Yapı: MS-DOS
- Belirgin bir yapısı yoktur: küçük, basit ve sınırlı donanım için yazılmıştır.
- Arayüzler ve işlev düzeyleri iyi ayrılmamıştır; uygulamalar BIOS rutinlerine ve donanıma doğrudan erişebilir.
- Intel 8088’de çift kip olmadığından donanım koruması yoktu: tek bir hatalı program tüm sistemi çökertebilir.
- Modüller arasında net sınır ve veri gizleme (data hiding) yoktur.
- Silberschatz bunu “basit yapı” olarak, monolitik çekirdeklerden ayrı ele alır.
Yapılar
Monolitik Sistem
Tüm işletim sistemi, çekirdek kipinde çalışan tek bir program olarak bağlanır. Her prosedür diğerini doğrudan çağırabilir.
- Ana program: çağrı numarasına bakıp istenen hizmet prosedürünü başlatır.
- Hizmet prosedürleri: her sistem çağrısını gerçekleştirir.
- Yardımcı prosedürler: birden çok hizmetin ortak işleri (ör. kullanıcı belleğinden veri almak).
Çoğu monolitik çekirdek bugün sürücüleri ve dosya sistemlerini çalışma anında yüklenebilir modül olarak da alır.
Yapılar
Geleneksel UNIX ve Linux: Monolitik Çekirdek
Güçlü yönler
- Doğrudan fonksiyon çağrıları: IPC ve kip geçişi yok, hızlı.
- Tasarımı ve gerçeklemesi görece basit, bütünleşik.
Zayıf yönler
- Tek bir sürücü hatası tüm çekirdeği çökertebilir.
- Dev kod tabanı (Linux 2025’te 40 milyon satırı aştı): hata bulmak ve bakım zor.
Yapılar
Katmanlı Yapı
Katman 0: kesmelerde ve zamanlayıcı dolunca süreçler arasında geçiş yapar; üstteki katmanlar tek CPU’yu düşünmek zorunda kalmaz.
Katman 1: süreçlere bellek ayırır, sayfaları tambur (o günün diski) ile bellek arasında taşır.
Katman 2: her süreç ile operatör konsolu arasındaki iletişimi yönetir.
Katman 3: G/Ç aygıtlarını yönetir; üst katmanlar soyut aygıtlarla çalışır.
Katman 4: kullanıcı programları; bellek, konsol ve G/Ç ayrıntılarıyla uğraşmaz.
Katman 5: sistem operatörü. Dijkstra’nın THE sistemi (1968) bu altı katmandan oluşuyordu.
OS katmanlara bölünür: en alt katman donanıma, en üst katman kullanıcıya en yakındır. Her katman yalnızca altındakilerin hizmetlerini kullanır.
Artılar
- Hata ayıklama ve doğrulama katman katman yapılır; hata ilgili katmanda aranır.
- Soyutlama ve veri gizleme kolaydır.
Eksiler
- Katmanları doğru tanımlamak zordur (bağımlılıklar çoğu kez iki yönlüdür).
- Her katman geçişi ek yük getirir. Fikir bugün ağ yığınlarında yaşar.
Yapılar
Mikroçekirdek (Microkernel)
- Gerekli olmayan her şey çekirdekten çıkarılır; çekirdekte yalnızca IPC (mesaj aktarımı), temel zamanlama, adres uzayı yönetimi ve kesme işleme kalır.
- Sürücüler, dosya sistemleri ve ağ yığını kullanıcı kipinde sunucu süreçler olarak çalışır; yeni hizmetler kullanıcı alanına eklenir, çekirdek değişmez.
- Örnekler: MINIX 3, QNX Neutrino (otomotiv), L4 ailesi, biçimsel olarak doğrulanmış seL4. macOS ise saf mikroçekirdek değil, hibrit XNU’dur.
- Mekanizma çekirdekte, politika dışarıda: çekirdek öncelikli süreçleri çalıştırmayı sağlar; önceliklerin nasıl atanacağına kullanıcı kipindeki bileşen karar verir.
Artılar
- Çöken sürücü sistemi düşürmez, yeniden başlatılabilir.
- Küçük çekirdek: test, doğrulama ve taşıma kolay.
- Daha güvenli: saldırı yüzeyi küçük.
Eksiler
- Mesajlar ve kip geçişleri ek yük getirir; L4 tasarımları bunu büyük ölçüde azalttı.
Yapılar
Mikroçekirdekte Bir Dosya Okuma
Uygulama, dosya sistemi sunucusuna bir mesaj gönderir; mesaj çekirdeğin IPC mekanizmasından geçer.
Çekirdek mesajı, kullanıcı kipindeki dosya sistemi sunucusuna teslim eder.
Dosya sistemi hangi bloğun okunacağını bulur ve yine çekirdek üzerinden disk sürücüsüne mesaj yollar.
Sürücü, çekirdeğin izin verdiği G/Ç ile donanıma erişir; yanıtlar aynı yoldan döner. Monolitik çekirdekte bu iş tek bir fonksiyon çağrı zinciridir.
Yapılar
MINIX 3: Bir Mikroçekirdek Örneği
Sürücülerin sağlığını denetler; çöken bir sürücüyü (ör. TTY) kullanıcı fark etmeden yeniden başlatır: kendini onaran sistem.
Sürücü kullanıcı kipindedir; G/Ç portlarına yalnızca çekirdek çağrılarıyla, izin verilen ölçüde erişir. Hatalı bir sürücü belleği bozamaz.
Yapılar
İstemci–Sunucu Modeli
Mikroçekirdek üzerinde süreçler iki sınıfa ayrılır: hizmet isteyen istemciler ve hizmet veren sunucular. Haberleşme yalnızca mesajlarladır.
İstemci, mesajın yerelde mi yoksa ağdaki başka bir makinede mi işlendiğini bilmek zorunda değildir: model doğal olarak dağıtık sistemlere genişler (bugünün web ve mikroservis mimarileri).
Yapılar
Tanenbaum – Torvalds Tartışması (1992)
- “LINUX is obsolete” başlıklı iletisinde monolitik tasarımı 1970’lerin geride kalmış bir yaklaşımı olarak gördü.
- Mikroçekirdek daha modüler, esnek, taşınabilir; bir bileşendeki hatanın verdiği zarar sınırlı.
- Donanım hızlandıkça mesajlaşmanın ek yükü önemsizleşir.
- Monolitik çekirdeğin tasarımı ve gerçeklemesi daha basit; doğrudan fonksiyon çağrıları daha hızlı.
- Süreçler arası mesajlaşmaya gerek yok; pratikte çalışan kod önemli.
- Açık kaynak geliştirme modeli Linux’un hızla gelişmesini sağladı.
Yapılar
Modüler Yapı: Yüklenebilir Çekirdek Modülleri
- Çekirdekte yalnızca temel bileşenler bulunur; diğer hizmetler açılışta veya çalışma anında modül olarak yüklenir (Linux LKM, FreeBSD, Solaris).
- Katmanlıya benzer (tanımlı arayüzler) ama daha esnektir: her modül diğerini çağırabilir. Mikroçekirdeğe benzer ama mesaj gerekmez, modüller çekirdek kipinde çalışır.
Açılışta çekirdek ve initramfs’teki gerekli modüller yüklüdür. lsmod yüklü modülleri listeler.
USB bellek takılır: udev olayı modprobe usb-storage ve vfat modüllerini (bağımlılıklarıyla) yükletir.
Modül kendini çekirdeğe kaydeder ve doğrudan fonksiyon çağrılarıyla çalışır: hızlı, ama izolasyon yoktur; hatalı modül çekirdeği çökertebilir.
Kullanım sayısı 0 olunca modprobe -r (veya rmmod) modülü bellekten çıkarır. Modüllerin çekirdek sürümüyle uyumlu olması gerekir.
Yapılar
Hibrit Çekirdek: Windows ve macOS
Windows NT: mikroçekirdek fikirleri (alt sistemler, nesne/mesaj temelli tasarım) korunmuş, ama performans için yürütücü, grafik ve sürücüler çekirdek kipine alınmıştır.
macOS / iOS XNU: Mach mikroçekirdeği ile BSD katmanı aynı çekirdek adres uzayında birleşir: mikroçekirdeğin modülerliği + monolitik hız.
Yapılar
Exo-Çekirdek (Exokernel)
- MIT’de Engler ve Kaashoek’un araştırma mimarisi (1995): çekirdek Aegis, kütüphane OS ExOS. Ticari bir işletim sistemi değildir.
- Yönetimi korumadan ayırır: çekirdek yalnızca kaynakların kime ait olduğunu izler; soyutlamaları (dosya, sanal bellek) uygulama düzeyindeki LibOS’lar sağlar.
- Uygulamaya özgü bellek yönetimi ve önbellekleme ile yüksek başarım; ama uygulama geliştirmek karmaşıktır. Fikir bugün unikernel’lerde ve DPDK / SPDK gibi çekirdeği atlayan G/Ç’de yaşar.
Yapılar
Yapıların Karşılaştırılması
| Yapı | Çekirdekte ne var? | Güçlü yön | Zayıf yön | Örnek |
|---|---|---|---|---|
| Basit | her şey, sınırsız | küçük, basit | koruma yok | MS-DOS |
| Monolitik | tüm servisler | hız | hata yalıtımı yok | UNIX, Linux |
| Katmanlı | hiyerarşik katmanlar | doğrulama kolay | ek yük, tanım zor | THE, MULTICS |
| Mikroçekirdek | IPC, zamanlama, bellek | güvenilirlik | mesaj ek yükü | MINIX 3, QNX, seL4 |
| Modüler | çekirdek + modüller | esneklik, hız | modül = tam yetki | Linux, FreeBSD |
| Hibrit | mikro + seçili servisler | denge | karmaşıklık | Windows, macOS |
| Exokernel | yalnızca koruma | uygulamaya özgü hız | geliştirme zor | Aegis/ExOS |
Gerçek sistemler saf değildir: Linux monolitik + modüler, Windows ve macOS hibrittir; hemen hepsi bir ölçüde katmanlıdır.
Sanal Makineler
Sanal Makine Kavramı
- Hipervizör (VMM), tek bir fiziksel donanım üzerinde her biri bağımsız bir bilgisayar gibi görünen sanal makineler oluşturur.
- Her konuk OS kendi CPU’su, RAM’i, diski ve G/Ç aygıtları olduğuna inanır; farklı işletim sistemleri aynı donanımda eş zamanlı çalışabilir.
- Fikir IBM VM/370’e (1972) dayanır; bugün bulut bilişimin temelidir: sunucu birleştirme, yalıtım, anlık görüntü, canlı taşıma.
Sanal Makineler
Hipervizör Türleri
Tip 1 (bare-metal): hipervizör doğrudan donanımda, en ayrıcalıklı kipte çalışır; konuk OS’lar onun üzerindedir. Veri merkezlerinin standart çözümüdür.
Saf tip 2: hipervizör, ana makine OS’u üzerinde sıradan bir süreçtir; konuk komutlarını yorumlar veya ikili çeviriyle çalıştırır (ör. KVM’siz QEMU). Esnek ama yavaştır.
Pratik tip 2: hipervizör yine bir uygulamadır, ancak ana OS’a yüklenen bir çekirdek modülü sayesinde donanım destekli sanallaştırmayı (Intel VT-x, AMD-V, ARM EL2) kullanır.
Sınırlar bulanıklaştı: KVM, Linux çekirdeğinin kendisini tip 1 hipervizöre dönüştürür; Hyper-V etkinleşince Windows bile bir kök bölümde (VM) çalışır.
Sanal Makineler
Tip 1 ve Tip 2 Hipervizörler
- İşletim sisteminden bağımsız, doğrudan donanım üzerinde çalışır.
- Fiziksel sunucuları sanal makinelere bölmek, kaynakları verimli kullanmak ve izlemek için.
- VMware ESXi: kurumsal veri merkezleri.
- Microsoft Hyper-V: Windows Server rolü (ayrı ücretsiz “Hyper-V Server” 2019’dan sonra sürdürülmedi).
- Xen (XCP-ng) ve KVM: açık kaynak; büyük bulutların (AWS Nitro, Google Cloud) temeli KVM’dir.
- Bir ana makine işletim sistemi üzerinde uygulama olarak çalışır.
- Kişisel bilgisayarlarda deneme, eğitim ve geliştirme ortamları için.
- Oracle VirtualBox: ücretsiz, açık kaynak, çok platformlu.
- VMware Workstation Pro / Fusion: 2024’ten beri ücretsiz.
- Parallels Desktop ve UTM (QEMU): macOS üzerinde.
- G/Ç yolu ana OS’tan geçtiği için ek yük daha fazladır; donanım desteğiyle CPU farkı küçüktür.
Sanal Makineler
Sanal Makine mi, Konteyner mi?
OS düzeyinde sanallaştırma: süreçler namespaces ile yalıtılır, cgroups ile sınırlanır. Saniyenin altında başlar (Docker, Podman, Kubernetes).
Tam yalıtım, farklı OS çalıştırabilir; ama her VM kendi çekirdeğini ve belleğini taşır.
Firecracker microVM, Kata Containers, gVisor; WSL 2 da hafif bir Hyper-V VM’inde gerçek Linux çekirdeği çalıştırır.
Donanım ve Yapı
Simetrik Çok İşlemcili ve Çok Çekirdekli Mimari
SMP: her CPU kendi yazmaçlarına ve önbelleğine sahiptir, belleği paylaşır; hepsi OS dâhil her işi yapabilir. Çekirdek veri yapıları kilitlerle korunmalıdır (Linux’un “büyük çekirdek kilidi” 2011’de tamamen kaldırıldı).
Çok çekirdekli yonga: çekirdekler aynı yongada, yakın önbellek paylaşımıyla daha hızlı ve az enerjiyle haberleşir. 2026’da yaygın olan P/E (performans/verimlilik) çekirdekleri zamanlayıcıya yeni görevler yükler.
Bağlama ve Açılış
Derleme, Bağlama ve Yükleme
Derleyici kaynak kodu yeniden konumlandırılabilir nesne dosyasına çevirir: adresler henüz kesin değildir, dış semboller (ör. printf) çözülmemiştir.
Bağlayıcı nesne dosyalarını ve statik kütüphaneleri birleştirir, sembolleri çözer, adresleri düzeltir ve çalıştırılabilir dosya üretir.
Kabuk execve çağırır; çekirdekteki yükleyici dosyanın başlığını okur, kesimleri adres uzayına eşler ve dinamik bağlayıcıyı (ld-linux.so) başlatır.
Paylaşılan kütüphaneler (libc.so.6) çalışma anında bağlanır ve süreçler arasında paylaşılır. Biçimler OS’a özgüdür: ELF (Linux), PE (Windows), Mach-O (macOS); bu yüzden programlar OS’lar arasında doğrudan taşınamaz.
Bağlama ve Açılış
İşletim Sisteminin Açılışı (Boot)
Açılış, çekirdeği belleğe yükleyip ilk kullanıcı sürecini başlatana kadar geçen süreçtir. Linux’ta systemd-analyze her aşamanın süresini gösterir.
Güç verilince CPU sıfırlanır ve kalıcı bellekteki ürün yazılımına atlar.
UEFI donanımı ilkler; GPT diskteki EFI sistem bölümünden (FAT32) önyükleyiciyi yükler.
Önyükleyici menü sunar; seçilen çekirdeği ve başlangıç RAM diskini (initramfs) belleğe koyar ve çekirdeğe atlar.
Çekirdek bellek yönetimini, zamanlayıcıyı ve sürücüleri başlatır; initramfs içindeki betikler gerekli modülleri yükler.
Gerçek kök dosya sistemi bağlanır ve initramfs bırakılır.
Çekirdek PID 1’i (systemd) başlatır; o da servisleri, ağı ve giriş ekranını açar. Bundan sonra her süreç PID 1’in soyundandır.
Özet
Kontrol Soruları
- Kullanıcı kipinde çalışan bir program neden G/Ç komutlarını doğrudan çalıştıramaz? Denerse ne olur?
printfilewritearasındaki fark nedir? Hangisi sistem çağrısıdır?fork()neden “bir kez çağrılır, iki kez döner”? Atada ve çocukta dönüş değerleri nedir?- Mikroçekirdekte bir sürücü çökerse ne olur? Monolitik çekirdekte?
- Linux’un yüklenebilir modülleri onu mikroçekirdek yapar mı? Neden?
- Tip 1 ve tip 2 hipervizörü ayırt eden nedir? KVM nereye konur?
Cevapları göster
- G/Ç ayrıcalıklı komuttur; mod biti 1 iken donanım tuzak üretir, OS süreci sonlandırır (koruma).
printfkullanıcı kipinde biçimleyen kütüphane fonksiyonudur; gerektiğindewritesistem çağrısını yapar.- Çağrıdan sonra iki süreç vardır ve ikisi de aynı noktadan devam eder: atada çocuğun PID’si, çocukta 0 (hata: −1).
- Mikroçekirdekte yalnızca o sunucu süreci çöker, yeniden başlatılabilir; monolitikte tüm çekirdek çökebilir.
- Hayır: modüller çekirdek kipinde ve aynı adres uzayında çalışır, mesajla değil fonksiyon çağrısıyla haberleşir.
- Tip 1 doğrudan donanımda, tip 2 bir ana OS üzerinde çalışır. KVM çekirdeği hipervizöre dönüştürdüğü için genelde tip 1 sayılır.
Özet
Kaynaklar
- Silberschatz, Galvin ve Gagne, Operating System Concepts, 10. baskı, Wiley, 2018 (Bölüm 2 ve 18).
- Tanenbaum ve Bos, Modern Operating Systems, 4. baskı, Pearson, 2014 (Bölüm 1.5–1.7 ve 7).
- Arpaci-Dusseau ve Arpaci-Dusseau, Operating Systems: Three Easy Pieces (OSTEP), sürüm 1.10, pages.cs.wisc.edu/~remzi/OSTEP.
- Linux man sayfaları:
syscalls(2),syscall(2),fork(2),pipe(7),mount(8). - Engler, Kaashoek ve O’Toole, “Exokernel: An Operating System Architecture for Application-Level Resource Management”, SOSP 1995.