← Radar

Konu: Altyapı4 dk okuma

Güç düğmesinden kapanışa: İşletim sisteminin temel kavramları, sırayla

Bu neden önemli?

Bir güvenlik açığı haberinde 'çekirdek', 'root', 'sayfa önbelleği' gibi kelimeler geçtiğinde ne olduğunu anlamak için bu temel gerekli. Ayrıca yavaşlayan bir sunucuyu, donan bir uygulamayı ya da kapanmayan bir konteyneri anlamanın da yolu buradan geçiyor.

İşletim sistemi ne yapar?

Bilgisayarında aynı anda yüzlerce program çalışıyor, ama işlemcinin belki 8 çekirdeği var. Yine de fareyi oynattığında imleç anında hareket ediyor. Bunu sağlayan şey işletim sistemi: Donanımı paylaştıran, programları birbirinden koruyan ve hepsine ortak bir arayüz sunan yazılım. İlk örneklerden biri olan GM-NAA I/O, 1956’da IBM 704 için yazıldı ve tek yaptığı, bir program bitince sıradakini başlatmaktı. Bugün çok daha fazlasını yapıyorlar; bilgisayarı açıp kapatırken olanları sırayla izleyelim.

1. Açılış: Firmware ve bootloader

Güç düğmesine bastığında işlemci en ilkel hâlinde uyanır: Ne dosya vardır ne bellek yönetimi. Anakarttaki firmware (bugün UEFI, eskiden BIOS) diski bulacak kadar donanımı hazırlar ve işi bootloader’a devreder. Linux’ta bu genelde GRUB’dur. Görevi tek: Çekirdeği (kernel) diskten bulup belleğe yüklemek.

2. Yetki halkaları

İşlemci farklı yetki seviyelerinde çalışabilir. x86’da dört halka var ama pratikte ikisi önemli: Halka 0’da çekirdek her şeyi yapabilir. Halka 3’te ise uygulamalar çalışır ve donanıma doğrudan dokunamaz. Bu ayrımı işlemcinin kendisi uygular. Bu sayede hatalı bir program genelde sadece kendini çökertir, bütün sistemi değil.

3. Sanal bellek

Bir programın gördüğü bellek adresleri gerçek değildir. Her sürecin kendi sayfa tablosu vardır ve işlemcideki MMU bu sanal adresleri gerçek fiziksel adreslere çevirir. Bellek, genelde 4 KB’lık sayfalar hâlinde dağıtılır. Sonuç: Tarayıcın, şifre yöneticisinin belleğini okuyamaz. Program bellekte olmayan bir sayfaya dokunursa page fault oluşur, çekirdek sayfayı diskten getirir ve program hiçbir şey olmamış gibi devam eder.

4. Dosya sistemi

Disk aslında numaralı bloklardan oluşan uzun bir şerittir. Dosya sistemi bunun üstüne dosya ve klasör görüntüsü kurar. Linux’ta her dosyanın bir inode’u vardır: boyut, izinler, tarihler ve verinin diskteki yeri. İlginç olan, dosya adının inode’da olmaması. Adlar klasörlerde tutulur, bu yüzden aynı dosyaya birden fazla ad verebilirsin. ext4, NTFS, APFS gibi modern dosya sistemleri journaling kullanır: Önce ne yapacağını bir günlüğe yazar, sonra yapar. Elektrik kesilirse veri çoğu zaman bozulmaz. Okunan dosyalar ayrıca bellekte, sayfa önbelleğinde tutulur ki bir sonraki okuma hızlı olsun.

5. Sürücüler ve kesmeler

Ekran kartı, Wi-Fi, klavye gibi her donanım için bir sürücü yüklenir. Sürücüler çekirdekte çalıştığı için hatalı biri bütün sistemi çökertebilir. Klavyeye basıldığını işletim sistemi sürekli sorarak öğrenmez: Donanım bir kesme (interrupt) gönderir, işlemci elindeki işi bırakıp çekirdekteki ilgili kodu çalıştırır.

6. İlk süreç ve sistem çağrıları

Çekirdek hazır olunca ilk kullanıcı programını başlatır: PID 1. Linux’ta bu genelde systemd’dir ve diğer bütün süreçlerin atasıdır. Bundan sonra çalışan her şey halka 3’tedir. Bir dosya okumak isteyen program bunu doğrudan yapamaz, çekirdekten sistem çağrısı (syscall) ile ister. İşlemci kısa süreliğine halka 0’a geçer, iş yapılır, geri dönülür. C’deki printf bile sonunda write çağrısına dönüşür. Linux’ta birkaç yüz sistem çağrısı var ve bilgisayarın gerçek API’si bunlar.

7. Zamanlayıcı ve thread’ler

Yüzlerce süreç birkaç çekirdeği paylaşır. Kimin ne zaman çalışacağına zamanlayıcı (scheduler) karar verir. Linux 6.6’dan beri EEVDF adlı bir algoritma kullanıyor: Her göreve hakkı olan işlemci payını takip ediyor ve hakkı olanlar arasında “son tarihi” en yakın olanı çalıştırıyor. Thread’ler ise aynı süreç içinde paralel çalışan kollar. Belleği paylaştıkları için hızlılar ama iki thread aynı değişkene aynı anda yazarsa race condition çıkar. Rust’ın borrow checker’ı bu yüzden bazı paralel kodları hiç derlemez. Buna karşı kullanılan kilidin içini mutex yazısında anlattık.

8. Süreçler arası iletişim ve kapanış

Farklı süreçler belleği paylaşamaz, o yüzden IPC yöntemleri var. En bilineni 1973’ten beri Unix’te olan pipe: cat dosya | grep kelime yazdığında bir programın çıktısı diğerinin girdisi olur. Kapatma düğmesine bastığında PID 1, süreçlere önce kibarca SIGTERM sinyali gönderir. Süresi içinde kapanmayanlara SIGKILL gelir; bu sinyal yakalanamaz. Sonra dosya sistemi diske yazılır, sürücüler donanımı bırakır ve güç kesilir.

Neden bilmeye değer?

Bu kavramlar haberlerde sürekli geçiyor. Örneğin Copy Fail açığı, sıradan bir kullanıcının sistem çağrıları üzerinden sayfa önbelleğine yazıp root olmasıydı. Yapay zekâ terimleri için benzer bir sıralı anlatımı da kavramlar yazısında yapmıştık. Daha derine inmek istersen ücretsiz “Operating Systems: Three Easy Pieces” kitabı iyi bir başlangıç.

Düşün

  • Bir Docker konteynerini durdurduğunda neden bazen tam 10 saniye bekliyorsun? (İpucu: SIGTERM, sonra SIGKILL.)
  • Bilgisayarında şu an kaç süreç çalışıyor? ps aux | wc -l ile bak.

Videoyu izle

Tıklayınca video YouTube'dan yüklenir; o ana kadar bu sayfa YouTube'a hiçbir istek göndermez.
Kaynaklar (8, İngilizce)

Kendi cümlelerimizle yazılmış bir özettir, çeviri değildir. Tüm kaynaklar yukarıda.

Konu: Altyapı3 dkVideo: Better Stack

JuiceFS: Ucuz bulut depolamayı bilgisayarında bir klasör gibi kullanmak

S3 gibi nesne depolama servisleri ucuz ve sınırsız, ama normal bir disk gibi davranmıyor. Açık kaynak JuiceFS, dosyaların içeriğini buluta, adını ve klasör yapısını bir veritabanına koyup ikisini sıradan bir klasör gibi bağlıyor. Yerel önbellek sayesinde ikinci okuma neredeyse disk hızında.