Do spisu tresci tematu 2
2.1.3 Opis funkcji wait
Spis tresci
Wprowadzenie
Funkcja wait
wstrzymuje proces wywolujacy do momentu,
az jeden z procesow potomnych przestanie dzialac.
Jezeli zakonczony potomek juz jest, to funkcja wraca natychmiast.
Implementacja funkcji wait
jest funkcja systemowa
sys_wait4
,
Funkcje ta wywoluje inna funkcja systemowa - sys_waitpid
,
a ta zas funkcja sys_wait
.
Parametrem funkcji wait
jest wskaznik do zmiennej typu int
.
Wywolanie wait
(s) odpowiada wywolaniu sys_wait4
(-1,s,0,NULL).
Pod adres s funkcja ma wpisac przyczyne zakonczenia procesu.
Procesy brane pod uwage
Funkcja wait
poszukujac procesu potomnego, ktory przestal dzialac
rozpatruje procesy ZOMBIE
i STOPPED
.
Proces moze osiagnac ten stan na dwa sposoby.
Pierwszy z nich to wywolanie funkcji exit
.Jedna z czynnosci
wykonywanych w tej funkcji jest zapamietanie argumentu
(czyli kodu wyjscia) w polu exit_code
struktury task_struct
odpowiadajacej konczacemu sie procesowi. Scislej rzecz biorac
zapamietywane jest 8 najmlodszych bitow argumentu przesunietych
o osiem pozycji w lewo.
Dla wielu sygnalow czynnoscia domyslna jest zakonczenie procesu.
Jesli proces nie zmieni obslugi takiego sygnalu i otrzyma go,
to wtedy rowniez przechodzi w stan ZOMBIE
, o czym mozemy sie
przekonac analizujac funkcje systemowa
do_signal
,
Do pola exit_code
jest wtedy wpisywany numer sygnalu (ewentualnie
ze znacznikiem pamieci), ktory przyniosl procesowi smierc.
Numer ten nie jest przesuwany tak jak argument funkcji exit
.
Wspomniany znacznik pamieci to siodmy bit liczac od zera.
Jest ustawiany, jesli konczacy sie proces generuje plik core,
czyli zrzut pamieci wewnetrznej. Dzieje sie tak przy standardowej
obsludze sygnalow SIGQUIT
, SIGILL
,SIGTRAP
, SIGABRT
, SIGFPE
i SIGSEGV
(dotyczy dostarczonego Linuxa 2.0, Stevens podaje jeszcze inne sygnaly
dla systemow 4.3BSD i V).
Proces przechodzi w stan STOPPED
po otrzymaniu sygnalu SIGSTOP
, SIGTSTP
, SIGTTIN
, SIGTTOU
(2 ostatnie nie wystepuja w systemie V). Uprzednio numer sygnalu,
ktory zatrzymal proces jest wpisywany do pola exit_code
.
Ojciec przy przegladaniu swoich synow w funkcji wait
w przypadku procesu STOPPED
sprawdza, czy w tym polu jest zero.
Jesli nie, to wait
zwraca identyfikator znalezionego procesu
wczesniej wyzerowawszy to pole0. Jesli tak, to znaczy, ze ojciec
juz sie dowiedzial o zatrzymaniu procesu potomnego i nie ma
sensu informowac go o tym powtornie. Wtedy przeszukiwanie jest
kontynuowane.
Wartosci przekazywane przez funkcje
Funkcja wait
przekazuje dwie wartosci:
1) zwraca identyfikator zakonczonego procesu potomnego
2) pod podany adres wpisuje przyczyne zakonczenia procesu.
Jesli byl to proces ZOMBIE
to wpisywana jest zawartosc pola
exit_code
. W przypadku procesu STOPPED
wartosc z exit_code
przesuwana jest o osiem bitow w lewo,
zas na wolne miejsce wpisywana jest wartosc 0x7f.
Dzieki takiej organizacji proces macierzysty zawsze moze rozroznic,
czy proces potomny, ktory przestal dzialac jest zatrzymany,
czy tez byl procesem ZOMBIE
i z jakiego powodu.
proces potomny: 8 starszych bitow 8 mlodszych bitow
wywolal exit argument dla exit 0x00
zabity sygnalem 0x00 numer sygnalu (*)
zatrzymany numer sygnalu 0x7f
(*) - w tym bajcie oprocz numeru sygnalu zapisanego na 5-ciu najmlodszych bitach jest takze zapisywana na najstarszym bicie informacja czy proces wygenerowal plik core (zrzut pamieci)
Po wystapieniu bledu funkcja biblioteczna wait
zwraca -1,
a do zmiennej errno
wpisuje kod bledu otrzymany z wywolania sys_wait4
.
Mozliwe bledy to:
- ECHILD
(proces wywolujacy w ogole nie ma potomkow)
- EFAULT
(adres podany jako parametr jest niewlasciwy - nalezy do przestrzeni w ktorej proces nie moze pisac)
- ERESTARTSYS
(w trakcie oczekiwania na smierc potomka proces dostal niespodziewany sygnal, t.zn. rozny od SIGCHLD
i nie zablokowany)
Algorytm funkcji
Najpierw funkcja sprawdza (verify_area
),
czy adres podany jako argument jest wlasciwy. Jesli proces nie moze
pisac po tym obszarze, to funkcja konczy sie zwracajac blad.
Wyjatkiem jest adres zerowy, ktory podany jako argument powoduje
to, ze nic pod niego nie jest wpisywane, zatem nie wymaga on weryfikacji.
Nastepnie (przy wywolaniu przez wait
) proces wpisuje sie do swojej
kolejki wait_chldexit
(pole struktury task_struct
). Ma to zastosowanie
w funkcji
notify_parent
(wykonywanej przy okazji do_exit
poprzez exit_notify
)
, w ktorej proces budzi swoj proces macierzysty czekajacy wewnatrz
wait
na smierc potomka.
Nastepny krok to przegladanie swoich synow. Przy wywolaniu funkcji
przez wait
argument pid jest rowny -1, zatem funkcja sprawdza
wszystkie procesy potomne procesu wywolujacego. Po znalezieniu pierwszego
'dobrego' procesu funkcja zwraca jego identyfikator po
wykonaniu czynnosci odpowiednich dla danego rodzaju procesu.
W przypadku ZOMBIE
sa to zwiekszenie czasu uzytkownika i systemu
procesu macierzystego (pola cutime,cstime
) o czas zuzyty przez potomka,
wpisanie zawartosci pola exit_code
pod adres podany jako argument
(o ile jest niezerowy) i usuniecie pozostalosci po procesie zakonczonym.
Dla procesu STOPPED
funkcja wpisuje odpowiednia wartosc pod podany adres
i ustawia pole exit_code
na 0. Funkcja oczywiscie nie zwalnia miejsca
po procesie, ani tez nie wznawia tego procesu.
Jesli proces w ogole nie ma synow to funkcja zwraca blad.
Jesli ma, lecz wszyscy 'dzialaja' to proces musi byc wstrzymany.
Wczesniej funkcja sprawdza, czy nie nadszedl jakis nieoczekiwany
sygnal, t.zn. rozny od SIGCHLD
i nie zablokowany. Jesli nadszedl,
to funkcja zwraca blad, jesli nie, to proces zasypia
(schedule)
,
jako TASK_INTERRUPTIBLE
, czyli dopuszczajac przerwania. Po obudzeniu
proces przechodzi ponownie do przegladania synow.
Funkcja wait
a ignorowanie sygnalu smierci potomka
Proces moze ustawic obsluge sygnalu SIGCHLD
na SIG_IGN
.
Oznacza to, ze proces macierzysty nie jest zainteresowany stanem koncowym
swoich procesow potomnych, zatem nie ma sensu przechowywac w systemie
procesow ZOMBIE
. Dlatego w momencie obslugi sygnalu SIGCHLD
(do_signal)
,
jesli proces go ignoruje, jadro samo (za proces) bedzie wywolywac
funkcje sys_wait4
z opcja WNOHANG
do skutku, t.zn. az nie bedzie
procesow ZOMBIE
. Powstaje pytanie, co wtedy gdy proces ignorujacy sygnal SIGCHLD
bedzie czekal wewnatrz funkcji wait
i jeden z jego potomkow stanie sie
procesem ZOMBIE
. Kluczowy jest moment obslugi sygnalu. W systemie
opisywanym przez Bacha proces ZOMBIE
zostanie usuniety. Proces
macierzysty zas dalej bedzie czekal wewnatrz funkcji wait
, az do smierci
wszystkich swoich potomkow i wtedy sys_wait4
zwroci blad ECHILD
.
Natomiast w dostarczonym systemie Linux 2.0, jak rowniez 1.2.8 (LAB)
proces nie zdazy obsluzyc sygnalu przed ponownym przeszukiwaniem
swoich synow, zatem znajdzie ZOMBIEGO
, usunie go i zwroci jego pid.
Demostruje to program
wait_prg1.c.
Natomiast w ogole automatyczne usuwanie procesow ZOMBIE
przy ignorowaniu sygnalu SIGCHLD
dziala, co demonstruje program
wait_prg2.c.
Zrodla informacji:
- Zrodla jadra:
- Maurice J. Bach, Budowa systemu operacyjnego UNIX, WNT 1995
- W. Richard Stevens, Programowanie zastosowan sieciowych w systemie UNIX , WNT 1995,1996
Autor: Marcin Wrozek