Kierunki rozwoju systemu operacyjnego CROOK dla minikomputera MERA-400
Wstęp
W niniejszym opracowaniu podano skrótowo niektóre przemyślenia związane z pomysłem przeniesienia (z ulepszeniem) systemu CROOK na inny sprzęt, bądź też uczynienia go przenośnym (raczej może: znacznie bardziej przenośnym). Uwagi te i propozycje ilustrowane są przykładami rozwiązań, które istnieją (bądź istniały) w systemie CROOK ze wskazaniem niektórych ich wad i zalet -- głównie na podstawie praktycznych doświadczeń eksploatacyjnych w różnorakich otoczeniach.
Jednym z głównych celów jest "przepisanie" systemu na język wyższy (inaczej zresztą takie przedsięwzięcie było by mało realne w rozsądnym przedziale czasowym). Podano również niektóre propozycje dalszego rozwoju prac programistycznych.
Generalnie mówiąc, system CROOK w obecnej postaci jest już zbyt złożony. Zaciążyła na nim zbyt wielka uniwersalność, która, jak wiadomo, jest głównym wrogiem sprawności i niezawodności oprogramowania. Można by myśleć o KSO -- Klockowym Systemie Operacyjnym, gdzie ze starannie zdefiniowanych i opracowanych klocków składało by się nieduże, specjalizowane systemy operacyjne i dostrajało je do typu zastosowań.
Rozwój systemów CROOK
Historia rodziny systemów operacyjnych CROOK związana jest ściśle z historią polskich minikomputerów K-202 i MERA-400. Minikomputer K-202 pojawił się w Instytucie Okrętowym Politechniki Gdańskiej w 1972 roku pod hasłem automatyzacji i sterowania w okrętownictwie. K-202 miał bardzo nowoczesną jak na owe czasy architekturę, wielopoziomowy system przerwań, możliwość pracy w trybach użytkowym i systemowym, podział pamięci na bloki. Cechy te predysponowały minikomputer do pracy wieloprocesowej i wieloprogramowej, koniecznej w przewidywanych zastosowaniach.
System operacyjny CROOK-1 powstawał ewolucyjnie dostosowując się do aktualnych potrzeb i zmieniającej się konfiguracji K-202. Początkowa konfiguracja obejmowała procesor, 88 kB pamięci operacyjnej, czytnik taśmy papierowej, perforator, drukarkę i dwa dalekopisy służące jako końcówki użytkowników. Na tej konfiguracji system umożliwiał jednoczesną pracę dwóch użytkowników.
System CROOK-2 mógł sterować obiektem w czasie rzeczywistym (poprzez kasetę CAMAC), jednocześnie obsługując kilku użytkowników wprowadzających i wykonujących swoje programy. Użytkownik zgłaszjąc się do systemu rezerwował blok pamięci o żądanym wymiarze i w nim musiał już sam rozmieścić używane przez siebie programy. Dopuszczenie kolejnego użytkownika do pracy było uwarunkowane istnieniem wolnej pamięci, nie zajętej dotychczas przez innych użytkowników.
System CROOK-3 był już pełnym, dyskowym, wielodostępnym systemem operacyjnym mogącym pracować także w czasie rzeczywistym. Użytkownik przystępując do pracy musiał podać swoją nazwę i hasło otwierające dostęp do swojego własnego skorowidza zbiorów dyskowych. Ponadto mógł korzystać ze zbiorów umieszczonych w ogólnodostępnej bibliotece. Użytkownik mógł wprowadzić i uruchomić jednocześnie kilka programów, z których każdy mógł składać się z kilku współbieżnych procesów. System zapewniał pełną ochronę zbiorów i programów przed przypadkową lub celową ingerencją ze strony innych użytkowników.
W czasie gdy na K-202 powstawał CROOK-3 pojawiła się następczyni K-202, maszyna MERA-400. Chociaż wykonana w nieco nowszej technologii, MERA-400 zachowała prawie dokładnie architekturę i listę rozkazów K-202. Niewielkie zmiany dotyczyły sposobu realizacji rozkazów warunkowych, wywoływania funkcji systemowych (ekstrakodów) i postaci rozkazów wejścia-wyjścia. Dodano też kilkanaście nowych rozkazów. Przenoszenie oprogramowania z K-202 na MERĘ-400 odbywało się więc prawie automatycznie. W kilka tygodni po zainstalowaniu w Instytucie Okrętowym MERY-400 przeniesiono na nią systemy CROOK-2 i CROOK-3 wraz z całym pracującym pod tymi systemami oprogramowaniem.
Minikomputer MERA-400 posiadał w standardowej konfiguracji 64 kB pamięci operacyjnej i jeden dysk 5 MB. CROOK-3 potrafił w tej konfiguracji obsłużyć czterech użytkowników, przy czym sam system zajmował na stałe tylko 16 kB pamięci operacyjnej, a każdy z użytkowników miał pozostałe 48 kB do dyspozycji. Oczywiście zwiększenie pojemności pamięci operacyjnej pozwoliło na zwiększenie liczby jednocześnie obsługiwanych użytkowników i większy komfort pracy.
W 1981 roku na zlecenie Instytutu Maszyn Matematycznych powstał generalnie przekonstruowany CROOK-4, zawierający w sobie hierarchiczny podsystem zbiorów dyskowych i hierarchiczną strukturę procesów. Użytkownik pracując pod systemem CROOK-4 uzyskał możliwość wprowadzenia własnych nowych zleceń, definiowania własnych języków komunikacji z systemem, a także możliwość symulacji działania innych systemów operacyjnych. Do CROOKa-4 dołączono obsługę wszystkich urządzeń z którymi mogła współpracować MERA-400. Zespół z Politechniki Poznańskiej wykonał translatory języków FORTRAN, LISP, CSL, ALGOL i ostatnio MODULA-2. Systemy CROOK pracują na siedemdziesięciu instalacjach MERY-400 w bardzo różnych warunkach - w wyższych uczelniach, biurach projektów, przedsiębiorstwach przemysłowych. Stosunkowo najmniej jest zastosowań do sterowania w czasie rzeczywistym, czyli celu dla którego pierwotnie powstał. Nie mniej w kilku polskich miastach MERA-400 pod CROOK-iem steruje synchronizacją sygnalizacji świetlnej.
W 1985 roku zaprzestano ostatecznie produkcji MERY-400. Z końcem tegoż roku IMM zrezygnował z dalszej dystrybucji CROOKa-4. W tej sytuacji Przedsiębiorstwo Zagraniczne AMEPOL - producent m.in.: pamięci operacyjnych, procesorów komunikacyjnych umożliwiających podłączanie większej liczby końcówek oraz sterowników pamięci dyskowych typu WINCHESTER przejął funkcję dystrybutora systemu. Urządzenia produkowane przez AMEPOL uczyniły ze starej MERY-400 sprzęt nowej jakości. Sprzęt ten wymagał też adaptacji systemu operacyjnego. Pojawił się CROOK-5 współpracujący z procesorem komunikacyjnym, pamięciami operacyjnymi o pojemności 2 MB, z dyskami o dużej pojemności, z zegarem czasu rzeczywistego. Podsystem zbiorów dyskowych rozszerzono o zbiory w pamięciach operacyjnych (RAM-disc).
Ogólna charakterystyka systemu CROOK-6
System operacyjny CROOK-6 ma być przenośną i poprawioną wersją systemu operacyjnego CROOK-4 pracującego na minikomputerze MERA-400. Będzie to wielodostępny, dyskowy system operacyjny przeznaczony do:
- prowadzenia prac programistycznych, obliczeń inżynierskich, przetwarzania tekstów, dydaktyki;
- przetwarzania danych, wdrażania i eksploatacji wielodostępnych baz danych;
- sterowania w czasie rzeczywistym.
Przyjęta w systemie koncepcja współpracy procesów stwarza środowisko do implementacji języków programowania posiadających wbudowane mechanizmy współbieżności.
Zaprogramowanie możliwie dużej części systemu w języku 'C', jak i dostępność wszystkich mechanizmów systemowych z poziomu tego języka umożliwi przeniesienie systemu CROOK-6 na inny minikomputer. Zaadoptowanie biblioteki języka 'C' spod systemu UNIX stworzy dogodne warunki do przenoszenia oprogramowania między systemem CROOK-6 a innymi systemami (np. na komputerach osobistych typu IBM-PC).
Biblioteka użytkowa języka 'C' projektowana jest w ten sposób, by podstawowe funkcje były zgodne zewnętrznie zarówno z funkcjami systemu UNIX, jak i funkcjami dostarczanymi z kompilatorami języka 'C' dla komputerów IBM-PC i podobnych (kompilatory Aztec 'C' i Microsoft 'C').
Obiekty systemu operacyjnego
Najbardziej elementarnym obiektem mogącym uzyskiwać zasoby od systemu jest proces. Dla każdego procesu, w momencie jego powoływania, system tworzy wektor opisu procesu. Proces może posiadać własny blok pamięci operacyjnej oraz specjalny zbiór dyskowy służący do przechowywania obrazu pamięci procesu w czasie gdy proces nie zajmuje pamięci. Każdy proces może tworzyć inne procesy potomne, każdy (z wyjątkiem jednego) ma też swojego przodka. System zapewnia synchronizację procesów i przydziela im zasoby.
Dostęp do pamięci masowych (dyskowych) odbywa się poprzez hierarchiczny podsystem zbiorów, umożliwiając jednoczesne i wygodne korzystanie z nich wielu użytkownikom.
System umożliwia tworzenie zbiorów w pamięci operacyjnej (RAM-disc). Zbiory tego typu tworzone są tylko jako zbiory robocze (istnieją tylko do końca sesji użytkownika). Ich tworzenie i używanie jest takie same jak dla zbiorów dyskowych.
Proces jest połączony ze źródłem lub ujściem informacji (urządzeniem zewnętrznym, zbiorem dyskowym itp.) poprzez strumień. Strumień jest dołączony do procesu który go powołał i do wspomnianego wyżej obiektu końcowego (źródła lub ujścia informacji). Możliwe jest ponadto dołączanie strumienia do obiektu poprzez inny strumień. Przy realizacji odwołania do strumienia system przegląda najpierw strumienie własne, a następnie strumienie wszystkich przodków procesu. Tak więc strumień utworzony przez proces jest globalny dla wszystkich jego procesów potomnych. Istotną cechą określającą źródło lub ujście informacji w systemie jest przynależność do przestrzeni. Struktura przestrzeni określa sposób tworzenia, przechowywania i używania informacji. System rozpoznaje następujące przestrzenie:
- zbiorów i podobszarów dyskowych,
- RAM-disc,
- zbiorów taśmowych,
- urządzeń,
- komunikatów,
Funkcje systemowe
System operacyjny CROOK-6 udostępnia programom użytkowym kilkadziesiąt funkcji systemowych. Funkcje te mogą być wywoływane przez programy użytkowe za pomocą wywołań systemowych. Można wyróżnić 6 grup funkcji:
- Funkcje zarządzania procesami. W grupie tej znajdują się funkcje pozwalające zarówno na tworzenie i sterowanie pracą procesów potomnych jak i wykonywanie pewnych operacji pomocniczych dotyczących procesu wywołującego funkcję.
- Funkcje semaforowe. Funkcje realizujące typowe operacje semaforowe: semafor całkowitoliczbowy (dla procesów działających we wspólnym bloku pamięci) oraz semafor binarny (dla procesów używających wspólnego strumienia).
- Funkcje współpracy z podsystemem zbiorów. W tej grupie znajdują się funkcje tworzenia i usuwania zbiorów i strumieni, ustalania parametrów i kategorii dostępu do zbiorów, ustalania skorowidza bieżącego, dołączania i odłączania talerzy dyskowych oraz kilka funkcji pomocniczych.
- Funkcje WE/WY sekwencyjnego (znakowego buforowanego na poziomie systemu).
- funkcje swobodnego dostępu do zbiorów dyskowych.
- funkcje pomocnicze.
Istnieje grupa funkcji obsługiwanych przez system w sposób szczególny. Wywołanie funkcji z tej grupy powoduje alarm systemowy przekazywany do przodka niezależnie od deklaracji własnej obsługi alarmów. Są one przeznaczone do komunikacji procesu z procesem przodkiem.
Procesy
Proces jest podstawowym obiektem zarządzanym przez system operacyjny. Każdy proces (z wyjątkiem jednego, pierwotnego, który jest przodkiem wszystkich innych) może być utworzony tylko przez inny proces. W momencie tworzenia powstaje relacja przodek-potomek decydująca o wzajemnym oddziaływaniu procesów.
Proces po utworzeniu i uruchomieniu wykonuje się we wspólnym bloku pamięci ze swoim przodkiem. Może on tworzyć dowolną liczbę procesów potomnych. Mechanizm ten daje możliwość tworzenia rodziny procesów działających we wspólnym bloku pamięci (wspólny obszar kodu i danych).
Każdy proces nie posiadający potomków może zażądać od systemu "przeniesienia" tzn. umieszczenia go w osobnym bloku pamięci operacyjnej. System utworzy wówczas odpowiedni blok pamięci, załaduje do niego ciało procesu ze wskazanego zbioru i wznowi proces w nowym bloku pamięci. Po operacji "przeniesienia" procesu działają nadal wszystkie mechanizmy koordynacji właściwe dla procesów będących w relacji potomek-przodek.
Stany procesu
Proces od chwili utworzenia może znajdować się w jednym z czterech stanów:
- stan zatrzymania: stan ten występuje bezpośrednio po utworzeniu procesu, jak i po spowodowaniu alarmu systemowego oraz po zatrzymaniu przez przodka. Przejście do stanu aktywnego następuje tylko w wyniku wykonania operacji wznowienia przez przodka.
- stan oczekiwania: stan po wykonaniu operacji "czekaj". Wznowienie procesu następuje po spowodowaniu alarmu, wysłaniu komunikatu przez potomka lub po wznowieniu przez przodka.
- stan aktywny: stan normalnej realizacji procesu. Proces w tym stanie jest wykonywany, lub znajduje się na liście procesów oczekujących na dostęp do procesora.
- stan zawieszony: proces znajduje się na liście procesów oczekujących na zakończenie operacji WE/WY lub na przydzielanie zasobu systemowego (także na budzik lub podniesienie semafora).
Przodek procesu może w każdej chwili wznowić proces zatrzymany lub oczekujący, a także zatrzymać i usunąć proces będący w dowolnym stanie.
Dla procesów nierezydujących będących w stanie zatrzymania lub w stanie zawieszenia spowodowanego oczekiwaniem na zakończenie operacji WE/WY cały obraz pamięci procesu może być przechowywany w specjalnym zbiorze dyskowym tworzonym przez system podczas wykonywania operacji "przeniesienia".
Atrybuty procesów
Z każdym procesem związana jest liczba określająca atrybuty procesu. W czasie tworzenia procesu jest ona ustawiana tak samo jak w procesie przodku. Przeniesienie ciała procesu do osobnego bloku pamięci powoduje ustawienie wartości atrybutów na takie, jakie są zapisane w etykiecie zbioru zawierającego nowe ciało procesu.
Atrybuty procesu określają pewne jego dodatkowe cechy:
- proces rezydujący: proces nie posiadający zbioru obrazu pamięci, "zakotwiczony" na stałe w pamięci operacyjnej.
- proces o podwyższonych uprawnieniach; są to uprawnienia do podwyższania priorytetu, niestandardowego działania na obszarach dyskowych, do dowolnego ustalania parametrów zbiorów dyskowych itp.
Szeregowanie (koordynacja) procesów
Każdy proces ma przypisany priorytet. W systemie istnieje lista procesów aktywnych, na której umieszczane są procesy gotowe do wykonania. Proces przechodzący w stan aktywny umieszczany jest na liście według priorytetu, jako pierwszy wśród procesów o jednakowym priorytecie. Aktualnie wykonywanym jest zawsze proces pierwszy na liście. W wypadku zawieszenia lub zatrzymania procesu jest on usuwany z listy. Na końcu listy znajduje się zawsze systemowy proces "tracenia czasu", który wykonywany jest wtedy, gdy na liście nie ma innych procesów.
Alarmy zgłaszane przez procesy
Alarmami nazywane są wszystkie zdarzenia uniemożliwiające dalsze wykonywanie procesu. Mogą być one spowodowane błędem w programie, niewłaściwym działaniem urządzeń, odwołaniem do nieistniejącego zbioru, itp. Po spowodowaniu alarmu proces zostaje zatrzymany, alarm zostaje wpisany na listę alarmów przodka a przodek uaktywniony jeśli był w stanie oczekiwania. Proces mający potomków powinien po uaktywnieniu sprawdzać stan swojej listy alarmów. Służy do tego wywołanie systemowe które pobiera identyfikator procesu pierwszego na liście alarmów i usuwa ten proces z listy. Mechanizm listy alarmów używany jest także do przesyłania sygnałów do przodka. Przewidziano do tego celu grupę funkcji systemowych, których wykonanie powoduje zatrzymanie procesu i alarm z przekazaniem jako numeru alarmu numeru funkcji. Znaczenie poszczególnych numerów jest lokalne dla danego poziomu przodek-potomek. Każdy proces może zadeklarować własną obsługę alarmów, przekazując do systemu adres tablicy w której zostanie umieszczona zawartość licznika rozkazów i numer alarmu. Po sprawdzeniu numeru alarmu proces może zrezygnować z jego dalszej obsługi i przekazać alarm przodkowi, tak jakby nie była deklarowana własna obsługa.
Mechanizmy koordynacji wzajemnej procesów
System CROOK-6 udostępnia procesom wiele mechanizmów umożliwiających ich wzajemną koordynację i wymianę informacji. Przez wzgląd na związki zachodzące między współpracującymi procesami można wydzielić trzy grupy mechanizmów koordynacji:
- dla procesów będących w relacji potomek-przodek:
- badanie i zmiana stanu procesu potomnego,
- dostęp do pamięci procesu przez jego przodka,
- alarmy i sygnały przesyłane poprzez listę alarmów,
- komunikaty wysyłane w obu kierunkach;
- dla procesów działających we wspólnym bloku pamięci operacyjnej:
- semafory całkowitoliczbowe;
- dla procesów działających na wspólnym strumieniu:
- semafor binarny związany ze strumieniem.
Zarządzanie pracą procesu potomnego
System operacyjny ma wbudowane następujące wywołania umożliwiające procesowi sterowanie pracą jego potomków:
- DEFP -definiuj proces potomny i załaduj jego rejestry.
- DELP -usuń proces wraz z wszystkimi jego potomkami.
- TREG -pobierz zawartości rejestrów procesu potomnego.
- SREG -załaduj rejestry procesu potomnego.
- RUNP -uaktywnij proces potomny.
- HANG -zatrzymaj proces potomny.
- REAP -czytaj ze zbioru systemowego (zawierającego obraz pamięci operacyjnej procesu) lub z pamięci procesu potomnego.
- WRIP -pisz do zbioru systemowego lub do pamięci procesu potomnego.
Dla operacji REAP i WRIP pamięć procesu (lub odpowiedni zbiór dyskowy) traktowana jest tak jak zbiór dyskowy o dostępie bezpośrednim (swobodnym).
Koordynacja procesów potomek-przodek
Do koordynacji procesów będących w relacji potomek-przodek służy, opisany w punkcie 4.4, mechanizm listy alarmów, oraz mechanizm przesyłania komunikatów. Przesłanie komunikatu realizowane jest poprzez utworzenie lokalnego strumienia przy procesie adresacie. Obiektem końcowym tego strumienia jest bufor systemowy zawierający treść komunikatu. Proces odbierający musi sprawdzić istnienie odpowiedniego strumienia i wczytać z niego treść komunikatu. Otrzymanie komunikatu wznawia proces oczekujący, a dla komunikatu nadanego przez przodka, także proces zatrzymany. System nie zezwala na przejście procesu w stan oczekiwania jeżeli istnieje nie odebrany komunikat, lub proces potomny oczekujący na obsługę alarmu lub sygnału.
Semafor całkowitoliczbowy
Semaforem całkowitoliczbowym jest zmienna dostępna dla wszystkich procesów działających we wspólnym bloku pamięci. Jej wartość początkowa musi być nieujemna. System dba o to, by po wykonaniu operacji na semaforze jej wartość nie była mniejsza od 0. Argumentami operacji semaforowych są nazwa zmiennej i liczba o jaką należy zmienić wartość semafora. System udostępnia procesom dwie operacje na semaforze:
- WAIS -odejmij wskazaną liczbę od wartości semafora. Jeżeli wartość semafora pozostanie dodatnia lub równa zero kontynuuj proces; w przeciwnym przypadku pozostaw pierwotną wartość semafora bez zmian i zawieś proces do chwili uzyskania przez semafor odpowiedniej wartości (w wyniku wykonania funkcji SIGN przez inny proces).
- SIGN -zwiększ wartość semafora o podaną liczbę i ewentualnie uaktywnij czekające procesy (lub jeden z nich).
Semafor binarny
W systemie operacyjnym każdy strumień jest globalny dla wszystkich potomków procesu który go utworzył. W chwili tworzenia strumienia definiowany jest semafor którego wstępną wartością jest 1. System udostępnia procesom trzy operacje na semaforze:
- REAS -podaj wartość semafora. Jeżeli wartość semafora wynosiła jeden, zmień ją na zero.
- TAKS -jeśli wartość semafora strumienia wynosi jeden, zmień ją na zero. W przeciwnym razie zawieś proces do chwili uzyskania przez
semafor wartości jeden.
- RELS -jeśli proces wykonał uprzednio funkcję TAKS, ustal wartość semafora strumienia na jeden i ewentualnie uaktywnij jeden z czekających na ten semafor procesów.
Organizacja zbiorów w pamięciach dyskowych
Użytkowanie pamięci dyskowych w systemie CROOK-6 odbywa się w oparciu o podsystem zbiorów. Przez zbiór rozumiemy tutaj pewien spójny obszar pamięci dyskowej, wraz z odpowiadającą mu pozycją słownika zbiorów.
System umożliwia korzystanie ze zbiorów w sposób sekwencyjny jak również swobodny. Przy dostępie sekwencyjnym zbiór traktowany jest jako ciąg znaków (byte'ów) i system dokonuje przepakowania poszczególnych sektorów na znaki lub odwrotnie. Używany jest przy tym wskaźnik (związany ze strumieniem, poprzez który uzyskuje się dostęp do zbioru), który wskazuje aktualny element zbioru (znak, byte). Wskaźnik ten jest automatycznie zwiększany po pobraniu lub zapisie każdego elementu. Wskaźnik ten można odpowiednim ekstrakodem cofnąć do początku lub ustawić na koniec zbioru, co umożliwia dopisywanie do zbioru nowych elementów. Przy dostępie swobodnym system umożliwia przepisanie do/z pamięci operacyjnej zawartości dowolnego sektora lub sektorów położonych wewnątrz zbioru.
Pamięci masowe dyskowe są podzielone na jednostki logiczne zwane obszarami, odpowiadające zazwyczaj nośnikom fizycznym (talerz, pakiet wymienny). Do maszyny mogą być dołączone różne typy pamięci dyskowych – dyski z talerzami wymiennymi, dyski elastyczne (floppy disc), dyski niewymienne typu Winchester. System zapewnia jednakowy z punktu widzenia użytkowników i programów sposób dostępu do tych pamięci masowych, niezależnie od ich typu, jak również dołączanie i odłączanie poszczególnych obszarów, co z kolei umożliwia zmianę nośników wymiennych bez przerywania pracy systemu.
Zbiory zakładane przez użytkowników są tworzone w zasadzie jako nietrwałe i w tej postaci mogą istnieć co najwyżej do końca sesji. Jeśli użytkownik zechce zachować utworzony zbiór, może go utrwalić (w ramach przydzielonego budżetu sektorów). Może również udostępnić swoje zbiory do zapisu i odczytu lub tylko do odczytu użytkownikom podległym lub wszystkim użytkownikom.
Przy tworzeniu zbioru ustalany jest jego pierwotny rozmiar. Jeżeli przy zapisie do zbioru rozmiar ten okaże się zbyt mały, system przeprowadzi automatycznie operację rozszerzenia zbioru zajmując sektory przyległe do zbioru. Jeśli sektory pamięci dyskowej przyległe do zbioru są zajęte, system w ramach operacji rozszerzania zbioru przepisze cały zbiór w inne wolne miejsce. Dopiero przy braku na danym talerzu dyskowym spójnego obszaru o potrzebnym rozmiarze nastąpi alarm systemowy.
Organizacja obszarów dyskowych
Na każdym obszarze dyskowym znajduje się wielopoziomowe drzewo skorowidzów. Każdy, dopuszczony do pracy na danym obszarze użytkownik ma swój skorowidz główny. Może on tworzyć nowe, podległe sobie, skorowidze. Niektóre z nich mogą być skorowidzami głównymi użytkowników. Zbiory zakładane w danym skorowidzu są dostępne przy pracy w danym skorowidzu oraz we wszystkich skorowidzach nadrzędnych. Użytkownik może udostępnić zbiór (do odczytu, zapisu lub wykonania) wszystkim użytkownikom lub wszystkim użytkownikom podległym.
Opis drzewa skorowidzów oraz słownik zbiorów znajdują się w dwóch zbiorach szczególnych. Zbiory te, jak i skorowidz będący korzeniem drzewa tworzone są podczas inicjalizacji talerza dyskowego.
Algorytm szukania zbioru
Dostęp do zbiorów uzyskuje się poprzez strumienie. Przy dołączaniu do strumienia zbiór jest identyfikowany poprzez tytuł zbioru. Tytuł zbioru składa się z trzech elementów: nazwy przestrzeni, nazwy skorowidza i nazwy zbioru. Poszczególne elementy (z wyjątkiem nazwy zbioru) mogą być puste.
Decydujący wpływ na sposób szukania zbioru w skorowidzach ma format zadanego tytułu zbioru:
- podanie tylko nazwy zbioru powoduje przeszukiwanie skorowidzów na wszystkich dostępnych obszarach zgodnie z następującym algorytmem:
- ustalenie do przeglądania skorowidza bieżącego;
- ustalenie pierwszego obszaru na którym jest znany skorowidz jako obszaru do poszukiwania zbioru;
- poszukiwanie zbioru w skorowidzu ustalonym na ustalonym obszarze;
- ustalenie następnego obszaru na którym jest znany skorowidz jako obszaru do poszukiwania zbioru i powrót do punktu 3;
- ustalenie do przeglądania skorowidza nadrzędnego względem ostatnio przeglądanego i, jeżeli taki istnieje, powrót do punktu 2.
- podanie nazwy obszaru powoduje ograniczenie szukania zbioru do wskazanego obszaru;
- podanie nazwy skorowidza powoduje przeszukiwanie tylko wskazanego skorowidza na wszystkich obszarach dyskowych. System ustala wstępnie czy wskazany skorowidz jest nadrzędnym, podrzędnym, czy też obocznym (ani podrzędnym ani nadrzędnym) skorowidza bieżącego. Następnie poszukuje w nim zbioru o podanej nazwie i odpowiednio ustalonej kategorii dostępu. Należy dodać, że podanie nazwy skorowidza jest niezbędne przy dostępie do zbioru w skorowidzu podrzędnym oraz w skorowidzu nie będącym nadrzędnym względem bieżącego.
Parametry zbiorów
Zbiory dyskowe w systemie opisywane są przez kilka parametrów. Określają one bliżej zawartość zbioru i sposób jej użycia. Z informacji zawartej w etykiecie zbioru korzystać może zarówno system operacyjny, jak i programy tworzone przez użytkowników. W etykiecie zbioru znajdują się następujące parametry:
- długość zbioru,
- parametr 1,
- parametr 2,
- bity zezwoleń na dostęp do zbioru,
- atrybuty,
- parametr MEM.
Parametr "długość zbioru" określa wyrażony w sektorach rozmiar informacji zapisanej do zbioru.
Parametr 1 i parametr 2 interpretowane są przez system w zależności od sposobu korzystania ze zbioru:
- dla operacji transmisji znakowych określają one położenie końca zbioru i są ustalane funkcją systemową.
- dla programu ładowanego ze zbioru oznaczają one odpowiednio adres ładowania (i startowy) oraz długość ładowanego ciała programu;
- w pozostałych przypadkach nie są przez system analizowane i mogą być dowolnie używane przez programy.
Bity zezwoleń na dostęp do zbioru zawierają kategorie dostępu określające operacje jakie mogą być wykonywane na danym zbiorze spod innych skorowidzów, zależnie od ich położenia w drzewie w stosunku do skorowidza, w którym znajduje się dany zbiór.
Kategorie dostępu:
- (brak) - zbiór nietrwały (roboczy);
- OR - zezwolenie właścicielowi na odczyt;
- OW - zezwolenie właścicielowi na zapis;
- OE - zezwolenie właścicielowi na wykonanie;
- LR - zezwolenie użytkownikom podległym na odczyt;
- LW - zezwolenie użytkownikom podległym na zapis;
- LE - zezwolenie użytkownikom podległym na wykonanie;
- AR - zezwolenie wszystkim użytkownikom na odczyt;
- AW - zezwolenie wszystkim użytkownikom na zapis.
- AE - zezwolenie wszystkim użytkownikom na wykonanie.
Atrybutem zbioru jest liczba zawierająca pewne dodatkowe informacje o zbiorze np.:
- zbiór uszkodzony (atrybut ustalany przez program ustalania i korekcji skorowidzów);
- zbiór którego aktualna kopia jest na taśmie magnetycznej;
- zbiór który nie był ostatnio używany (atrybut przeznaczony do współpracy z programem
usuwającym stare zbiory z dysku);
- zbiór który nie zostanie usunięty podczas usuwania zbiorów nie używanych;
- atrybuty procesu którego ciało zostanie załadowane ze zbioru.
Parametr MEM zawiera liczbę określającą rozmiar pamięci przydzielanej przy pierwszym uruchamianiu programu ze zbioru (dotyczy tylko zbiorów zawierających programy binarne).
Rozwiązania stosowane w systemach CROOK
Organizacja pamięci operacyjnej
Maszyny na których były uruchamiane systemy CROOK (K-202 i MERA-400) mają wbudowane dość bogate mechanizmy umożliwiające zarządzanie pamięcią przez program pracujący w trybie uprzywilejowanym (system operacyjny). Cała dostępna pamięć podzielona jest na strony po 8 kB. Każda strona ma przypisany sobie identyfikator. System operacyjny ma możliwość łączenia kilku stron i przydzielania tak otrzymanego bloku pamięci procesom. Bloki pamięci nie muszą być spójne (tzn. mogą mieć "dziury"), natomiast ich przestrzeń adresowa nie może przekraczać 128 kB. Mechanizmy sprzętowe zapewniają całkowitą ochronę procesom pracującym w różnych blokach pamięci. Duża elastyczność tworzenia bloków ułatwia systemowi zarządzanie pamięcią i umożliwia jej efektywne wyzyskanie.
W systemie CROOK-2 system tworzył na polecenie użytkownika blok pamięci o żądanym rozmiarze. Użytkownik musiał sam rozmieszczać programy w swoim bloku, dbając o to, by jego programy wzajemnie się nie zakłócały. Programy różnych użytkowników nie mogły się natomiast wzajem zakłócić dzięki ochronie sprzętowej! W czasie pracy użytkownik mógł zażądać zmiany rozmiaru przydzielonego bloku. Tak zaprojektowane procedury przydziału pamięci były bardzo proste a mimo to umożliwiały jednoczesną pracę kilku użytkowników. Ich podstawową wadą było duże zapotrzebowanie na pamięć, która była zajęta niezależnie od tego czy była używana oraz konieczność uzgadniania rozmiarów bloków przez użytkowników. Na maszynie K-202 posiadającej 88 kB pamięci procedury te umożliwiały sensowną pracę co najwyżej trzem użytkownikom.
W systemie CROOK-3 pamięć była przydzielana procesom (programom). Wraz z utworzeniem bloku pamięci tworzony był zbiór dyskowy do przechowywania obrazu pamięci procesu wtedy, gdy proces był zawieszony, czekał na zakończenie wolnej operacji WE/WY lub gdy zostawał chwilowo zawieszony celem zwolnienia pamięci dla innego procesu. Przeprowadzanie wymian pamięci z dyskiem pogarszało nieco parametry systemu (wydłużało np. czas reakcji). System CROOK-3 był zainstalowany na około 10 minikomputerach MERA-400 i kilku K-202. Na minikomputerze K-202 wyposażonym w 88 kB pamięci mogło pracować jednocześnie czterech użytkowników, przy czym czas reakcji na proste polecenie podawane z monitora nie przekraczał na ogół jednej sekundy.
Rozwój systemu CROOK-4 nastąpił w czasie szybkiego wzrostu podaży pamięci operacyjnej. Większość instalacji minikomputera MERA-400 ma co najmniej 192 kB pamięci a instalacje wyposażone w ponad 1 MB nie należą do rzadkości. W tej sytuacji system operacyjny musiał umożliwić programom jak najlepsze jej wyzyskanie. W systemie CROOK-4 została zachowana zasada przydzielania pamięci procesom oraz metoda wymian między pamięcią a dyskiem. Do celów sterowania i pracy w czasie rzeczywistym została stworzona klasa procesów rezydujących. Procesy należące do tej klasy nie posiadają zbiorów na przechowywanie obrazu ich pamięci, gdyż nie jest ona wymieniana z dyskiem. W czasie eksploatacji systemu okazało się korzystne zaliczenie do tej klasy także procesów realizujących pewne podstawowe zlecenia operatorskie takie, jak np.: wyprowadzanie zawartości skorowidza, tworzenie nowego skorowidza, kopiowanie zbiorów i wiele innych. Możliwe jest ponadto zadeklarowanie trybu pracy systemu, w którym wszystkie procesy uruchamiane są jako rezydujące. W systemie przewidziano ponadto możliwość tworzenia zbiorów roboczych w pamięci operacyjnej (RAM-disc). Zbiory te widziane są przez programy tak samo jak zbiory dyskowe, przy czym dozwolona jest dodatkowa operacja polegająca na dołączeniu do przestrzeni adresowej procesu strony 8 kB należącej do zbioru. Operacja ta umożliwia wydatne zwiększenie przestrzeni adresowej procesu oraz stworzenie pamięciowych obszarów komunikacyjnych dla procesów pracujących w różnych blokach pamięci.
Obecnie w IOPG minikomputer MERA-400 wyposażony w pamięć 2 MB obsługuje jednocześnie do dwudziestu użytkowników: studentów i pracowników przygotowujących programy i wykonujących obliczenia inżynierskie oraz księgowość i dziekanat. Przy obciążeniu tego typu (długie obliczenia, edycja, kompilacja) podstawową barierą w polepszeniu jakości usług komputerowych (ocenianych przede wszystkim według czasu reakcji systemu na proste polecenie) staje się szybkość jednostki centralnej.
Projektując przenośny system operacyjny należałoby zrobić analizę procedur przydziału pamięci w celu określenia sprzętowo niezależnego interface'u z resztą systemu oraz wydzielenia możliwie dużej grupy funkcji niezależnych od sprzętu. Należałoby zdefiniować operacje podstawowe możliwe do zrealizowania przy pamięciach podzielonych na strony jak i w pamięciach ciągłych z rejestrami bazowymi.
Algorytmy szeregowania procesów
W systemie CROOK-1 zastosowano bardzo prosty algorytm szeregowania procesów typu LIFO, w którym w wyniku obsługi przerwania reaktywowany był proces oczekujący na to przerwanie. Algorytm ten okazał się skuteczny w prostych zastosowaniach systemu i zapewniał bardzo szyb_ką reakcję na zdarzenia zewnętrzne. System działał zupełnie poprawnie na komputerze bez generatora przerwań zegarowych.
W systemie CROOK-2, w związku z zastosowaniami do sterowania w czasie rzeczywistym, konieczne stało się wprowadzenie priorytetów procesów. Zachowano algorytm LIFO dla grup procesów o tym samym priorytecie. Oznaczało to, że po przerwaniu, oczekujący proces był umieszczany na liście procesów aktywnych jako pierwszy w grupie procesów o tym samym priorytecie. Reaktywowany był tylko wtedy, gdy nie było przed nim procesów o wyższych priorytetach. Ponadto dla grupy procesów o najniższym priorytecie wprowadzono cykliczną rotację (round-robin) w oparciu o przerwania z generatora zegarowego.
W systemie CROOK-3 zachowano w zasadzie ten sam algorytm, rozszerzając cykliczną rotację na wszystkie grupy procesów. Rotacja odbywała się oddzielnie dla każdej grupy procesów o tym samym priorytecie.
W systemie CROOK-4 dla poprawienia czasu wykonywania krótkich zadań, wprowadzono mechanizm obniżania priorytetu procesów które nie komunikowały się długo z urządzeniami zewnętrznymi.
Algorytmy szeregowania procesów były tworzone w zasadzie intuicyjnie, a skuteczność ich działania oceniana tyko obserwacyjnie. Badania skuteczności działania różnych algorytmów metodami pomiarowymi nie były dotąd prowadzone ze względu na szczupłość zespołu i konieczność realizacji pilniejszych zadań.
Organizacja zbiorów
Opisany w rozdziale 5 podsystem zbiorów jest od kilku lat używany na kilkudziesięciu instalacjach sytemu CROOK-4. Jego głównymi zaletami są:
- łatwe administrowanie stosunkowo dużą liczbą użytkowników i zbiorów;
- możliwość przygotowania środowiska (zbiorów bibliotecznych lokalnych) dla grupy użytkowników (mogą to być użytkownicy o niskich kwalifikacjach np. operatorzy wprowadzający dane);
- duża szybkość szukania zbioru osiągnięta dzięki skupieniu opisów zbiorów i opisu skorowidzów oraz
wprowadzeniu funkcji mieszającej;
- wprowadzenie kategorii zbiorów nietrwałych zapobiegające niepotrzebnemu 'zaśmiecaniu' nośnika.
Niewątpliwą wadą przyjętego rozwiązania jest konieczność nadawania skorowidzom unikalnych nazw. W sytuacji wymiany nośników między ośrodkami dochodzi czasem do kolizji nazw skorowidzów (nie powodują one jednak groźnych skutków). Przy projektowaniu systemu należałoby rozważyć możliwość stworzenia mechanizmu dostępu do zbioru według wskazanych ścieżek.
Osobnego komentarza wymaga sprawa spójności zbiorów. We wszystkich systemach CROOK każdy zbiór zajmuje zawsze spójny fragment obszaru dyskowego. Niepożądanymi efektami takiego rozwiązania jest konieczność przepisywania zawartości zbioru przy jego rozszerzaniu oraz fragmentacja nośnika (obszaru dyskowego). Z pomiarów przeprowadzonych w IOPG wynika, że w czasie pracy systemu na cztery operacje utworzenia nowego zbioru wykonywana jest jedna operacja przepisania, spowodowana rozszerzaniem zbioru. System wykonując operację przepisywania używa nie zajętej pamięci operacyjnej; zbiory przepisywane są w czasie rozszerzania blokami po 24 kB co znacznie przyspiesza operację i zmniejsza ruchy głowic dyskowych.
Podatność obszaru dyskowego na fragmentację zależy silnie od rodzaju wykonywanych prac. Z doświadczeń z eksploatacji systemu w IOPG wynika, że w skutek fragmentacji obszarów dyskowych traci się około 3% pojemności nośnika (bez przeprowadzania scalania). Wskaźnik ten będzie malał wraz ze wzrostem pojemności nośnika i rósł wraz ze wzrostem długości przechowywanych zbiorów. Sama zaś operacja scalania jest prosta w użyciu i stosunkowo szybka.
System w sposób istotny korzysta ze spójności zbiorów dyskowych. Operacje transmisji blokowych przeprowadzane są wprost do pamięci procesu, a sekwencyjne operacje WE/WY buforowane przez system wykonywane są poprzez bufory o pojemności 8 kB (oczywiście tylko przy istnieniu wolnej pamięci).
Takie rozwiązanie daje mniejszą liczbę transmisji oraz zmniejsza częstotliwość i zasięg ruchów głowic dyskowych w stosunku do rozwiązań stosujących "rozrzuconą" strukturę zbiorów (np. CP/M, PC-DOS, MS-DOS, UNIX). Ograniczenie liczby ruchów głowic nie pozostaje bez wpływu na częstość awarii stacji dyskowych.
Połączenia międzykomputerowe
Niewygody wynikające z eksploatacji w jednym ośrodku kilku oddzielnych minikomputerów MERA-400 spowodowały podjęcie prac mających na celu połączenie tych maszyn. Stosunkowo najprostsze było połączenie linią transmisji szeregowej poprzez standardowy interface V24. Wykonanie połączenia umożliwia już przesyłanie informacji. Używanie takiego połączenia nie jest jednak zbyt wygodne. Przesyłanie zawartości zbioru z jednego komputera do drugiego wymaga uruchomienia w każdym z nich programu kopiującego. Na czas kopiowania łącze jest zajęte i niedostępne dla innych użytkowników.
Dla usunięcia tych niedogodności zaprojektowano i wykonano moduł programowy wbudowany w system operacyjny, który umożliwia użytkowanie łącza w sposób komutowany programowo. Moduły obsługi łącza komunikują się z sobą używając protokołu komunikacji opracowanego specjalnie do tego celu. Każdy użytkownik pracujący na jednym z minikomputerów (podległym) może poprzez łącze zgłosić się na drugim minikomputerze (nadrzędnym) i normalnie pracować jako użytkownik tego komputera. Obsługa łącza zapewnia jednoczesną pracę poprzez łącze wielu użytkownikom. Ponadto każdy użytkownik może zlecić przesłanie zawartości zbioru z dysku połączonego z jednym komputerem na dysk połączony z drugim. Przesyłanie zbioru nie przeszkadza w pracy innym. Bloki przesyłanego zbioru przeplatają się z blokami konwersacji. Podczas przesyłania zbiorów sprawdzane są sumy kontrolne poszczególnych zbiorów i w razie wykrycia przekłamań transmisja danego bloku jest powtarzana.
Opracowany do obsługi łącza V24 program przesyłania zbiorów przydał się, po modyfikacji, do innego jeszcze celu. Opracowano mianowicie program dla 8-bitowego mikrokomputera "Baobab" (opracowanego w Instytucie Informatyki P.G.) pracującego pod systemem zgodnym z CP/M 2.2, pozwalający używać tego mikrokomputera jako inteligentnej końcówki MERY-400 poprzez łącze V24 przy szybkości 9600 bodów. Program ten pozwala na przesyłanie zbiorów z dysków systemu CP/M na dyski MERY-400 i odwrotnie, z pełną kontrolą poprawności na poziomie bloku i zbioru (oprócz możliwości użytkowania mikrokomputera jako normalnej końcówki MERY-400 oraz lokalnie pod CP/M). Program ten zostanie w najbliższej przyszłości przeniesiony na IBM-PC (nie powinno to być trudne, gdyż został napisany w języku 'C').
Oprogramowane w ten sposób połączenia między maszynami MERA-400 łagodzą trudności eksploatacji kilku maszyn, ale nie likwidują ich zupełnie. Nawet przy największej osiągalnej w interface V24 prędkości 9600 bodów łącze jest zbyt wolne. Jest to szczególnie uciążliwe gdy zachodzi na przykład potrzeba skopiowania całej zawartości dysku na podłączoną do drugiej maszyny jednostkę taśmy magnetycznej.
W celu pokonania i tej trudności zaprojektowano i wykonano urządzenie pracujące w kanale pamięciowym MERY-400 (kanał DMA). Urządzenie to sprzęga minikomputer MERA-400 z magistralą zewnętrzną do której poprzez identyczne urządzenia podłączone są inne minikomputery. Po zainicjowaniu połączenia transmisja odbywa się na drodze: pamięć operacyjna, kanał DMA, magistrala zewnętrzna, kanał DMA, pamięć operacyjna. Następuje przepisanie zawartości pamięci jednego komputera do pamięci drugiego komputera z szybkością ponad 2 MB/sek. Tak pracujące urządzenie pozwala na stworzenie z kilku minikomputerów jednego systemu o dużej mocy obliczeniowej, lub sieci minikomputerów współpracujących ze sobą. Otwierają się też nowe, ciekawe możliwości konstrukcji systemów operacyjnych pracujących na tak skonfigurowanym sprzęcie.
W chwili obecnej moduł programowy obsługi szybkiego łącza współpracujący z systemem CROOK-5 pozwala użytkownikowi każdego z dwóch połączonych minikomputerów na bezpośrednie korzystanie z pamięci dyskowych drugiego minikomputera. Zastosowanie obu łącz - szybkiego i wolnego, w zasadzie już teraz rozwiązuje wszystkie niewygody związane z jednoczesną eksploatacją kilku maszyn.
Mechanizmy współbieżności w językach wyższych
System operacyjny CROOK ma wbudowane mechanizmy, pozwalające uzyskać współbieżne wykonywanie procesów. Obecnie można tych mechanizmów używać jedynie w programach napisanych w języku symbolicznym (asemblerze). Nie ma jednak, z technicznego punktu widzenia, żadnych przeszkód by mechanizmy te nie były dostępne z poziomu języków wyższych, w szczególności języka 'C' i/lub Pascala.
System CROOK ma wszystko, co byłoby potrzebne do praktycznej na nim realizacji Concurrent Pascala Pera Brinch Hansena. Implementacja takiego rozszerzenia Pascala nie była by szczególnie trudna (istnieje dobrze zdefiniowany wzorzec). W dalszej części opracowania rozważane będą problemy związane z implementacją współbieżności w języku 'C'.
Implementacja współbieżności w języku 'C' wymaga wydzielenia i zdefiniowania zestawu funkcji realizujących takie mechanizmy oraz napisania odpowiednich bibliotek. Muszą one zapewniać:
- utworzenie i aktywację procesu;
- koordynację wzajemną procesów;
- możliwość wymiany informacji między współzależnymi procesami;
- uzyskiwanie przez procesy odpowiednich atrybutów (priorytety, "kotwiczenie" w pamięci operacyjnej itp.);
- ochronę przed wzajemnym zablokowaniem się procesów.
Funkcje te wymagają szczególnie starannego zaprojektowania. Wiąże się z tym konieczność podjęcia decyzji co do sposobu rozwiązania kilku problemów. Niektóre z tych problemów mają również wpływ na konstrukcję samego kompilatora języka 'C', a właściwie postaci generowanych przezeń programów wynikowych.
Rozmiar i przydzielanie pamięci na stosy
Zazwyczaj obszar pamięci przeznaczony na stos jest wkompilowany w program na sztywno według rozmiaru domyślnego (default) lub podanego jako opcja kompilatorowi, a jego przekroczenie nie jest badane w czasie wykonywania programu. Ma to taką zaletę, że nie powoduje żadnych narzutów związanych z kontrolą przekroczenia obszaru stosu, a wadę -- że wymaga zapewnienia odpowiedniego marginesu bezpieczeństwa. Maszyna MERA-400 daje wprawdzie możliwość rekonfiguracji pamięci procesu (dołączania pamięci do obszaru adresowania procesu w kwantach po 8 KBy, pod warunkiem, że w przestrzeni adresowej procesu jest odpowiednia "dziura" i że proces potrafi z tej pamięci zrobić użytek), jednakże możliwości praktycznej realizacji rozszerzania stosu tą metodą będą bardzo ograniczone jeśli mamy do czynienia z procesami wykonującymi się w tym samym obszarze adresowym (dzielącymi pamięć). Podobny problem (może nawet w jeszcze ostrzejszej formie) występuje w przypadku procesów działających na wspólnym kodzie, a mających rozłączne obszary stosów i danych.
Jedną z możliwych metod rozwiązania tych trudności może być umieszczenie odpowiednich mechanizmów w kompilatorze języka 'C'. Kompilator mianowicie, analizując program, wie ile stosu potrzebuje jaka funkcja, jakie funkcje wołają inne funkcje -- ergo potrafi określić rozmiar stosu potrzebnego programowi. Oczywiście, pod warunkiem, że jakaś funkcja nie woła się rekurencyjnie. Jednakże nawet w takim przypadku można przyjąć przez zaniedbanie jakąś umowną głębokość rekurencji (którą można podać kompilatorowi), a kompilator może drukować odpowiednie ostrzeżenie lub wręcz ustalić właściwy margines bezpieczeństwa stosu konwersacyjnie.
Innym możliwym rozwiązaniem było by zastosowanie sekwencji rezerwacji stosu w kodzie realizującym wołanie funkcji. Wówczas procesy pracujące na wspólnym kodzie mogły by również używać tego samego stosu, rekurencja w niczym by rzeczy nie utrudniała. Pozostał by natomiast problem globalnej kontroli wielkości stosu oraz pojawił by się nowy -- "pustych" obszarów stosu i ich odzyskiwania. Oczywistą jest rzeczą, że zastosowanie takiego rozwiązania w zasadniczy sposób powiększa narzut -- mechanizm wołania funkcji ma znaczenie w języku 'C' podstawowe i kod ten mechanizm realizujący powinien być jak najszybszy i jak najzwięźlejszy.
Wymiana informacji między procesami
System CROOK ma w obecnej chwili mechanizmy, pozwalające na zorganizowanie wymiany informacji między procesami oraz ich wzajemną synchronizację. Być może wadą jest ich ograniczenie do procesów będących w relacji przodek – potomek. Nie jest to jednak ograniczenie szczególnie dotkliwe, a usunięcie go było by stosunkowo łatwe.
Biblioteki podstawowe języka 'C'
Przy opracowywaniu funkcji bibliotecznych dla języka 'C' kierujemy się nałożonym sobie wymogiem, by większość podstawowych funkcji była zgodna z ogólnie przyjętym już standardem (spotykanym w większości lepszych kompilatorów 'C' dostępnych obecnie u nas). Ma to oczywiście na celu uzyskanie jak najwyższego stopnia przenośności programów.
Cały zestaw funkcji można umownie podzielić na trzy grupy:
- Funkcje zapewniające dostęp do mechanizmów systemu operacyjnego oraz wejście/wyjście najniższego poziomu (open, creat, close, read, write, lseek). Podstawowymi będą tu funkcje (specyficzne dla systemu) realizujące bezpośrednie wołanie funkcji systemu CROOK (ekstrakodów). Obecnie używany z kompilatorem 'C' mechanizm nie jest jeszcze zadowalający, ale z konieczności jest używany jako swego rodzaju "bootstrap". Do tej grupy należą również funkcje alokacji pamięci najniższego poziomu brk i sbrk, wymagające ścisłego powiązania z kompilatorem przy istniejącej w maszynie MERA-400 organizacji pamięci operacyjnej;
- Funkcje alokacji pamięci malloc, calloc, realloc, free oraz funkcje wejścia/wyjścia (buforowanego) (fopen, fclose, fread, fwrite, fgets, fputs, fgetc, fputc itd). Nie podjęto jeszcze ostatecznej decyzji, czy funkcje te powinny korzystać z buforowania przez system operacyjny, czy też same je wykonywać. Można przytoczyć wiele argumentów zarówno za jednym jak i za drugim rozwiązaniem. Jednym z występujących tu problemów jest odmienna konwencja traktowania znaków końca wiersza w zbiorach znakowych, która wiele kłopotów przysporzyła i innym implementatorom języka 'C' na systemach innych niż UNIX i jego klony. W systemie CROOK rekord znakowy (wiersz) rozpoczyna się znakiem LF a kończy znakiem CR. Konwencją języka 'C' jest jeden znak (LF) kończący wiersz. Inne systemy używają zazwyczaj pary znaków (CR i LF) jako zakończenia wiersza. Rozwiązanie zastosowane w systemie CROOK ma wiele zalet, jednakże bardzo utrudnia użycie wbudowanych w system mechanizmów blokowych transmisji znakowych przez funkcje języka 'C' z zachowaniem przyjętych dla tego języka (a właściwie dla systemu UNIX) konwencji. Alternatywą jest zastosowanie buforowania przez funkcje języka 'C', co oznacza konieczność wbudowywania czy też alokowania buforów w programy użytkowe (a to, na przykład, uniemożliwia wyrugowanie z pamięci operacyjnej programu wykonującego akurat powolną transmisję);
- Inne funkcje nie powiązane z systemem, jak np. funkcje matematyczne, operacje na łańcuchach, konwersje liczb i wiele innych.
Powyższy podział funkcji nie jest szczególnie ścisły ani kompletny, wskazuje jedynie na pewne zagadnienia wymagające rozwiązania bądź podjęcia decyzji. Wiadomo natomiast dość dokładnie, jaki musi być bazowy zestaw funkcji (głównie na podstawie własnych doświadczeń jak i analizy porównawczej bibliotek niektórych kompilatorów 'C').
Wielodostępne bazy danych
Wielodostępne bazy danych są przykładem zastosowań, wymagającym odpowiedniego zestawu funkcji bibliotecznych umożliwiających ich programowanie w językach wyższych. Podobnie jak w przypadku procesów współbieżnych (szczególnie działających w czasie rzeczywistym) konieczne są tu bardzo starannie opracowane biblioteki, dostarczające możliwości kontroli integralności bazy danych i ograniczające do minimum programiście możliwość napisania programów działających niszcząco na zazwyczaj bardzo istotne i cenne dane. Mechanizmy definiowania struktur rekordów, wyszukiwania informacji (nawet według bardzo złożonych algorytmów) itp. nie wymagają istotnego powiązania z systemem operacyjnym i dadzą się zrealizować przy użyciu podstawowego zestawu funkcji. Potrzebne są natomiast funkcje blokowania dostępu na poziomie zbioru i rekordu (a może nawet i pola) oraz mechanizmy chroniące przed zablokowaniem się procesów.
Może okazać się celowym zdefiniowanie specjalnego okrojonego podsystemu do takich zastosowań, z odpowiednimi procedurami kopiowania, rejestrowania i odtwarzania, mającymi na celu uzyskanie właściwego stopnia pewności i niezawodności.
Źródło: Kierunki rozwoju systemu operacyjnego CROOK dla minikomputera MERA-400, Zbigniew Czerniak, Włodzimierz Martin, Marek Nikodemski, Gdańsk 1986