Kernel (zwany też jądrem) jest rdzeniem systemu operacyjnego i pomostem pomiędzy fizycznym sprzętem, a uruchamianym oprogramowaniem.
Czym jest kernel i jaką rolę pełni w systemie operacyjnym?
Wyobraźmy sobie komputer jako zbiór warstw, z których najniższą jest fizyczny sprzęt, a najwyższą – uruchamiane na komputerze aplikacje. Jądro stanowiłoby wówczas warstwę środkową, tę pomiędzy sprzętem a aplikacjami. Kernel kontroluje zasoby sprzętowe korzystając przy tym ze sterowników, rozwiązuje konflikty między aplikacjami w zakresie dostępu do tychże zasobów, a także optymalizuje ich użycie.
Sterownik – program odpowiadający za dane urządzenie i umożliwiający kontrolę na dnim.
W zdecydowanej większości systemów operacyjnych kernel jest pierwszym (nie licząc bootloadera) programem uruchamianym po starcie, po przejmuje on na siebie kolejne zadania, w tym rozruch pamięci i urządzeń peryferyjnych. Kernel obsługuje polecenia I/O pochodzące od uruchamianego oprogramowania “tłumacząc” je na instrukcje procesora CPU.
Bootloader – inaczej program rozruchowy, uruchamia system operacyjny zainstalowany na urządzeniu.
Czytaj więcej: Jak sprawdzić architekturę procesora?
W celu zapewnienia bezpieczeństwa i stabilnej pracy kernel działa w tak zwanej przestrzeni jądra – wydzielonym obszarze pamięci operacyjnej, do którego dostępu pozbawione jest inne oprogramowanie. To właśnie w tej przestrzeni kernel wykonuje takie zadania jak uruchamianie procesów, alokacja pamięci, zarządzanie zasobami sprzętowymi czy obsługa przerwań. Mniej krytyczne oprogramowanie, na przykład przeglądarki internetowe lub odtwarzacze wideo, działa natomiast w tzw. przestrzeni użytkownika – obszarze pamięci operacyjnej odseparowanym od przestrzeni jądra.
Powyższe rozwiązanie zapobiega zachodzeniu interferencji pomiędzy jądrem a uruchamianym oprogramowaniem, którego skutkiem byłaby niestabilność i wolna praca. Pojedynczy nieprawidłowo działający program mógłby bowiem spowodować awarię całego systemu operacyjnego. Uniemożliwia ono również złośliwemu oprogramowaniu przejęcie pełnej kontroli.
Cechy jądra systemu operacyjnego
Do cech kerneli współczesnych systemów operacyjnych należą:
- Wielozadaniowość – możliwość uruchamiania więcej niż jednego procesu (programu)
- Wielowątkowość – obsługa wykonywania wielu wątków (pod-programów, zadań) przez pojedynczy program w oczekiwaniu na ich rezultat
- Wywłaszczalność – realizowana przez tzw. planistę możliwość przerwania pracy programu (np. w razie zawieszenia się), odebrania czasu procesora i przekazania go innego procesowi
- Skalowalność – możliwość zmiany zwiększenia lub zmniejszenia skali obsługiwanych zasobów sprzętowych
Planista – inaczej dyspozytor lub z angielskiego scheduler, część systemu operacyjnego odpowiedzialna za przydzielania czasu procesora do programów.
Czas procesora – czas, w czasie którego procesor CPU zajęty jest przetwarzaniem instrukcji systemu operacyjnego lub zainstalowanego oprogramowania
Wywołania systemowe
Zdarza się, że dany proces działający na komputerze potrzebuje np. dostępu do systemu plików w celu zapisania danych. W tym celu musi skorzystać z tzw. wywołania systemowego, interfejsu pomiędzy programem a jądrem systemu operacyjnego, które z kolei realizuje powierzone zadanie.
Nowoczesne oprogramowanie nie korzysta zazwyczaj z wywołań systemowych bezpośrednio, ale poprzez biblioteki języka C lub specjalne API. Właściwy sposób realizacji wywołań systemowych różni się znacząco zależnie od rodzaju systemu operacyjnego oraz architektury procesora.
Szczypta historii
Wbrew pozorom obecność systemu operacyjnego (a więc także jego kernela) nie jest niezbędna do uruchamiania programów – mogłyby one działać na fizycznym sprzęcie bez żadnego pośrednika, bez warstwy abstrakcji i funkcji dostarczanych przez system operacyjny. Takie właśnie podejście stosowano w latach 50. oraz 60., na samych początkach rozwoju techniki komputerowej. Wymagane było resetowanie komputera (zajmującego wówczas całą salę) pomiędzy uruchamianiem kolejnych programów. Nawet dziś znaleźć można urządzenia działają bez systemu operacyjnego – należą do nich m.in. niektóre konsole do gier lub systemy wbudowane.
Drastyczny wzrost wydajności komputerów spowodował konieczność opracowania mechanizmu dzielenia czasu procesora pomiędzy wielu użytkowników, a następnie zarządzania uprawnieniami i zabezpieczeń przed nieuprawnionym dostępem. Doprowadziło to do powstania protoplastów dzisiejszych systemów operacyjnych.
Powstały w 1985 roku Amiga OS, system operacyjny dla komputerów Commodore Amiga, które odniosły znaczący sukces komercyjny jako komputery osobiste, korzystał już z dosyć zaawansowanej architektury kernela. Komponent exec.library odpowiedzialny za uruchamianie programów miał wbudowany mechanizm przypominający komunikację między serwerami znaną z dzisiejszych mikrokerneli. Niektóre komponenty, w tym m.in. graphics.library, miały jednak wciąż bezpośredni dostęp do fizycznego sprzętu. Kernel Amiga OS działał w przestrzeni użytkownika, a jedynie niektóre zadania realizowane były w przestrzeni jądra.
Znaczący wpływ na dzisiejsze kernele miało opracowanie Uniksa, który wprowadził wiele stosowanych do dziś innowacyjnych rozwiązań. Należały do nich m.in. wysoce wysokopoziomowa koncepcja traktowania podłączonych urządzeń jako “plików” oraz sam system plików. Architektura Uniksa dzieliła system operacyjny na dwie części: oprogramowanie wykonujące poszczególne zadania i jądro uruchamiające te programy. To właśnie z Uniksa wywodzi się m.in. Linux, systemy BSD oraz macOS.
Czytaj więcej: Xenix – o tym, jak Microsoft stworzył swojego Uniksa
Opracowany przez Microsoft w latach 90. system Windows NT i wszyscy jego następcy (a więc także Windows 11) używają jądra hybrydowego, formy bardziej rozbudowanego mikrokernela.
Programiści wciąż pracują nad rozwojem architektury kernela systemu operacyjnego w celu zwiększenia możliwości, bezpieczeństwa i wydajności. W ten sposób powstają nowe koncepcje, często znajdujące się wciąż w eksperymentalnej fazie.
Rodzaje kerneli
Choć zadania przypisane do jądra systemu operacyjnego są podobne niezależnie od systemu, którego część stanowią, sposób ich wykonywania różni się pomiędzy poszczególnymi rodzajami kerneli.
Jądro NT znane z systemów z rodziny Windows oraz XNU / Darwin z systemu macOS uznawane są za przykłady jądra hybrydowego. Linux, podstawa licznych dystrybucji, jest natomiast jądrem monolitycznym. Oprócz kerneli monolitycznych i hybrydowych, rozwijane są również implementacje lub koncepcje mikrokerneli, nanokerneli, exokerneli i multikerneli.
Jądro monolityczne
W jądrze monolitycznym, typowym dla systemów uniksowych, wszystkie procesy działają obok głównego procesu kernela, znajdując się w ten sposób w tej samej przestrzeni pamięci operacyjnej. Taki rodzaj jądra jest prostszy architektonicznie, ale jednocześnie powoduje powstanie licznych zależności pomiędzy komponentami. Błąd w jednym z nich może spowodować awarię całego sytemu.
Jądro monolityczne jest jednym, “dużym” programem działającym w przestrzeni jądra i wykonującym wszelkie zadania związane z pracą kernela. Zawiera wszystkie podstawowe funkcje, w tym sterowniki do urządzeń, planistę, obsługę systemu plików czy stosu sieciowego. Nowoczesne jądra monolityczne (takie jak Linux) korzystają z tzw. modułów wgrywanych do pamięci w razie wystąpienia takiej potrzeby, zapewniając w ten sposób możliwość rozszerzenia zakresu funkcji kernela, a jednocześnie zmniejszając ilość kodu działającego cały czas w przestrzeni jądra.
Najpopularniejsze, monolityczne jądro Linux może zostać zmniejszone dzięki możliwości dynamicznego ładowania i odłączania modułów oraz dostosowywania pod własne wymagania – Linux jest dostępny jako oprogramowanie typu open-source. W niektórych dystrybucjach miniaturyzacja osięgnęła skalę wręcz ekstremalną: muLinux mieści się na dyskietce, dostarczając przy tym zestaw podstawowych narzędzi.
Do znaczących wad kernela monolitycznego należą:
- Duża baza kodowa utrudniająca rozwój
- Błędy w jednym z komponentów mogą mieć znaczący wpływ na pozostałe z uwagi na pracę w przestrzeni jądra
- Moduły kernela pracują w tej samej przestrzeni adresowej, w wyniku czego awaria jednego z nich może doprowadzić do awarii całego systemu
- Przenoszenie na inne architektury CPU jest wysoce utrudnione
Mikrokernel
Mikrokernel jest odwrotnością kernela monolitycznego i próbą rozwiązania przedstawionych powyżej problemów dotykających te ostatnie. Jak sama nazwa mówi, mikrokernel jest wysoce zminimalizowany, a zdecydowana większość funkcji systemu wyniesiona jest poza jądro do przestrzeni użytkownika. Komponenty te działają tam jako “serwery” i realizują mniej krytyczne zadania, komunikując się między sobą za pośrednictwem kernela.
Sam mikrokernel dostarcza jedynie warstwę abstrakcji nad fizycznym sprzętem, zapewnia podstawowe wywołania systemowe i realizuje takie zdania jak zarządzanie pamięcią, obsługę wielozadaniowości, czy komunikację między procesami. Niektóre komponenty (np. planista) działają w przestrzeni jądra jedynie częściowo, w zakresie niezbędnym do prawidłowej pracy.
Takie podejście umożliwia łatwiejszy rozwój kernela i zmniejszenie ryzyka awarii całego systemu w razie nieprawidłowej pracy pojedynczego komponentu. Jak to jednak zwykle bywa, zniwelowanie jednych (w tym przypadku wad jądra monolitycznego) wad tworzy nowe. Konieczność wykonywania dużej liczby wywołań systemowych przez oprogramowanie działające w przestrzeni użytkownika powoduje spadek wydajności, szczególnie w systemach o dużej ilości uruchomionych jednocześnie procesów, samo zarządzanie procesami jest bardzo skomplikowane, a zapotrzebowanie na pamięć większe niż w przypadku jądra monolitycznego.
Dlatego też mikrokernel szczególnie dobrze nadaje się do systemów wykonujących pojedyncze zadania, często krystyczne. Konieczność obsługi dużej liczby procesów wówczas praktycznie nie istnieje.
Co ciekawe, konstrukcja mikrokernela umożliwia stworzenie całej reszty systemu operacyjnego jako zwykłej aplikacji napisanej w wysokopoziomowym języku programowania, a nawet na obsługę wielu systemów operacyjnych przez pojedynczy kernel, w tym ich dynamiczne przełączanie lub jednoczesną pracę.
Jądro hybrydowe
Jądro hybrydowe, stosowane powszechnie w popularnych komercyjnych systemach operacyjnych (w tym Windowsie i macOS), są formą kompromisu pomiędzy jądrem monolitycznym a mikrokernelem.
W zakresie architektury, kernel hybrydowy przypomina rozbudowany mikrokernel, w którym, w celu uzyskania większej wydajności, do przestrzeni jądra przeniesiono więcej zadań, w tym m.in. obsługę systemu plików czy sieci. W przeciwieństwie do kerneli monolitycznych, hybrydowe nie posiadają zazwyczaj możliwości dynamicznego dołączania ładowania modułów w czasie pracy, korzystają natomiast ze znanych z mikrokerneli serwerów – w tej formie działają między innymi sterowniki do poszczególnych urządzeń.
Zwiększenie zakresu funkcji systemowych obsługowanych przez kernel ma pozytywny wpływ na wydajność i pozwala uniknąć znaczącego wzrostu liczby wywołań systemowych przy jednoczesnej realizacji wielu zadań (jak w mikrokernelu), a także pracy znaczącej liczby procesów w przestrzeni jądra (jak w jądrze monolitycznym).
Pozostałe rodzaje kerneli
Poza jądrami monolitycznymi, hybrydowymi i mikrokernelami wyróżniamy również następujące rodzaje jąder systemowych:
- Nanokernel – w tym rozwiązaniu niemal wszystkie usługi, w tym te najbardziej podstawowe takie jak obsługa przerwań, są implementowane jako zewnętrzne sterowniki działające w przestrzeni użytkownika, zmniejszając w ten sposób drastycznie zapotrzebowanie na pamięć.
- Exokernel – funkcjonalność jądra jest tu jeszcze bardziej ograniczona niż w nanokernelu. Obsługują one wyłącznie ochronę fizycznego sprzętu i nie zapewniają same z siebie żadnej warstwy abstrakcji na której możliwe byłoby uruchamianie aplikacji. Oddzielenie ochrony sprzętu od roli zarządzania nim umożliwia twórcom oprogramowania samodzielne opracowanie najlepszego sposobu użycia dostępnych zasobów.
- Multikernel – traktuje wielordzeniowy procesor jako sieć niezależnych rdzeni, tak jakby był on systemem rozproszonym.
Zestawienie kerneli stosowanych w poszczególnych systemach operacyjnych
KERNEL | SYSTEM OPERACYJNY | RODZAJ KERNELA |
---|---|---|
DragonFly BSD Kernel | DragonFly BSD | Hybrydowy |
FreeBSD | FreeBSD, Debian (w wersjach kFreeBSD), OrbisOS | Monolityczny |
GNU Hurd | Arch (wersja Hurd), Debian (wersja Hurd) | Mikrokernel |
Linux | Dystrybucje Linuksa (w tym m.in. Ubuntu, Debian, RHEL, CentOS, Arch), Android, webOS, Firefox OS, Fire OS, Chrome OS, Sailfish OS, Tizen i inne | Monolityczny |
Mach | NeXTSTEP, OPENSTEP | Mikrokernel |
NetBSD Kernel | NetBSD | Monolityczny |
OpenBSD Kernel | OpenBSD | Monolityczny |
OS/2 Kernel | OS/2 wersja 2 i nowsze | Hybrydowy |
Plan 9 Kernel | Plan 9 | Monolityczny |
ReactOS Kernel | ReactOS | Hybrydowy |
SunOS Kernel | SunOS | Monolityczny |
Solaris Kernel | Solaris | Monolityczny |
Windows NT | Systemy z rodziny Windows NT, Windows 2000 i nowsze, Windows Phone, Windows Mobile 10 | Hybrydowy |
XNU (Darwin) | macOS, iOS, iPadOS, tvOS, watchOS, OpenDarwin, PureDarwin, GNU/Darwin | Hybrydowy |