Choices

10 marca 2009

Jedną z cech systemów operacyjnych na którą zwykle kładzie się duży nacisk jest ich niezawodność i stabilność. W tym celu starano się rozwijać mikrojądra, które dzięki większej izolacji poszczególnych elementów systemu zmniejszają podatność na błędy. Także wykorzystanie bezpiecznych języków (jak np. w Singularity) jest pewnym krokiem w kierunku zwiększenia niezawodności systemów. Innym projektem wykorzystującym pewne ciekawe mechanizmy jest eksperymentalny system operacyjny Choices rozwijany na Uniwersytecie Illinois w Urbana-Champaign.

Ogólna budowa

Choices jest napisanym w C++ systemem operacyjnym zorientowanym obiektowo. Jako całość jest tworzony z wielu odrębnych obiektów współpracujących ze sobą. Składa się z frameworków definiujących poszczególne aspekty jego działalności. Dziedziczenie jest wykorzystywane do łatwego przenoszenia systemu na inne platformy i do stosowania zależnych od sprzętu optymalizacji. Choices wspiera SPARC, x86 oraz ARM, a także istnieje możliwość jego uruchomienia w trybie użytkownika na Solarisie i Linuksie.

Wyjątki procesora

Chocies korzysta z dobrodziejstw języków programowania wysokiego poziomu także w przypadku wyjątków procesora. Każde przerwanie jest obsługiwane przez InterruptManagera. Przekazuje on stosowne informacje do odpowiednich elementów systemu operacyjnego, lub jeżeli przerwanie jest wyjątkiem procesora zgłasza błąd. InterruptManager rzuca wtedy wyjątek C++ (model jego obsługi nie ma znaczenia), w taki sposób, aby stos wskazywał, że został on rzucony z miejsca w którym wystąpił wyjątek procesora. Dzięki temu kod obsługi wyjątków może zlokalizować błędną operację i wykonać odpowiednie czynności.

Odzyskiwanie po awarii

Choices wspiera mechanizmy odzyskiwania stanu programu (bądź jądra) w przypadku ewentualnych błędów spowodowanych wadliwym kodem lub nieprawidłowym funkcjonowaniem sprzętu.

  • przeładowanie kodu - jest to mechanizm uaktywniający się, gdy procesor zasygnalizuje próbę wykonania nieprawidłowej operacji, które są najczęściej oznaką błędu sprzętowego związanego z pamięcią operacyjną. W tej sytuacji wadliwa instrukcja jest ponownie ładowana z innego źródła danych (np. obrazu jądra trzymanego w pamięci flash). Dodatkowo, możliwe są okresowe kontrole poprawności kodu opierające się na zgodności sum kontrolnych. Ten mechanizm może być zastosowany jedynie do kodu, który nie jest generowany run-time.
  • mikrorestart jest wykonywany najczęściej gdy błąd wystąpi podczas wykonywania funkcji dostarczanej przez komponent. Polega na ponownym załadowaniu, przygotowaniu do działania i kolejnej próbie wywołania funkcji. W odróżnieniu od poprzedniego mechanizmu, mikrorestart skupia się głównie na próbie odzyskania uszkodzonych struktur danych, gdzie pomocne są także opisane w dalszej części artykułu Server State Regions.
  • automatyczny restart usługi - dotyczy głównie serwerów działających jako procesy w trybie użytkownika. Polega właściwie na tym samym co mikrorestart, z tym, że także próbuje radzić sobie z ewentualnymi problemami wynikającymi z utrzymywanych przez proces blokad oraz dostępu do pamięci współdzielonej. W celu umożliwienia skutecznego restartu usługi, Choices monitoruje wszystkie blokady utrzymywane przez procesy. W sytuacji gdy proces ulegnie awarii, blokady są zwalniane, tak aby nie powodowały problemów po wznowieniu działania programu.

  • transakcje - jest to sposób radzenia sobie z ewentualnymi błędami szeroko wykorzystywany w bazach danych. Transakcje polegają na zachowaniu kopii danych, tak aby można było całkowicie anulować wykonywaną operację, jeżeli którykolwiek z jej elementów się nie powiedzie. Innymi słowy, w przypadku napotkania błędu, dane pozostają niezmienione. Dzięki temu ewentualne błędy, nie mogą naruszyć integralności danych.

Kontrolowane restarty

Innym istotnym mechanizmem, co prawda jeszcze niezaimplementowanym, są policy-driven restarts. Dają programistom możliwość dokładnego opisania sposobu ponownego uruchamiania programu, tak aby dostosować go do konkretnych potrzeb. Możliwe jest także zdefiniowanie pewnych operacji jako reakcję na określony błąd zastępującą zwykły restart programu.

Server State Regions

Część mikrojąder jest zaprojektowana w taki sposób, że każdy serwer przetrzymuje wszystkie potrzebne mu dane na temat każdego z klientów. Jest to rozwiązanie proste i wygodne zarówno dla jądra jak i poszczególnych serwerów działających w przestrzeni użytkownika. Sprawia to jednak, że działanie programu jest uzależnione od przypisanych mu danych obecnych w usługach z których korzysta. W rezultacie, mimo izolacji poszczególnych komponentów, błąd w kodzie serwera wciąż może doprowadzić do błędu aplikacji z niego korzystających.

Rozwiązanie tego problemu, jakie zastosowano w Choices polega na przeniesieniu wszystkich danych aplikacji poza przestrzeń adresową serwera. Tworzy się w ten sposób tak zwane Server State Regions, obszary pamięci przechowujące wymagane przez konkretną usługę dane na temat aplikacji. SSR pomimo że są tworzone z pamięci dostępnej klientom, są dla nich ze względów bezpieczeństwa niedostępne. Dzięki temu, serwer może bezpiecznie umieścić w nich wszystkie informacje jakie dotyczą konkretnych aplikacji.

Gdy aplikacja po raz pierwszy skorzysta z usług oferowanych przez dany serwer, zostanie utworzony dla niej osobny SSR. Następnie przy każdym wywołaniu funkcji serwera odpowiedni SSR jest tymczasowo mapowany do jego przestrzeni adresowej1. Po wykonaniu wszystkich potrzebnych operacji i powrocie do kodu aplikacji serwer ponownie traci dostęp do SSR.

W przypadku awarii serwera zostaje on automatycznie uruchomiony ponownie. Dzięki SSR błąd serwera może naruszyć poprawność danych co najwyżej jednej aplikacji, podczas gdy wszystkie pozostałe nie odczują żadnych skutków awarii. Dodatkowo po restarcie serwer może uzyskać informacje na temat swojego poprzedniego stanu i spróbować naprawić ewentualne błędy w przetwarzanym SSR.

Zastosowanie SSR ma także szereg dodatkowych zaleta. Wykorzystywanie pamięci aplikacji do tworzenia SSR znacząco ogranicza możliwe sposoby przeprowadzenia ataku DoS na serwer. SSR są także niezależne od klienta, dzięki czemu mogą zostać wykorzystane do odzyskania dawnego stanu aplikacji przed jej ewentualną awarią. Oczywiście wymaga to dodatkowego wsparcia ze strony klienta i nie jest wspierane przez jądro w takim stopniu jak odzyskiwanie serwera, ale pozwala np. na niezerwanie połączeń TCP w przypadku błędu klienta.

1 Warto zaznaczyć, że nie wpływa to w znaczący sposób na wydajność, ponieważ każde wywołanie funkcji udostępnianych przez serwer i tak powoduje unieważnienie TLB.

Podsumowanie

Choices nie jest projektem przeznaczonym do użytku. Należy na niego patrzeć jak na system edukacyjny i eksperymentalny, który łączy w sobie wiele różnych mechanizmów zapewniających większą niezawodność. Wiele z tych rozwiązań zostało już zastosowanych w innych mikrojądrach, ale w Choices stara się stworzyć z nich spójny system współpracujących ze sobą elementów. Projekt niestety zdaje się być obecnie martwy, ostatnie aktualizacje jego strony miały miejsce latem 2007 r. Innym problemem jest fakt, że wiele mechanizmów zostało szczegółowo opisanych, ale nie są jeszcze zaimplementowane.

Komentarze do wpisu "Choices" zablokowane.