W tym post-cie, opiszę teoretycznie jądo systemu UNIX.
Jest to czwarta część na moim blogu dotycząca teorii systemów operacyjnych.
W kolejnych częściach opiszę: funkcje systemowe związane z procesami na bazie UNIX-a.
W części pierwszej opisałem: wstęp do UNIX-a.
W części drugiej opisałem: system plików UNIX-a.
W części trzeciej opisałem: powłokę UNIX-a.
Uwaga - materiał pochodzi z mojej skarbnicy wiedzy zgromadzonej podczas studiów na UAM w Poznaniu na przełomie lata 1999-2002 i wtedy też był redagowany. Stanowi doskonałe teoretyczne uzupełnienie wiedzy dla studentów kierunku informatyka.
Proszę traktować tego posta, jako opis jądra systemu operacyjnego UNIX bez podziału na wersje i rodzaje. Tam gdzie jest potrzeba wyraźnie zaznaczam jakiej wersji i jakiego rodzaju systemu operacyjnego UNIX-a dotyczy opis.
Materiał bazuje na książkach:
1. Podstawy systemów operacyjnych - wydawnictwo WNT, autorzy: Abraham Silberschatz i Peter B. Galvin
2. System operacyjny UNIX dla początkujących i zaawansowanych - wydawnictwo BUM, autorzy: Zbyszko Królikowski i Michał Sajkowski
Według mnie najlepsza książka dla osób rozpoczynajacych przygodę z systemem operacyjnym UNIX zarówno pod względem praktycznym jak i teoretycznym dla administratorów i programistów.
Jądro jest najgłębszą częścią
systemu operacyjnego UNIX. Działanie systemu operacyjnego w
obrębie jądra dzielimy na: - obsługę funkcji
systemowych, pułapek i przerwań. W jądrze możemy wyróżnić
dwie części: jedna z nich obsługuje zastosowania, a druga
przerwania. Struktura jądra - schemat:
[Rysunek jest przerysowny osobiście prze zemnie, część oryginalna znajduje się w książce, pt.: "System operacyjny UNIX dla początkujących i zaawansowanych" - Autorzy: Zbyszko Królikowski i Michał Sajkowski - str 95.]
Obie części jądra współpracują
w rozdziale zasobów systemu oraz realizacji operacji I/O.
Część obsługująca zastosowania rozpoczyna operacje I/O.
Rezygnuje z procesora i następnie czeka na powiadomienie
przez drugą część, że obsługa I/O została zakończona.
Funkcje
systemowe, pułapki i przerwania. Jednym z działań najczęściej
wykonywanych w jądrze jest żądanie wykonania funkcji
systemowej. Funkcje systemowe zapewniają dostęp do usług
świadczących przez jądro, a żądanie ich wykonania można
uważać za polecenia dla jądra. Program obsługujący wywołania
funkcji systemowej, zanim funkcja systemowa zostanie
zainicjowana wykonuje następujące działania wstępne: -
odczytuje parametry funkcji systemowej, - sprawdza czy
parametry są umieszczone pod poprawnymi adresami i następnie
kopiuje je z procesu użytkownika do jądra, - wywołuje w jądrze
odpowiedni program obsługujący f. systemową. Wyniki działania
funkcji systemowej są zwracane do procesu użytkownika. W
przypadku sukcesu program obsługi funkcji systemowej w jądrze
zwraca wartość specyficzną dla danej funkcji, w przypadku
porażki - wartość -1. W czasie wykonywania funkcji
systemowych mogą wystąpić dwa zdarzenia. Do procesu może
być wysłany sygnał albo inny proces może osiągnąć wyższy
priorytet. Jeżeli do procesu zostanie wysłany sygnał, to
może on spowodować zaniechanie funkcji systemowej. Inna możliwość
to zawieszenie sygnału do czasu zakończenia funkcji. Jeżeli
w systemie istnieje proces o wyższym priorytecie, to
program korygujący wywołuje program szeregujący procesy,
czyli program obsługujący przydział procesora do procesów.
Program ten spowoduje, że procesor zostanie przydzielony do
procesu o wyższym priorytecie. Pułapki mogą występować
z powodu błędu w programach (na przykład dzielenie przez
zero), czy też błędów systemowych (na przykład błąd
strony). Proces jest informowany o powstałym problemie albo
za pomocą sygnału, albo przez sam fakt swojego zakończenia.
Przerwania spowodowane przez urządzenia wejścia/wyjścia są
obsługiwane przez moduły obsługi urządzeń (device
drivers). Moduły te są włączane do jądra podczas
instalacji lub rozbudowy systemu. Programy spowodowane przez
inne urządzenia są obsługiwane przez programy przerwań
stanowiące standardową część jądra. Przerwania
spowodowane przez urządzenia występują asynchronicznie.
Programy obsługi urządzeń są uruchamiane na żądanie.
Kiedy występuje przerwanie moduł obsługi urządzenia odwołuje
się do tzw. stosu przerwań, znajdującego się w części
stosu - jądra danego procesu. Program obsługi przerwań
musi być wykonany do końca, to znaczy jego wykonanie nie
może być przerwane.
Zarządzanie procesami - w systemie
UNIX rozróżniamy dwa typy procesów: jądra i użytkowe.
Procesy jądra funkcjonują tylko całkowicie wewnątrz jądra.
Procesy użytkowe to wszystkie pozostałe procesy, tzn.
utworzony przez proces systemowy init i wszystkie procesy z
niego wyprowadzane. Proces init wykonuje funkcje
administracyjne w systemie, obejmuje obsługę prawidłowego
przejścia systemu z trybu jednego użytkownika do trybu
wielodostępnego i utworzenie procesu rejestracji (getty) użytkowników.
Przejście do trybu wielodostępnego odbywa się zgodnie ze
skryptem /etc./rc i obejmuje następujące czynności: -
usunięcie plików tymczasowych, ustawienie daty,
sprawdzenie systemu plików oraz zainicjowanie programów
szeregujących operacje wydruku, a także programów prowadzących
księgowości systemu i regulowanie zapisywania bloków
buforowanych wewnętrznie przez system na dysk. Podstawą
uruchomienia procesu w systemie jest umieszczenie go w pamięci
operacyjnej oraz przydzielenie mu procesora. Unix, tak jak
każdy system wielozadaniowy stwarza iluzję współbieżnie
wykonywania wielu procesów. Jądro systemu określa porządek
przydziału zasobów do procesów gotowych do wykonania - mówi
o szeregowaniu zasobów systemu. Jądro wykonuje również
szeregowanie procesów, tzn. dokonuje ustalenia kolejności,
w jakiej procesor ma być przydzielony do procesów gotowych
do wykonania. System UNIX wykorzystuje algorytm Round Robin
do szeregowania procesów, jednak kwant czasu jest dużo
mniejszy niż w standardowej wersji tego algorytmu. Każdy
proces ma określony priorytet, przy czym obowiązuje
zasada: im większa liczba, tym niższy priorytet. Procesy
systemowe wykonujące operacje wejścia/wyjścia oraz inne
ważne zadania systemowe mają priorytety o wartościach
ujemnych i nie mogą być usunięte przez sygnały.
Zwyczajne procesy użytkowników mają priorytety dodatnie,
tak więc nie mogą być wykonywane przed systemowymi.
Stosowany w systemie UNIX algorytm szeregowania to
wielokolejkowy algorytm priorytetowy. Algorytm szeregowania
w systemie UNIX - schemat:
[Rysunek jest przerysowny osobiście prze zemnie, część oryginalna znajduje się w książce, pt.: "System operacyjny UNIX dla początkujących i zaawansowanych" - Autorzy: Zbyszko Królikowski i Michał Sajkowski - str 98.]
Im więcej czasu procesora
dany proces zużywa, tym niższy staje się jego priorytet.
We współczesnych systemach kwant czasu procesora
przydzielany procesowi to najczęściej 0,1 sekundy (4.3 BSD
UNIX), natomiast co sekundę system przelicza na nowo wartość
priorytetów, według następującej reguły: nowy priorytet
= wartość bazowa + wykorzystanie procesora. Licznik
wykorzystania procesora jest zwiększany o 1 z każdym
taktem zegara systemowego i jest przechowywany w tak zwanej
tablicy procesu. Przekroczenie określonej wartości
powoduje przesunięcie procesu do kolejki o niższym
priorytecie. Wartość bazowa jest zazwyczaj równa zero. Użytkownik,
który pragnie obniżyć priorytet swoich procesów, może
ę wartość zwiększyć wykonując funkcje systemową nice.
Tylko administrator systemu może obniżyć wartość bazową
zwiększając tym samym priorytet swoich procesów. W ramach
określonej kolejki do szeregowania procesów jest
wykorzystywany algorytm Round Robin. Współpracuje on z
systemową procedurą timeout, która przekazuje modułowi
obsługi przerwań zegara informację o tym, że upłynął
określony kwant czasu. Odpowiednia procedura jądra
dokonuje przeszeregowania procesów. Proces traci przydział
procesora, gdy skończy się kwant czasu lub gdy oczekuje na
zakończenie operacji I/O. Proces może również zrezygnować
z przydziału procesora w efekcie zajścia określonego
zdarzenia (event). Każdy użytkownik jest identyfikowany
przez liczbę całkowitą zwaną identyfikatorem użytkownika
(user identification (uid)). Identyfikator przydzielony jest
użytkownikowi przez administratora systemu i może znaleźć
go w wierszu odpowiadającym nazwie danego użytkownika w
pliku /etc./passwd. Każdy proces ma automatycznie
przydzielony identyfikator użytkownika który go utworzył.
Użytkownik z identyfikatorem równym zero jest użytkownikiem
specjalnym zwanym użytkownikiem nadrzędnym (root user albo
superuser) albo administratorem systemu. Może on odczytywać
i zapisywać wszystkie pliki w systemie, niezależnie od ich
właściciela i ich zabezpieczenia. Procesy z
identyfikatorem uid równym zero mają możliwość
wykonania niewielkiej liczby chronionych funkcji systemowych
niedostępnych dla zwykłych użytkowników. Niektóre
programy realizujące określone polecenia powinny być dostępne
nie tylko administratorowi, ale również zwykłym użytkownikom
systemu. Ponieważ ze względu na wymogi bezpieczeństwa
systemu, administrator nie może udostępniać hasła do
sytemu innym użytkownikom, wprowadzono mechanizm umożliwiający
te programy. Mechanizm ten polega na zastąpieniu niektórych
bitów określających prawa dostępu do pliku zawierającego
program realizujący dane polecenie przez tak zwane bity
SETUID. Bity te oznaczone przez s, zastępują wybrane bity
x zezwalające na wykonanie programu, a ich obecność
oznacza, że efektywnym identyfikatorem użytkownika danego
procesu nie jest identyfikator użytkownika który ten proces
uruchomił, ale id. użytkownika który jest właścicielem
pliku zawierającego wykonywany program. W ten sposób
administrator systemu umożliwia w kontrolowany sposób dostęp
zwykłym użytkownikom do pewnych informacji o systemie.
Każdy
proces dysponuje wydzielonym obszarem pamięci, w którym
zawarta jest jego wirtualna przestrzeń adresowa oraz
obszary pomocnicze, z których korzysta jądro do zarządzania
pracą procesów. W wirtualnej przestrzeni adresowej procesu
wyróżnia się cztery segmenty: - segment tekstu programu,
- segment danych, - segment stosu, - szczelinę. Segment
tekstu programu rozpoczyna się od adresu 0 w wirtualnej
przestrzeni adresowej. W segmencie tym nie można niczego
zapisywać, można go tylko odczytać. Jest to dzielony między
różne procesy wykonujące ten sam kod. W drugim segmencie
znajdującym się za tekstem programu, mieszczą się dane użytkownika.
W tym obszarze proces może je zarówno zapisywać, jak i
odczytywać. W trzecim segmencie pamięci przechowuje się
stos. Rozpoczyna się od największego adresu w pamięci
wirtualnej procesu. Jeśli stos próbuje przekroczyć granicę
segmentu stosu, pojawia się przerwanie sprzętowe.
Odpowiednie procedury jądra systemu powiększają rozmiar
segmentu stosu obniżając jego granicę o kilka tysięcy
bajtów (najczęściej o rozmiar strony). Programy nie mają
możliwości zmiany rozmiaru segmentu stosu. Gdy program
rozpoczyna pracę na stos są wpisywane zmienne
charakteryzujące środowisko pracy programu oraz samo
polecenie i jego argumenty. Obraz procesu w pamięci
operacyjnej - schemat:
[Rysunek jest przerysowny osobiście prze zemnie, część oryginalna znajduje się w książce, pt.: "System operacyjny UNIX dla początkujących i zaawansowanych" - Autorzy: Zbyszko Królikowski i Michał Sajkowski - str 100.]
Zazwyczaj segment danych i
stosu danego programu współdzielą tę samą przestrzeń
adresową, lecz rozrastają się niezależnie w przeciwnych
kierunkach. Pomiędzy nimi znajduje się obszar nie
wykorzystanej przestrzeni, tzw. szczelina. Segment stosu
rozrasta się automatycznie, natomiast "ekspansja"
segmentu danych jest wykonana z wykorzystaniem funkcji
systemowej brk. Jeśli kilku użytkowników wykorzystuje w
danej chwili ten sam program, to w pamięci operacyjnej jest
przechowywana tylko jedna kopia programu, a nie kilka (po
jednej dla każdego użytkownika), jak to się zdarza w
innych systemach. Jest to możliwe dzięki mechanizmowi współdzielonego
segmentu tekstu programu. Wirtualna przestrzeń adresowa
procesów i pamięć fizyczna - schemat:
[Rysunek jest przerysowny osobiście prze zemnie, część oryginalna znajduje się w książce, pt.: "System operacyjny UNIX dla początkujących i zaawansowanych" - Autorzy: Zbyszko Królikowski i Michał Sajkowski - str 101.]
Nad wirtualną przestrzenią
adresową procesu znajduje się tzw. obszar użytkownika,
zawierający informację o stanie procesu. Są to unikalne
identyfikatory związane z procesem, informacje o prawach i
przywilejach związanych z procesem, obszar ten zawiera również
wszystkie deskryptory związane z procesem. Obszar ten może
czasami być podzielony na: - strukturę użytkownika która
przechowuje informacje o procesie potrzebna tylko wtedy, gdy
znajduje się on w p.o. Przechowywany jest tutaj
identyfikator użytkownika, który uruchomił proces oraz
identyfikator jego grupy. Pamiętany jest tutaj również
katalog bieżący i tablica otwartych plików procesu. -
blok kontrolny. Informację o procesie dopełniają wektory
środowiskowe i argumenty procesu, zawierające wartości
parametrów funkcji systemowych i wartości zwracane przez
te funkcje. Ogólnie procesy są wykonywane w dwóch
trybach: jądra i użytkownika. Wspomniane procesy jądra są
wykonywane tylko w trybie jądra natomiast procesy użytkownika
mogą być wykonywane w trybie użytkownika i w trybie jądra.
Procesy użytkownika mają dostęp do większości usług jądra
za pomocą funkcji systemowych. Wywołanie przez proces użytkownika
funkcji systemowej powoduje uruchomienie procesu systemowego
lub inaczej procesu jądra, który obsługuje wykonanie tej
funkcji. Proces jądra wykorzystuje stos różny od stosu
procesu użytkownika. Stos jądra (kernel stack) znajduje się
zaraz za strukturą użytkownika. Stos jądra i struktura użytkownika
tworzą razem systemowy segment danych. Do zarządzania
procesami jądro wykorzystuje różnego rodzaju bloki
kontrolne. Kiedy proces wykonywany w trybie użytkownika
żąda zasobów od systemu operacyjnego za pomocą funkcji
systemowej, to następuje zamiana jego trybu na tryb jądra.
Każdy tryb pracy wymaga dostępu do różnych zasobów.
Zasoby te tworzą kontekst procesu. Zasobami tymi mogą być:
- na poziomie użytkownika: zawartość przestrzeni
adresowej i jego środowisko uruchomieniowe, - na poziomie jądra:
oprócz wyżej wymienionych, parametry szeregowania (np.
priorytet procesu) i parametry sterowania zasobami. Użytkownik
może tworzyć procesy, sterować ich wykonywaniem i odbierać
informację o zmianie statusu wykonywania. Każdy proces ma
przydzieloną unikalną wartość, zwaną identyfikatorem
procesu (PID). Wartość ta jest używana przez jądro do
identyfikacji procesu oraz użytkownika do wywoływania
funkcji systemowej. Jądro tworzy proces przez powielenie
kontekstu innego procesu. Ten nowy proces zwany jest
procesem potomnym oryginalnego procesu macierzystego z
identyfikatorem PPID. Kontekst powielony przy tworzeniu
procesu zawiera zarówno stan wykonywania procesu na
poziomie użytkownika jak i jądra. Współistnienie procesów
można zilustrować na przykładzie procesu powłoki,
interpretującego polecenia użytkownika. Proces ten w
chwili odczytania polecenia z klawiatury tworzy proces
potomny odpowiedzialny za realizację tego polecenia.
Standardowo proces macierzysty (czyli powłoka) oczekuje na
zakończenie procesu potomnego i dopiero wówczas pobiera
kolejne polecenia. Użytkownik może spowodować aby dane
polecenie było wykonywane w tle. Wtedy proces powłoki nie
czekając na zakończenie danego procesu potomnego, pobiera
nowe polecenie i tworzy dla niego nowy proces.
Zarządzanie
urządzeniami wejścia/wyjścia - w systemie UNIX, tak jak w
wielu systemach operacyjnych, szczegóły urządzeń
fizycznych są ukryte przed użytkownikiem. Jednakże rozwiązanie
zastosowane w tym systemie jest unikalne. Zadanie ukrycia
wspomnianych szczegółów należy do jądra - a ściślej
do systemu zarządzania urządzeniami wejścia/wyjścia. Jak
wiemy, w systemie UNIX wprowadzono zasadę, że urządzenia
fizyczne są postrzegane przez użytkownika jako pliki. Osiągnięto
to definiując urządzenie wirtualne funkcjonalnie
odpowiadające dyskowi i pisząc specjalne programy obsługi
urządzeń (device drivers), odwzorowujące operacje urządzenia
wirtualnego w operacje urządzenia fizycznego. Ze względu
na konieczność specjalnego traktowania przez system
wspomnianych plików odpowiadających urządzeniom nazwano
je plikami specjalnymi. Istnieją dwa podstawowe typy plików
specjalnych: blokowe i znakowe. Pliki blokowe reprezentujące
urządzenia blokowe, czyli dyski i taśmy. Pliki znakowe
reprezentujące urządzenia znakowe, czyli terminale i
drukarki. System wejścia/wyjścia składa się ze zbioru
modułów obsługi urządzeń, zazwyczaj jednego modułu obsługi
na urządzenie określonego typu. Moduły te są dołączane
do sytemu operacyjnego podczas generowania jądra i nie mogą
być później usuwane. Ich zadaniem jest odseparowanie
reszty systemu od sprzętu. System wejścia/wyjścia systemu
UNIX jest podzielony na dwie części, zgodnie z klasyfikacją
urządzeń, tj. część obsługująca urządzenia blokowe i
część obsługująca urządzenia znakowe. Celem części
systemu, która obsługuje operacje wejścia/wyjścia urządzeń
blokowych, czyli przede wszystkim dysków, jest
minimalizacja liczby przesyłań do i z dysku. W tym celu
stosuje się pamięć notatnikową buforów, która jest
umieszczana między systemem plików a modułami obsługi
dysków. Przy wykonywaniu operacji odczytu z urządzenia w
pierwszej kolejności przeszukiwana jest pamięć
notatnikowa buforów. Jeżeli w buforze znaleziono
odpowiedni blok danych, to nie ma potrzeby wykonywania
czasochłonnej operacji wejścia/wyjścia. Jeżeli nie
znaleziono, to wyszukuje się bufor z listy wolnych buforów,
aktualizuje się numer urządzenia i numer bloku i wykonuje
operację odczytu do pamięci notatnikowej. Jeżeli nie ma
wolnych buforów to wyszukuje się bufor z danymi które
najdłużej czekały na zapis. Dane z tego bufora zostają
zapisane na urządzenie wyjściowe a zwolniony bufor może
być wykorzystany przez operację odczytu. Informacja o tym,
że blok danych znajduje się w buforze, zawarta jest w nagłówku
bufora. Pamięć notatnikowa jest wykorzystywana zarówno
przy wykonywaniu operacji zapisu, jak i odczytu. W celu
utrzymania spójności systemu plików w przypadku awarii
zawartości pamięci notatnikowej, jest zapisywana na dysk
co 30 sekund.
Mechanizm zarządzania pamięcią operacyjną
różni się znacznie w zależności od wersji systemu. Jest
to ściśle związane z ograniczeniami sprzętowymi. W
wersjach systemu wcześniejszych niż UNIX 3 BSD oraz
prostych wersjach systemu, wykorzystywanych na sprzęcie
klasy PC technika wymiany obszarów pamięci pomiędzy pamięcią
operacyjną, a dyskową jest stosowana w ograniczonym
zakresie. To znaczy, że jeżeli w systemie znajduje się
zbyt wiele procesów i brakuje wolnego obszaru pamięci
operacyjnej, to niektóre z tych procesów są usuwane (często
używa się pojęcia wymiatane - and. swapping) na
dysk, aż zwolni się wystarczająco duży obszar pamięci
operacyjnej. Alokacja pamięci odbywa się w tego typu
systemach według algorytmu FF (ang. First Fit). Jeśli w
danej chwili nie ma odpowiednio dużo, spójnego obszaru
pamięci proces ulega zawieszeniu. Decyzję o tym, który
proces ma być wprowadzony do pamięci operacyjnej lub z
niej usunięty, podejmuje proces zawiadowcy (scheduler)
czyli proces 0 (w niektórych systemach zwany również pod
nazwą swapper process) Proces zawiadowcy jest budzony
okresowo (zazwyczaj co kilka sekund) i sprawdza które
procesy powinny być usunięte z pamięci, a które do niej
wprowadzone. W pierwszej kolejności są usuwane procesy
najdłużej przebywające w pamięci lub procesy duże i
podobnie wprowadzane są procesy, które były poza systemem
najdłużej lub są małe. Aby uniknąć problemu migotania,
nie pozwala się na usunięcie procesów, które nie
przebywały w systemie przez określony czas. Taki schemat
zarządzania pamięcią operacyjną wykorzystuje wiele
wersji systemu UNIX: wszystkie systemy USG (UNIX Support
Group) z wcześniejszymi wersjami UNIX System V włącznie.
Technika stronicowania została wprowadzona po raz pierwszy
w systemie UNIX 3 BSD. Obecnie wykorzystuje się ją w
systemach UNIX BSD i najnowszych wersjach UNIX System V. Są
to systemy z pamięcią wirtualną, ze stronicowaniem na
żądanie. Technika ta jest realizowana w sposób bezpośredni,
to znaczy, że jeżeli proces potrzebuje strony, której w
danej chwili nie ma w pamięci operacyjnej, to do jądra
systemu jest wysyłane przerwanie - "błąd
strony", alokowana odpowiednia ramka w pamięci
operacyjnej i właściwa strona czytana z dysku. Obraz pamięci
operacyjnej w systemie UNIX 4 BSD - schemat:
[Rysunek jest przerysowny osobiście prze zemnie, część oryginalna znajduje się w książce, pt.: "System operacyjny UNIX dla początkujących i zaawansowanych" - Autorzy: Zbyszko Królikowski i Michał Sajkowski - str 124.]
W dolnym obszarze pamięci
znajduje się jądro systemu a nad nim mapa pamięci (core
map). Pozostała część pamięci operacyjnej jest
podzielona na ramki stron, które mogą zawierać: tekst
programu, segment danych, stos, strukturę użytkownika i
tablicę odwzorowania stron lub mogą być po prostu nie
wykorzystane. Mapa pamięci stanowi zbiór informacji o
zawartości ramek stron. Pozycja numer 0 mapy pamięci
opisuje ramkę stron nr. 0, pozycja numer 1 - ramkę nr. 1
itd. Ramki stron mają najczęściej rozmiar 1KB, natomiast
poszczególne pozycje w mapie pamięci opisujące ramki są
16-bitowe. Z reguły mapa pamięci nie przekracza 2% całkowitego
obszaru pamięci operacyjnej. Usuwanie stron z pamięci
operacyjnej przebiega w dwóch etapach. Najpierw strona jest
oznaczana w tablicy odwzorowania stron procesu jako nieważna
i na razie w stosunku do niej nie są podejmowane żadne
akcje. Jeżeli na tym etapie zostanie wygenerowany sygnał
przerwania "błąd strony", to strona, której
przerwanie to dotyczy, może być wtedy oznaczona jako ważna
i można ją wykorzystać bez konieczności wykonywania
operacji wejścia/wyjścia to jest sprowadzania ją z pamięci
zewnętrznej. Najczęściej wykorzystuje się algorytm
wymiany stron LRU. Algorytm ten opiera się na założeniu,
że strona z pamięci operacyjnej, która najdłużej nie była
wykorzystana, nie będzie prawdopodobnie wykorzystana w
najbliższej przyszłości. Mapa pamięci operacyjnej (z wyłączeniem
jądra) jest cyklicznie i liniowo przeglądana przez program
o nazwie clock hand (w BSD - two handed clock, w System V -
one handed clock). Jeżeli ramka jest wolna, program bada
następną i jeżeli jest w niej wpisana jakaś strona, to
następuje sprawdzenie odpowiedniego zapisu w tablicy
odwzorowania stron. Jeżeli strona występuje jako nieważna,
to jest usuwana, a ramka dodawana do listy ramek wolnych.
Natomiast jeśli strona jest oznaczona jako ważna i
aktualnie nie jest wykorzystywana przez operacje wejścia/wyjścia,
to jest status ulega zmianie na nieważny i stronę
pozostawia się na razie w spokoju. W systemie kontroli
podlega również liczba stron ze statusem ważna, tak aby
nie obniżyła się ona zbytnio, co mogło by spowodować
nagły wzrost żądań sprowadzenia stron z pamięci
dyskowej. Proces clock hand jest zaimplementowany jako część
procesu 2 - pagedaemon (swapper jest procesem 0, init
procesem 1). Proces ten większość czasu "śpi",
lecz w tym czasie trwa sprawdzanie (kilka razy na sekundę),
czy konieczna jest w systemie interwencja tego procesu. Jeżeli
tak proces 2 zostaje obudzony, na przykład gdy liczba ramek
w p.o. spadnie poniżej pewnej wartości progowej (lotsfree)
- zazwyczaj 1/4 pamięci. Proces clock hand uwzględnia
podczas pracy zarówno to, ile ramek brakuje do osiągnięcia
wartości progowej, jak i wskazówek zawiadowcy. Jeżeli
proces zawiadowcy zadecyduje że system jest przeładowany,
to pewne procesy są z systemu usuwane, aż przeładowanie
zniknie. Brane są przy tym pod uwagę pewne dodatkowe
parametry, tj. minfree najniższy limit wolnej pamięci oraz
desfree średni rozmiar dostępnej pamięci w ostatnim
okresie. Innymi słowy procesy są usuwane, jeśli w
systemie wystąpił brak pamięci. Omówiony mechanizm zarządzania
pamięcią operacyjną jest mechanizmem systemowym, a więc
ingerencje użytkowników są w nim niemożliwe. System UNIX
dostarcza jednak pewne dodatkowe możliwości ingerowania w
organizację pamięci wykorzystywanej przez programy
aplikacyjne. Służy do tego zestaw funkcji systemowych,
pozwalających na zdefiniowanie i manipulowanie tzw. pamięcią
współdzieloną. Pamięć współdzielona (shared memory) służy
do przekazywania danych między procesami. Obszar współdzielony
musi zostać utworzony z wykorzystaniem funkcji systemowej
shmget z argumentami klucz, rozmiar i tryb dostępu (inaczej
- flagi dostępu - and. shmflag). Funkcja ta zwraca
identyfikator obszaru. Każdy z procesów, który chce
wymieniać dane poprzez ten obszar musi dołączyć go
funkcją shmat, podając jako argumenty identyfikator
uzyskany z shmget, adres pod którym proces chce widzieć
obszar (gdy adres jest równy zero system przyłącza obszar
pod pierwszym wolnym adresem) oraz flagi dostępu. Funkcja
shmat zawiera adres, pod którym obszar współdzielony jest
widoczny w danym procesie. Po zakończeniu korzystania z
obszaru proces odłącza go wykonując funkcje shmdt,
przekazując jako argument adres obszaru.