Mach (jądro) - Mach (kernel)

Mach
Deweloper(zy) Richard Rashid
Avie Tevanian
Pierwsze wydanie 1985 ; 36 lat temu ( 1985 )
Wersja stabilna
3.0 / 1994 ; 27 lat temu ( 1994 )
Rodzaj Mikrojądro
Strona internetowa Projekt Mach

Mach ( / m ɑː k / ) to jądro opracowane na Uniwersytecie Carnegie Mellon przez Richarda Rashida i Avie Tevanian i wywodzące się oryginalnie z 4.3BSD w celu wspierania badań nad systemami operacyjnymi , głównie przetwarzania rozproszonego i równoległego . Mach jest często wymieniany jako jeden z najwcześniejszych przykładów mikrojądra . Jednak nie wszystkie wersje Macha są mikrojądrami. Pochodne Mach są podstawą w jądrze systemu operacyjnego GNU Hurd i firmy Apple „s xnu jądra używanego w MacOS , iOS , iPadOS , tvOS i watchOS .

Projekt w Carnegie Mellon trwał od 1985 do 1994 roku, kończąc się na Mach 3.0, który jest prawdziwym mikrojądrem . Mach został opracowany jako zamiennik jądra w wersji BSD systemu Unix , więc nie trzeba by było wokół niego projektować nowego systemu operacyjnego. Mach i jego pochodne istnieją w wielu komercyjnych systemach operacyjnych. Obejmują one wszystkie korzystające z jądra systemu operacyjnego XNU , które zawiera wcześniejszy, niemikrojądrowy Mach jako główny komponent. System zarządzania pamięcią wirtualną Mach został również zaadoptowany w 4.4BSD przez programistów BSD z CSRG i pojawia się w nowoczesnych systemach uniksowych wywodzących się z BSD, takich jak FreeBSD .

Mach jest logicznym następcą jądra Accent firmy Carnegie Mellon . Główny programista projektu Mach, Richard Rashid , pracuje w Microsoft od 1991 roku; założył dział Microsoft Research . Inny z pierwotnych programistów Mach, Avie Tevanian , był wcześniej szefem oprogramowania w NeXT , a następnie dyrektorem ds. technologii oprogramowania w Apple Inc. do marca 2006 roku.

Historia

Nazwa

Choć deweloperzy, raz podczas fazy nazewnictwa, musiał rowerem na obiad przez błoto kałuże deszczowej Pittsburgh, Tevanian żartował słowo „syf” może służyć jako backronym ich M ulti- U Ser (lub M ultiprocessor U niversal) C ommunication K ernel. Włoski inżynier CMU, Dario Giuse, zapytał później lidera projektu Ricka Rashida o aktualny tytuł projektu i otrzymał jako odpowiedź „MUCK”, choć nie napisane, ale po prostu wymawiane jako IPA:  [mʌk], które, zgodnie z alfabetem włoskim , napisał jako Mach . Rashidowi tak bardzo spodobała się pisownia Giuse'a „Mach”, że zyskała przewagę.

Rury uniksowe

Kluczową koncepcją oryginalnego systemu operacyjnego Unix była idea potoku . Potok był abstrakcją, która pozwalała na przenoszenie danych jako nieustrukturyzowanego strumienia bajtów z programu do programu. Używając potoków, użytkownicy (lub programiści) mogą łączyć ze sobą wiele programów w celu wykonania zadań, przesyłając dane kolejno do kilku małych programów. Kontrastowało to z typowymi systemami operacyjnymi tamtych czasów, które wymagały jednego dużego programu, który mógłby obsłużyć całe zadanie, lub alternatywnie używał plików do przekazywania danych, co było kosztowne i czasochłonne pod względem zasobów.

Potoki zostały zbudowane na bazowym systemie wejścia/wyjścia . Ten system z kolei opierał się na modelu, w którym kierowcy mieli okresowo „blokować się” w oczekiwaniu na zakończenie zadań. Na przykład sterownik drukarki może wysłać wiersz tekstu do drukarki wierszowej, a następnie nie mieć nic do roboty, dopóki drukarka nie zakończy drukowania tego wiersza. W takim przypadku sterownik wskazywałby, że został zablokowany, a system operacyjny zezwoli na działanie innego programu, dopóki drukarka nie wskaże, że jest gotowa na więcej danych. W systemie potoków ograniczonym zasobem była pamięć, a gdy jeden program zapełnił pamięć przypisaną do potoku, naturalnie się blokował. Normalnie spowodowałoby to uruchomienie programu konsumującego i ponowne opróżnienie rury. W przeciwieństwie do pliku, w którym cały plik musi zostać odczytany lub zapisany, zanim następny program będzie mógł go użyć, potoki sprawiły, że ruch danych między wieloma programami odbywał się w sposób fragmentaryczny, bez żadnej interwencji programisty.

Jednak implementacja potoków jako buforów pamięci oznaczała kopiowanie danych z programu do programu, co było operacją czasochłonną i wymagającą dużych zasobów. To sprawiło, że koncepcja potoku nie była odpowiednia do zadań, w których potrzebna była szybka realizacja lub niskie opóźnienia, jak ma to miejsce w przypadku większości sterowników urządzeń . Jądro systemu operacyjnego i większość podstawowych funkcji zostały napisane jako jeden duży program. W miarę jak system operacyjny dodawał nowe funkcje ( na przykład sieci komputerowe ), rosły również rozmiary i złożoność jądra.

Nowe koncepcje

Potoki uniksowe oferowały system koncepcyjny, który można wykorzystać do budowania dowolnie złożonych rozwiązań z małych interaktywnych programów. Będąc mniejszymi, programy te były łatwe w programowaniu i utrzymaniu oraz miały dobrze zdefiniowane interfejsy, które upraszczały programowanie i debugowanie. Te cechy są jeszcze bardziej cenne dla sterowników urządzeń, gdzie niezwykle ważne są niewielkie rozmiary i bezbłędna wydajność. Istniało silne pragnienie modelowania samego jądra na tej samej podstawie, na podstawie małych, współpracujących programów.

Jednym z pierwszych systemów wykorzystujących system podobny do potoku jako podstawę systemu operacyjnego było jądro Aleph opracowane na Uniwersytecie w Rochester . To wprowadziło koncepcję portów , które zasadniczo były implementacją pamięci współdzielonej . W Aleph samo jądro zostało zredukowane do zapewnienia dostępu do sprzętu, w tym pamięci i portów, podczas gdy konwencjonalne programy korzystające z systemu portów implementowały wszystkie zachowania, od sterowników urządzeń po programy użytkownika. Ta koncepcja znacznie zmniejszyła rozmiar jądra i pozwoliła użytkownikom eksperymentować z różnymi sterownikami, po prostu ładując je i łącząc ze sobą w czasie wykonywania. To znacznie złagodziło problemy podczas tworzenia nowego kodu systemu operacyjnego, który zwykle wymagał ponownego uruchomienia komputera. Ogólna koncepcja małego jądra i sterowników zewnętrznych stała się znana jako mikrojądro.

Aleph został zaimplementowany na minikomputerach Data General Eclipse i był z nimi ściśle związany. Ta maszyna była daleka od ideału, ponieważ wymagała kopiowania pamięci między programami, co wiązało się ze znacznym obciążeniem wydajnościowym. Był też dość drogi. Niemniej jednak Aleph udowodnił, że system bazowy jest solidny, i zademonstrował klastrowanie komputerów poprzez skopiowanie pamięci przez wczesny interfejs Ethernet .

Mniej więcej w tym czasie pojawiła się na rynku nowa generacja procesorów centralnych (CPU), oferująca 32-bitowe przestrzenie adresowe i (początkowo opcjonalnie) obsługę jednostki zarządzania pamięcią (MMU). MMU obsługiwał instrukcje potrzebne do wdrożenia systemu pamięci wirtualnej (VM), śledząc, które strony pamięci były używane przez różne programy. Zaoferowało to nowe rozwiązanie koncepcji portu, wykorzystujące mechanizm kopiowania na zapis używany przez VM . Zamiast kopiować dane między programami, wystarczyło przesłać tylko dane potrzebne do nakazania MMU dostępu do tej samej pamięci. Ten system zaimplementowałby system komunikacji międzyprocesowej o znacznie wyższej wydajności.

Ta koncepcja została podjęta w Carnegie-Mellon, który zaadaptował Aleph dla stacji roboczej PERQ i zaimplementował go za pomocą kopiowania przy zapisie. Port powiódł się, ale powstałe jądro Accent miało ograniczone zastosowanie praktyczne, ponieważ nie uruchamiało istniejącego oprogramowania. Co więcej, Accent był tak samo związany z PERQ, jak Aleph z Zaćmieniem.

Mach

Główną zmianą pomiędzy tymi eksperymentalnymi jądrami a Mach'em była decyzja o ponownej implementacji wersji istniejącego jądra 4.2BSD w oparciu o koncepcje przekazywania komunikatów Accent. Takie jądro byłoby kompatybilne binarnie z istniejącym oprogramowaniem BSD, dzięki czemu system byłby natychmiast przydatny do codziennego użytku, a jednocześnie byłby użyteczną platformą eksperymentalną. Ponadto nowe jądro zostałoby zaprojektowane od początku do obsługi wielu architektur procesorów, umożliwiając nawet tworzenie heterogenicznych klastrów. W celu jak najszybszego uruchomienia systemu, system zostałby zaimplementowany, zaczynając od istniejącego kodu BSD i wdrażając go krok po kroku jako programy oparte na komunikacji międzyprocesowej (oparte na IPC). W ten sposób Mach zacząłby jako monolityczny system podobny do istniejących systemów UNIX iz czasem ewoluował bardziej w kierunku koncepcji mikrojądra.

Mach zaczął w dużej mierze od wytworzenia jasno zdefiniowanego, opartego na systemie UNIX, wysoce przenośnego akcentu. Rezultatem jest krótka lista ogólnych pojęć:

  • zadanie ” to obiekt składający się z zestawu zasobów systemowych, które umożliwiają uruchamianie „wątków”
  • " wątek " jest pojedynczą jednostką wykonania, istnieje w kontekście zadania i współdzieli zasoby zadania
  • " port " to chroniona kolejka wiadomości do komunikacji między zadaniami; zadania posiadają uprawnienia do wysyłania (uprawnienia) i odbierania uprawnień do każdego portu.
  • wiadomości ” to kolekcje wpisanych obiektów danych, które można wysyłać tylko do portów — nie dotyczy to konkretnie zadań lub wątków

Mach rozwinął koncepcje IPC firmy Accent, ale uczynił system znacznie bardziej uniksopodobnym, zdolnym nawet do uruchamiania programów uniksowych z niewielką modyfikacją lub bez nich. W tym celu Mach wprowadził koncepcję portu , reprezentującą każdy punkt końcowy dwukierunkowego IPC. Porty posiadały zabezpieczenia i prawa jak pliki w systemie UNIX, co pozwalało na zastosowanie do nich bardzo podobnego do UNIX modelu ochrony. Ponadto Mach pozwalał każdemu programowi na obsługę uprawnień, które normalnie byłyby nadawane tylko systemowi operacyjnemu, aby umożliwić programom w przestrzeni użytkownika obsługę takich rzeczy, jak interakcja ze sprzętem.

W systemie Mach, podobnie jak w systemie UNIX, system operacyjny ponownie staje się przede wszystkim zbiorem narzędzi. Podobnie jak w przypadku UNIX, Mach zachowuje koncepcję sterownika do obsługi sprzętu. Dlatego wszystkie sterowniki dla obecnego sprzętu muszą być zawarte w mikrojądrze. Inne architektury oparte na warstwie abstrakcji sprzętowej lub egzokernelach mogą przenieść sterowniki z mikrojądra.

Główna różnica w systemie UNIX polega na tym, że zamiast narzędzi obsługujących pliki, mogą obsługiwać dowolne "zadanie". Więcej kodu systemu operacyjnego zostało przeniesione z jądra do przestrzeni użytkownika, co spowodowało znacznie mniejsze jądro i powstanie terminu microkernel . W przeciwieństwie do tradycyjnych systemów, w systemie Macha proces lub „zadanie” może składać się z wielu wątków. Chociaż jest to powszechne w nowoczesnych systemach, Mach był pierwszym systemem, który w ten sposób definiował zadania i wątki. Zadanie jądra zostało zredukowane z zasadniczo systemu operacyjnego do obsługi „narzędzi” i planowania ich dostępu do sprzętu.

Istnienie portów i wykorzystanie IPC jest prawdopodobnie najbardziej podstawową różnicą między Mach a tradycyjnymi jądrami. W systemie UNIX wywoływanie jądra składa się z operacji znanej jako wywołanie systemowe lub trap . Program wykorzystuje bibliotekę do umieszczania danych w dobrze znanej lokalizacji w pamięci, a następnie powoduje błąd , rodzaj błędu. Kiedy system jest uruchamiany po raz pierwszy, jądro jest skonfigurowane jako „obsługa” wszystkich błędów, więc gdy program powoduje błąd, jądro przejmuje kontrolę, sprawdza przekazane mu informacje, a następnie wykonuje instrukcje.

W systemie Macha do tej roli został użyty system IPC. Aby wywołać funkcjonalność systemu, program prosi jądro o dostęp do portu, a następnie używa systemu IPC do wysyłania wiadomości do tego portu. Chociaż komunikaty były wyzwalane przez wywołania systemowe, tak jak w innych jądrach, pod Machem było to właściwie wszystko, co robiło jądro — obsługa rzeczywistego żądania byłaby zależna od innego programu.

Obsługa wątków i współbieżności zyskała dzięki przekazywaniu wiadomości za pomocą mechanizmów IPC, ponieważ zadania składały się teraz z wielu wątków kodu, które Mach mógł zamrażać i odblokowywać podczas obsługi wiadomości. Umożliwiło to rozproszenie systemu na wiele procesorów, używając pamięci współdzielonej bezpośrednio, jak w większości komunikatów Mach, lub dodając kod, aby skopiować wiadomość do innego procesora, jeśli zajdzie taka potrzeba. W tradycyjnym jądrze jest to trudne do zaimplementowania; system musi mieć pewność, że różne programy nie próbują pisać do tej samej pamięci z różnych procesorów. Jednak porty Mach, jego proces dostępu do pamięci, sprawiają, że jest to dobrze zdefiniowane i łatwe do wdrożenia, i stały się obywatelami pierwszej klasy w tym systemie.

System IPC początkowo miał problemy z wydajnością, więc opracowano kilka strategii, aby zminimalizować wpływ. Podobnie jak jego poprzednik, Accent , Mach używał pojedynczego mechanizmu pamięci współdzielonej do fizycznego przekazywania wiadomości z jednego programu do drugiego. Fizyczne kopiowanie wiadomości byłoby zbyt wolne, więc Mach polega na jednostce zarządzania pamięcią (MMU) maszyny, aby szybko mapować dane z jednego programu do drugiego. Tylko wtedy, gdy dane zostaną zapisane, będą musiały zostać fizycznie skopiowane, proces zwany „ kopiowaniem przy zapisie ”.

Wiadomości były również sprawdzane pod kątem poprawności przez jądro, aby uniknąć awarii jednego z wielu programów składających się na system. Porty zostały celowo wzorowane na koncepcjach systemu plików UNIX. Umożliwiło to użytkownikowi znalezienie portów przy użyciu istniejących koncepcji nawigacji w systemie plików, a także przypisanie praw i uprawnień w taki sam sposób, jak w systemie plików.

Rozwój w takim systemie byłby łatwiejszy. Kod, nad którym pracujemy, nie tylko istniałby w tradycyjnym programie, który można by zbudować przy użyciu istniejących narzędzi, ale także mógłby być uruchamiany, debugowany i usuwany za pomocą tych samych narzędzi. W przypadku monokernela błąd w nowym kodzie spowodowałby wyłączenie całej maszyny i wymaganie ponownego uruchomienia, podczas gdy pod Machem wymagałoby to jedynie ponownego uruchomienia programu. Dodatkowo użytkownik może dostosować system tak, aby zawierał lub wykluczał wszelkie wymagane funkcje. Ponieważ system operacyjny był po prostu zbiorem programów, mogli dodawać lub usuwać części, po prostu uruchamiając je lub zabijając, tak jak każdy inny program.

Wreszcie, pod Machem, wszystkie te funkcje zostały celowo zaprojektowane tak, aby były wyjątkowo neutralne dla platformy. Cytując jeden tekst na Macu:

W przeciwieństwie do UNIXa, który został opracowany bez względu na wieloprocesorowość, Mach zawiera obsługę wieloprocesorowości w całym tekście. Obsługa wieloprocesorowości jest również niezwykle elastyczna, od systemów z pamięcią współdzieloną po systemy bez pamięci dzielonej między procesorami. Mach jest przeznaczony do pracy na systemach komputerowych od jednego do tysięcy procesorów. Ponadto Mach można łatwo przenieść na wiele różnych architektur komputerowych. Kluczowym celem Macha jest bycie rozproszonym systemem zdolnym do działania na heterogenicznym sprzęcie. ( Dodatek B , Koncepcje dotyczące systemu operacyjnego )

Istnieje jednak szereg wad. Stosunkowo przyziemną kwestią jest to, że nie jest jasne, jak znaleźć porty. W systemie UNIX problem ten został rozwiązany z biegiem czasu, ponieważ programiści uzgodnili kilka „dobrze znanych” lokalizacji w systemie plików, aby spełniać różne zadania. Chociaż to samo podejście działało również w przypadku portów Macha, zakładano, że system operacyjny pod Macem jest znacznie bardziej płynny, a porty pojawiają się i znikają przez cały czas. Bez jakiegoś mechanizmu znajdowania portów i usług, które reprezentowały, duża część tej elastyczności zostałaby utracona.

Rozwój

Mach był początkowo hostowany jako dodatkowy kod napisany bezpośrednio do istniejącego jądra 4.2BSD, umożliwiając zespołowi pracę nad systemem na długo przed jego ukończeniem. Prace rozpoczęły się od już działającego systemu portów/IPC Accent, a następnie przeszły do ​​innych kluczowych części systemu operacyjnego, zadań i wątków oraz pamięci wirtualnej. Gdy części zostały ukończone, różne części systemu BSD zostały przepisane w celu wywołania Mach, a także w trakcie tego procesu dokonano zmiany w 4.3BSD.

W 1986 roku system był już gotowy do samodzielnego działania na DEC VAX . Mimo niewielkiej wartości praktycznej cel stworzenia mikrojądra został zrealizowany. Wkrótce potem pojawiły się wersje na IBM RT PC i dla stacji roboczych opartych na Sun Microsystems 68030 , udowadniając przenośność systemu. Do 1987 roku lista zawierała maszyny Encore Multimax i Sequent Balance , testujące zdolność Macha do pracy na systemach wieloprocesorowych. W tym samym roku wydano publiczne wydanie 1, a wydanie 2 nastąpiło w następnym roku.

Przez cały ten czas obietnica „prawdziwego” mikrojądra nie została jeszcze dostarczona. Te wczesne wersje Mach'a zawierały większość 4.3BSD w jądrze, systemie znanym jako serwer POE , co spowodowało, że jądro było w rzeczywistości większe niż UNIX, na którym był oparty. Pomysł polegał jednak na przeniesieniu warstwy UNIX z jądra do przestrzeni użytkownika, gdzie można było łatwiej nad nią pracować, a nawet wymienić. Niestety wydajność okazała się poważnym problemem i dokonano wielu zmian architektonicznych w celu rozwiązania tego problemu. Niezręczne problemy z licencjonowaniem systemu UNIX również nękały badaczy, więc te wczesne wysiłki mające na celu zapewnienie nielicencjonowanego środowiska systemowego podobnego do UNIX nadal znajdowały zastosowanie, również w dalszym rozwoju Mach.

Powstały Mach 3 został wydany w 1990 roku i wzbudził duże zainteresowanie. Mały zespół zbudował Mach i przeniósł go na wiele platform, w tym złożone systemy wieloprocesorowe, które powodowały poważne problemy dla jąder starszego typu. Spowodowało to spore zainteresowanie na rynku komercyjnym, na którym wiele firm rozważało zmianę platformy sprzętowej. Gdyby istniejący system można było przenieść, aby działał na Mach, wydawałoby się, że łatwo byłoby zmienić platformę pod spodem.

Mach zyskał znaczną poprawę widoczności, gdy Open Software Foundation (OSF) ogłosiła, że ​​będzie hostować przyszłe wersje OSF/1 na Mach 2.5, a także badała Mach 3. Mach 2.5 został również wybrany do systemu NeXTSTEP i wielu komercyjnych dostawców wieloprocesorowych. Mach 3 doprowadziły do licznych wysiłków na rzecz innych częściach systemów operacyjnych dla mikrojądro portowych, w tym IBM „s Workplace systemu operacyjnego i kilku wysiłków firmy Apple do budowy wersji cross-platform z klasycznego Mac OS .

Problemy z wydajnością

Mach pierwotnie miał być zamiennikiem klasycznego, monolitycznego UNIX-a iz tego powodu zawierał wiele podobnych do UNIX-a pomysłów. Na przykład, Mach używał systemu uprawnień i bezpieczeństwa wzorowanego na systemie plików UNIX. Ponieważ jądro było uprzywilejowane (działa w przestrzeni jądra ) w stosunku do innych serwerów i oprogramowania systemu operacyjnego, możliwe było, że nieprawidłowo działające lub złośliwe programy wysyłały do ​​niego polecenia, które mogłyby spowodować uszkodzenie systemu, i z tego powodu jądro sprawdzało każdą wiadomość pod kątem poprawności . Dodatkowo większość funkcji systemu operacyjnego miała być zlokalizowana w programach działających w przestrzeni użytkownika, co oznaczało, że musi istnieć jakiś sposób, aby jądro mogło przyznać tym programom dodatkowe uprawnienia, na przykład do działania na sprzęcie.

Niektóre z bardziej ezoterycznych funkcji Macha były również oparte na tym samym mechanizmie IPC. Na przykład Mach był w stanie z łatwością obsługiwać maszyny wieloprocesorowe. W tradycyjnym jądrze musi być wykonana rozległa praca, aby uczynić ją wklęsłą lub przerywaną , ponieważ programy działające na różnych procesorach mogą jednocześnie odwoływać się do jądra. W systemie Mach bity systemu operacyjnego są izolowane w serwerach, które mogą działać, jak każdy inny program, na dowolnym procesorze. Chociaż teoretycznie jądro Mach również musiałoby być ponownie wprowadzone, w praktyce nie stanowi to problemu, ponieważ jego czasy odpowiedzi są tak szybkie, że może po prostu czekać i kolejno obsługiwać żądania. Mach zawierał również serwer, który mógł przekazywać wiadomości nie tylko między programami, ale nawet przez sieć, co było obszarem intensywnego rozwoju pod koniec lat 80. i na początku lat 90.

Niestety, wykorzystanie IPC do prawie wszystkich zadań okazało się mieć poważny wpływ na wydajność. Testy porównawcze na sprzęcie z 1997 roku wykazały, że jednoserwerowe implementacje systemu UNIX oparte na Mach 3.0 były o około 50% wolniejsze niż natywne implementacje systemu UNIX.

Badanie dokładnego charakteru problemów wykonawczych przyniosło szereg ciekawych faktów. Jednym z nich było to, że sam IPC nie stanowił problemu: było trochę narzutu związanego z mapowaniem pamięci potrzebnej do jego obsługi, ale to tylko wydłużyło czas na wykonanie połączenia. Reszta, 80% czasu spędzonego, była spowodowana dodatkowymi zadaniami wykonywanymi przez jądro na wiadomościach. Najważniejsze z nich to sprawdzanie praw portów i ważność wiadomości. W testach porównawczych 486 DX-50 standardowe wywołanie systemowe UNIX trwało średnio 21 μs , podczas gdy równoważna operacja z Mach IPC wynosiła średnio 114 μs. Tylko 18 μs z tego było związanych ze sprzętem; reszta to jądro Mach, które uruchamiało różne procedury w wiadomości. Biorąc pod uwagę wywołanie systemowe, które nic nie robi, pełna podróż w obie strony w BSD wymagałaby około 40 μs, podczas gdy w systemie Mach w przestrzeni użytkownika zajęłoby to nieco poniżej 500 μs.

Kiedy Mach był po raz pierwszy poważnie używany w wersjach 2.x, wydajność była niższa niż w tradycyjnych monolitycznych systemach operacyjnych, być może nawet o 25%. Koszt ten nie był jednak uważany za szczególnie niepokojący, ponieważ system oferował również obsługę wielu procesorów i łatwą przenośność. Wielu uważało, że jest to oczekiwany i akceptowalny koszt do poniesienia. Gdy Mach 3 próbował przenieść większość systemu operacyjnego do przestrzeni użytkownika, obciążenie stało się jeszcze wyższe: testy porównawcze między Mach i Ultrix na MIPS R3000 wykazały spadek wydajności do 67% w przypadku niektórych obciążeń.

Na przykład uzyskanie czasu systemowego wymaga wywołania IPC do serwera w przestrzeni użytkownika, który utrzymuje zegar systemowy . Wywołujący najpierw pułapkuje w jądrze, powodując przełączenie kontekstu i mapowanie pamięci. Następnie jądro sprawdza, czy osoba wywołująca ma wymagane prawa dostępu i czy komunikat jest prawidłowy. Jeśli tak, istnieje inny przełącznik kontekstu i mapowanie pamięci, aby zakończyć wywołanie na serwerze przestrzeni użytkownika. Proces należy następnie powtórzyć, aby zwrócić wyniki, co daje łącznie cztery przełączniki kontekstu i mapowania pamięci oraz dwie weryfikację wiadomości. To obciążenie szybko łączy się z bardziej złożonymi usługami, w których często ścieżki kodu przechodzą przez wiele serwerów.

Nie było to jedyne źródło problemów z wydajnością. Inny koncentrował się na problemach związanych z prawidłową obsługą pamięci, gdy zabrakło pamięci fizycznej i musiało wystąpić stronicowanie. W tradycyjnych monolitycznych systemach operacyjnych autorzy mieli bezpośrednie doświadczenie z określaniem, które części jądra nazywają innymi, co pozwalało im dostroić swój pager, aby uniknąć stronicowania kodu, który miał zostać użyty. Pod Machem nie było to możliwe, ponieważ jądro nie miało pojęcia, z czego składa się system operacyjny. Zamiast tego musieli użyć jednego uniwersalnego rozwiązania, które zwiększyło problemy z wydajnością. Mach 3 próbował rozwiązać ten problem, dostarczając prosty pager, opierając się na pagerach w przestrzeni użytkownika w celu lepszej specjalizacji. Okazało się jednak, że nie przyniosło to większego efektu. W praktyce wszelkie korzyści, jakie miał, zostały zniszczone przez drogiego Niezależnego Konsultanta, który musiał go wezwać.

Inne problemy z wydajnością były związane ze wsparciem Macha dla systemów wieloprocesorowych . Od połowy lat 80. do początku lat 90. popularne procesory rosły w tempie około 60% rocznie, ale szybkość dostępu do pamięci rosła tylko o 7% rocznie. Oznaczało to, że koszt dostępu do pamięci ogromnie wzrósł w tym okresie, a ponieważ Mach opierał się na mapowaniu pamięci między programami, wszelkie „brakujące dane w pamięci podręcznej” spowalniały wywołania IPC.

Potencjalne rozwiązania

Narzut IPC jest głównym problemem dla systemów Mach 3. Jednak koncepcja wieloserwerowego systemu operacyjnego jest nadal obiecująca, choć nadal wymaga pewnych badań. Deweloperzy muszą uważać, aby wyodrębnić kod na moduły, które nie wywołują połączeń z serwera na serwer. Na przykład większość kodu sieciowego zostałaby umieszczona na jednym serwerze, minimalizując w ten sposób IPC dla normalnych zadań sieciowych.

Większość programistów zamiast tego trzymała się oryginalnej koncepcji POE pojedynczego dużego serwera zapewniającego funkcjonalność systemu operacyjnego. Aby ułatwić rozwój, umożliwili serwerowi systemu operacyjnego działanie w przestrzeni użytkownika lub w przestrzeni jądra. To pozwoliło im rozwijać się w przestrzeni użytkownika i mieć wszystkie zalety oryginalnego pomysłu Macha, a następnie przenieść debugowany serwer do przestrzeni jądra w celu uzyskania lepszej wydajności. Od tego czasu zbudowano kilka systemów operacyjnych przy użyciu tej metody, znanej jako kolokacja , w tym Lites , MkLinux , OSF/1 i NeXTSTEP/OPENSTEP/macOS. Chorus mikrojądro wykonany tę funkcję systemu podstawowego, dzięki czemu serwery zostać podniesiona do przestrzeni jądra za pomocą wbudowanych mechanizmów.

Mach 4 próbował rozwiązać te problemy, tym razem z bardziej radykalnym zestawem ulepszeń. W szczególności stwierdzono, że kod programu zazwyczaj nie jest zapisywalny, więc potencjalne trafienia z powodu kopiowania przy zapisie były rzadkie. W związku z tym sensowne było nie mapowanie pamięci między programami dla IPC, ale zamiast tego migracja używanego kodu programu do lokalnej przestrzeni programu. Doprowadziło to do koncepcji „wahadeł” i wydawało się, że wydajność uległa poprawie, ale programiści przeszli do systemu w stanie półużytecznym. Mach 4 wprowadził również wbudowane prymitywy kolokacji, czyniąc go częścią samego jądra.

W połowie lat 90. prace nad systemami z mikrojądrem były w dużej mierze w stagnacji, chociaż rynek ogólnie wierzył, że do lat 90. wszystkie nowoczesne systemy operacyjne będą oparte na mikrojądrach. Głównymi pozostałymi rozpowszechnionymi zastosowaniami jądra Mach są macOS firmy Apple i jego siostrzany system iOS, które działają na mocno zmodyfikowanym hybrydowym jądrze Open Software Foundation Mach (OSFMK 7.3) o nazwie „ XNU ” używanym również w OSF/1 . W XNU systemy plików, stosy sieciowe oraz funkcje zarządzania procesami i pamięcią są zaimplementowane w jądrze; system plików, sieć oraz niektóre funkcje zarządzania procesami i pamięcią są wywoływane z trybu użytkownika za pomocą zwykłych wywołań systemowych zamiast przekazywania komunikatów; Komunikaty Mach XNU są używane do komunikacji między procesami trybu użytkownika i dla niektórych żądań z kodu trybu użytkownika do jądra i od jądra do serwerów trybu użytkownika.

Mikrojądra drugiej generacji

Dalsza analiza wykazała, że ​​problem z wydajnością IPC nie był tak oczywisty, jak się wydawało. Przypomnijmy, że pojedyncza strona wywołania systemowego zajęła 20 μs w BSD i 114 μs w Mach działającym w tym samym systemie. Spośród 114 11 było spowodowanych zmianą kontekstu, identyczną jak w BSD. Dodatkowe 18 zostało użytych przez MMU do mapowania wiadomości między przestrzenią użytkownika a przestrzenią jądra. To daje tylko 29 μs, więcej niż tradycyjne wywołanie systemowe, ale niewiele.

Reszta, większość rzeczywistego problemu, była spowodowana przez jądro wykonujące takie zadania, jak sprawdzanie wiadomości pod kątem praw dostępu do portu. Choć mogłoby się wydawać, że jest to ważny problem bezpieczeństwa, w rzeczywistości ma to sens tylko w systemie podobnym do systemu UNIX. Na przykład system operacyjny dla jednego użytkownika z telefonem komórkowym lub robotem może nie potrzebować żadnej z tych funkcji, a jest to dokładnie ten rodzaj systemu, w którym system operacyjny Mach typu „wybierz i wybierz” byłby najbardziej wartościowy. Podobnie Mach powodował problemy, gdy pamięć została przeniesiona przez system operacyjny, co jest kolejnym zadaniem, które naprawdę ma sens tylko wtedy, gdy system ma więcej niż jedną przestrzeń adresową. DOS i wczesny Mac OS mają jedną dużą przestrzeń adresową współdzieloną przez wszystkie programy, więc w tych systemach mapowanie nie przyniosło żadnych korzyści.

Te realizacje doprowadziły do ​​powstania serii mikrojąder drugiej generacji , które dodatkowo zmniejszyły złożoność systemu i umieściły prawie całą funkcjonalność w przestrzeni użytkownika. Na przykład jądro L4 (wersja 2) zawiera tylko siedem wywołań systemowych i wykorzystuje 12k pamięci, podczas gdy Mach 3 zawiera około 140 funkcji i zużywa około 330k pamięci. Połączenia IPC pod L4 na 486DX-50 trwają tylko 5 μs, szybciej niż wywołanie systemowe UNIX w tym samym systemie i ponad 20 razy szybciej niż Mach. Oczywiście ignoruje to fakt, że L4 nie obsługuje uprawnień ani zabezpieczeń; ale pozostawiając to programom w przestrzeni użytkownika, mogą wybrać tyle lub tyle, ile potrzebują.

Potencjalny wzrost wydajności L4 jest ograniczany przez fakt, że aplikacje działające w przestrzeni użytkownika często będą musiały zapewniać wiele funkcji obsługiwanych wcześniej przez jądro. Aby przetestować wydajność end-to-end, MkLinux w trybie kolokacji porównano z portem L4 działającym w przestrzeni użytkownika. L4 dodał około 5%-10% kosztów ogólnych, w porównaniu do 29% Macha.

Oprogramowanie oparte na Mach

Poniżej znajduje się lista jąder systemu operacyjnego wywodzących się z Macha oraz systemów operacyjnych z jądrami wywodzącymi się z Macha:

Zobacz też

Bibliografia

Zewnętrzne linki