Budowa systemu operacyjnego

Obarczyliśmy więc system operacyjny zadaniami. Z lektury poprzedniego rozdziału wynika, że jest ich niemało ... podobnie jak niemała jest liczba możliwych podzespołów sprzętowych, które należy obsłużyć. Z tego względu system operacyjny jest dziś najczęściej systemem dużym i złożonym. To skomplikowany twór, który musi zapewniać z jednej strony dużą niezawodność i stabilność działania, a z drugiej łatwość rozbudowy i modyfikacji (na przykład dostosowania do szybko zmieniających się rozwiązań sprzętowych).

Dlatego też w praktyce nie spotyka się już systemów w pełni monolitycznych (rozwiązanie kiedyś popularne, szczególnie dla 8-bitowych komputerów). Natomiast często spotyka się opis systemu za pomocą modelu warstwowego.

Model warstwowy

W takim przypadku możemy rozrysować sobie komputer w następujący sposób:

Model warstwowy systemu komputerowego

Na samym dole mamy sprzęt, potem kolejne warstwy abstrakcji, z których każda wykorzystuje możliwości tej, która jest poniżej i udostępnia swoją funkcjonalność wyżej, stanowiąc jednocześnie pewnego rodzaju granicę - ukrywając niepotrzebne szczegóły przed warstwami wyższymi.

Mały przykład: rozważmy w jaki sposób obsługiwany jest dysk twardy. Jak wiecie z poprzednich lekcji, dysk twardy jest to zespół okrągłych talerzy pokrytych substancją magnetyczną, nad którymi poruszają się głowice. Tylko jak je zmusić do ruchu? W warstwie fizycznej realizują to mikrosilniki krokowe. Lecz z punktu widzenia systemu operacyjnego jest to zbyt skomplikowane. Dlatego też producenci dysków twardych wyposażają je w tzw. firmware - oprogramowanie bardzo niskopoziomowe, zaszyte w pamięci ROM urządzenia, które zawiera procedury sterowania silnikami krokowymi. Aby z nich korzystać, nie trzeba znać szczegółów budowy silnika, napięć nim sterujących, itp, itd. Wystarczy wywołać taką procedurę z numerem cylindra, nad którym ma się znaleźć głowica.
Tak więc, dla komputera (warstwa assemblera) pewne, nieistotne z jego punktu widzenia, szczegóły zostały ukryte poprzez warstwę firmware. Idąc dalej tym krokiem - jądro wykorzystuje procedury firmware wewnątrz swoich procedur, które zapisują logiczne struktury danych (czyli pliki) w fizycznych blokach i sektorach HDD. Z punktu widzenia aplikacji i finalnego użytkownika znów pewne nieistotne szczegóły zostały ukryte. Aby skorzystać z tych procedur, wydajemy proste polecenia - utworzenia, zapisania, skasowania pliku na dysku. Jądro systemu przetworzy te polecenia na ciąg poleceń pozycjonujących i sterujących głowicami HDD, a firmware przetworzy te polecenia na natężenia prądów w silnikach i głowicy.

Dostaliśmy więc coś w rodzaju radia (na zewnątrz mamy tylko pokrętła, które pozwalają nam na słuchanie muzyki i nie musimy wiedzieć co się dzieje wewnątrz) - mamy dostęp do plików, które można zapisywać i odczytywać bez konieczności posiadania wiedzy, co się dzieje fizycznie w maszynie nazywanej komputerem. Co więcej - dostaliśmy też abstrakcję - system plików. I z punktu widzenia aplikacji użytkownika nie jest istotne gdzie jest on umieszczony fizyczne. Korzystając z worda tak samo zapisujemy plik na pen-drive jak na HDD, mimo że fizyczna zasada działania tych dwóch urządzeń jest kompletnie różna.

Na tym zakończymy omawianie modelu warstwowego. Jest on przydatny w analizie i budowie systemów komputerowych, jednakże jak na potrzeby tego podręcznika - zbyt abstrakcyjny i teoretyczny. W jego miejsce proponujemy przyjąć uproszczony schemat systemu operacyjnego.

Schemat budowy systemu operacyjnego

W podejściu pokazanym poniżej ograniczamy liczbę warstw i jednocześnie pokazujemy która warstwa może korzystać z której:

System operacyjny - części składowe.

W podobny sposób można traktować wszystkie współczesne systemy operacyjne.

Jądro

Większość systemów operacyjnych opiera się o koncepcję jądra, która w naturalny sposób wynika z modelu warstwowego. W takim wypadku jądro jest po prostu nazwą nadaną najniższej warstwie w pełni implementowanej jako program wykonywany przez CPU.

Do typowych funkcji realizowanych przez jądro można zaliczyć:

Po uruchomieniu komputera specjalny mały program, nazywany bootloaderem, ładuje jądro systemu operacyjnego do pamięci i przekazuje mu sterowanie maszyną. Jądro uruchamia w tym momencie pierwszy, główny proces, inicjalizuje wszystkie urządzenia peryferyne i przechodzi w stan oczekiwania na zdarzenia (np. ruchy myszą, żądania wydruku od aplikacji, przerwania, itp.) W czasie, gdy nie pojawiają się żadne zdarzenia, jądro wykonuje specjalny proces, nazywany idle (w polskiej wersji windows przetłumaczony jako Proces bezczynności systemu).

Każdy proces będący częścią jądra może pracować w jednym z dwóch trybów: jako proces użytkownika - kiedy dostęp do pamięci i urządzeń wejścia / wyjścia jest nadzorowany, oraz w tzw. trybie jądra - kiedy wszystkie mechanizmy ochrony są wyłączone. Jak łatwo się domyśleć - błędnie napisany program czy funkcja uruchomiona jako proces jądra może w łatwy sposób "powiesić" cały system komputerowy.

Opracowanie jądra jest jednym z najtrudniejszych i najbardziej skomplikowanych zadań programistycznych. Jako główny, najważniejszy program w systemie komputerowym, jądro powinno spełniać różne (często przeciwstawne) wymagania. Musi cechować się wysoką wydajnością, stabilnością i odpornością na błędy aplikacji oraz awarie podzespołów. Dodatkowo, często nie może wykorzystywać mechanizmów abstrakcji, które samo udostępnia innym programom, czyli np. przy jego tworzeniu nie można zapomnieć o fizycznej realizacji zapisu na dysk i opierać się jedynie na koncepcji plików. Tak więc jądro samo w sobie stanowi całkiem skomplikowany system informatyczny, który może być zbudowany w różny sposób. Wyróżniamy kilka podstawowych metod konstrukcji jąder

Jądro monolityczne

Często stosowane w systemach Unix-owych. Wszystkie zadania są wykonywane przez jądro, będące jednym, dużym programem pracującym w pełni (wszystkie funkcje) w trybie jądra. Zaletami tej techniki są: prostota, stabilność oraz łatwość komunikacji pomiędzy różnymi członami jądra (to przecież w tym wypadku jeden program!). Dodatkowo, systemy z jądrem monolitycznym zazwyczaj działają szybciej (szczególnie w komputerach o małej liczbie CPU) niż ich główna alternatywa - mikrojądro. Główna wada natomiast wynika z problemów w rozwijaniu takiego jądra (ze względu na jego wielkość) oraz dodawaniu do niego procedur obsługi nowych urządzeń peryferyjnych. Dodanie obsługi nowego urządzenia wymaga kompilacji całego jądra, co zajmuje czas i jest trudne do wykonania przez nawet zaawansowanego użytkownika.

System operacyjny z monolitycznym jądrem.

W czystej postaci jądro monolityczne występuje tylko w zastosowaniach niszowych, natomiast w dużej mierze takie rozwiązanie stosują systemy Linux, OpenBSD czy FreeBSD - jądra tych systemów umożliwiają ładowanie modułów, co jest sprzeczne z koncepcją jednego dużego programu, ale daje możliwość stosowania driver'ów, czyli dodawania obsługi nowego sprzętu bez konieczności ponownej kompilacji całego jądra.

Mikrojądro

W tej technice z monolitycznego jądra zostaje tylko jego podstawowa część (odpowiedzialna za zarządzanie procesami oraz pamięcią). Części odpowiedzialne za bardziej wyrafinowane funkcje (m.inn. obsługę urządzeń peryferyjnych) są wydzielone do funkcjonalnych bloków albo realizowane jako zwykłe procesy w trybie użytkownika. W większości przypadków takie bloki funkcjonalne mogą być ładowane i resetowane nie przerywając pracy systemu komputerowego, ponadto zwiększanie funkcjonalności jądra (i w konsekwencji - całego systemu) jest możliwe bez wprowadzania jakichkolwiek zmian w jego podstawowej części. Główną wadą takiego podejścia jest wolniejsza praca systemu.

System operacyjny z mikrojądrem.

Dobrymi przykładami systemów operacyjnych opartych na mikrojądrze są AmigaOS, Amoeba, QNX czy GNU Hurd, mikrojądrami są także jądra znane jako Mach i L4. Firma Microsoft pracuje nad własnym rozwiązaniem tego typu w projekcie Singularity.

Jądro hybrydowe

Jest to kompromis między architekturą jądra monolitycznego i mikrojądra. W krytycznych usługach - np. stos sieci - usługi są na stałe wkompilowane w główny kod jądra, inne usługi pozostają oddzielone od głównego jądra i działają jako serwery (w przestrzeni jądra). Dzięki temu rozwiązaniu możliwe jest zachowanie wydajności jądra monolitycznego dla kluczowych usług.

Wydzielenie takiego rodzaju jądra budzi kontrowersje wśród specjalistów. Wielu z nich uważa, iż w porównaniu do podobnego jądra monolitycznego, pojęcie to jest niczym innym jak dobrym marketingiem.

Pomysłem stojącym za tym nowym pseudo-rodzajem jądra jest struktura podobna do mikrojądra, ale zaimplementowana jak jądro monolityczne. W przeciwieństwie do mikrojądra, wszystkie (lub prawie wszystkie) usługi wykonywane są w przestrzeni jądra. Podobnie jak w jądrze monolitycznym, nie ma strat w wydajności wywołanych przepływem komunikatów mikrojądra. Jednakże, podobnie jak w jądrach monolitycznych, nie ma korzyści wynikających z umieszczenia usług w przestrzeni użytkownika.

Budowa jądra systemu Windows 2000

Tego typu jądro jest podstawą systemów Windows NT, 2000, XP, 2003, Vista. Jest ono wykorzystywane również przez mniej popularne systemy, jak np. BeOS.

API (Application Programming Interface)

Usługi jądra nigdy nie są bezpośrednio widoczne dla użytkownika czy aplikacji. Użytkownik może je wykorzystywać i wywoływać korzystając z powłoki systemu, natomiast aplikacjie najczęściej wykorzystują tzw. API - zbiór poleceń, które aplikacje użytkownika mogą wydawać systemowi operacyjnemu (np.: „zamknij plik”, „odczytaj znak z klawiatury”). Warstwa API (ang. Application Program Interface) pełni rolę pośrednika między systemem operacyjnym a programami użytkownika. API wykorzystywane jest jedynie przez programistów i zazwyczaj dostarczane w formie zestawu plików nagłówkowych języka programowania C. Kompletne API zaawansowanego systemu operacyjnego to olbrzymia biblioteka (kilkaset tysięcy funkcji), najczęściej w dodatku kompletnie różna dla różnych systemów operacyjnych.

Programy narzędziowe

Najważniejszym z nich jest powłoka systemu, czyli jego interfejs widoczny dla użytkownika. To ona decyduje o wyglądzie i funkcjonalności systemu operacyjnego dla każdego z Was.

Dwa najczęściej spotykane typy powłoki to:

Powłoka często sama zawiera podstawowe polecenia, gdy jednak wydane przez użytkownika polecenie nie jest wbudowane, uruchamiany jest zewnętrzny program narzędziowy, np. do wyświetlenia zawartości aktualnego katalogu w powłoce tekstowej wywoływany jest program nazwany dir dla Windows oraz ls dla Unix-ów.

Z technicznego punktu widzenia powłoka nie różni się od innych programów narzędziowych, czy też nawet aplikacji zewnętrznych. Jest normalnym programem, pracującym w trybie użytkownika i może być zmieniona przez inny program definiowany przez użytkownika, co jest wykorzystywane do tworzenia rozmaitych nakładek, podmieniających np. interfejs Windows na podobny do MacOS.