Do spisu treści tematu 3
3.3.2 Semafory systemowe
Spis treści
Wprowadzenie
W jądrze Linuxa znajdują się semafory dostępne tylko dla procedur systemowych
(mogą one być wołane jedynie z poziomu jądra). Nie mają one nic wspólnego
z semaforami IPC. Semafory jądra są obsługiwane przez funkcje o nieskomplikowanej
składni i budowie, a deklaracja tychże semaforów to deklaracja struktury
nazwanej semaphore. Oto jej opis (deklaracja w semaphore.h).
struct semaphore {
int count;
int waking;
int lock;
struct wait_queue * wait;
};
-
count jest to ilość procesów, które wiszą na semaforze lub gdy
count jest dodatni, to oznacza on wartość semafora.
-
waking to zmienna pomocnicza mająca znaczenie dla współbieżności.
Jest zawsze dodatnia i mówi ona ile procesów z kolejki czekających może przejść
pod semaforem. Powinna być inicjowana na zero.
-
lock to zmienna istotna dla wieloprocesorowości.
-
wait_queue to koleja procesów czekających na semaforze
Działanie
Jak działa taki semafor?
Rozpocznę opis od podnoszenia semafora (wywołanie funkcji up).
Funkcja ta zwiększa count i sprawdz jaką ma ta zmienna wartość
(to w asemblerze). Jeśli jest mniejsza lub równa zero, oznacza to, że jakiś
proces czekał na semaforze. Wówczas proces zwiększa zmienną waking
o jeden (jeden wiecej proces będzie mógł przejść pod semaforem) i "budzi"
wszystkie procesy z kolejki procesów czekających (budzenie to tylko zmiana
stanu procesu i dowiązań prev_task, next_task w strukturze
task_struct, więc wiele budzeń, np. dwa wywołania up
po kolei, nic nie psuje). Teraz jeden z nich (ten który najszybciej otrzymał
procesor) zmniejsza stan zmiennej waking i przechodzi pod semaforem.
Opuszczenie semafora systemowego (funkcja down lub down_interruptible)
polega z kolei na zmniejszeniu wartości count i sprawdzeniu czy
jest ona większa lub równa zero (asembler). Jeśli nie to proces wstawia
się do kolejki czekających na semaforze (pole wait struktury semaphore).
Dalej w pętli próbuje odjąć jeden od zmiennej waking o ile jest
ona większa od zera (odjęcie z wyłączonymi przerwaniami sprzętowymi
- znów istotna współbieżność). Gdy mu się to uda to wychodzi z pętli, w
przeciwnym przypadku wiesza się wywołując funkcję szeregującą schedule. Po powrocie z tej funkcji (inny proces wywołał up lub "nasz" proces otrzymał sygnał) cofa się do początku pętli. Przy obniżaniu semafora za pomocą funkcji down_interruptible możliwe jest jeszcze wyjście z pętli pod warunkiem otrzymania sygnału).
Po wyjściu z pętli proces usuwa się z kolejki czekających pod semaforem.
Funkcje
Funkcje systemowe obsługujące semafory pochodzą z plików:
-
include/asm-i386/semaphore.h
-
arch/i386/lib/semaphore.S
-
kernel/sched.c
void down_failed(), void up_wakeup() ,void down_failed_interruptible()
Te trzy funkcje służą do wołania z poziomu asemblera funkcji odpowiednio
__down, __up,
__down_interruptible.
void __down(semafor systemowy),
void __down_interruptible(semafor
systemowy),
void __do_down(semafor systemowy,
stan procesu),
Dwie pierwsze funkcje wołają trzecią (z różnym drugim parametrem). Trzecia
funkcja wykonuje podstawowe działania przy opuszczaniu semafora systemowego
(jest blokująca).
void __up(smafor systemowy)
Funkcja podnosi semafor systemowy (wewnątrz sched.c).
void down(semafor systemowy)
void down_interruptible(semafor
systemowy)
Funkcje opuszczające semafor systemowy. Pierwsza zawiesza go na sposób,
w którym nie przyjmuje sygnałów, druga pozwala na odebranie sygnału.
void up(semafor systemowy)
Funkcja podnosi semafor systemowy.
give_buzz_lock(int *)
get_buzz_lock(int *)
Te dwie funkcje mają znaczenie tylko dla wieloprocesorowości.
Autor: Bartosz Kruszyński