Do spisu treści tematu Zarządzanie procesami
W Linuxie istnieją dwie funkcje służące
do zsynchronizowania swojego działania z zakończeniem działania lub zatrzymaniem
procesu potomnego.Są to funcje wait i waitpid.
Funkcja wait(s) wstrzymuje wywołujący ją proces do momentu, aż jeden z
jego procesów potomnych przestanie działać.
Funkcja waitpid( pid, s, options) wstrzymuje proces wywołujący do momentu,
aż potomek określony przez pid przestanie działać.
W obu funkcjach jeżeli odpowiedni potomek już jest, to funkcja wraca natychmiast.
Jeżeli paremetr s wywołania funkcji jest różny od 0, to funkcje wpisują
pod ten adres przyczynę zakończenia procesu.
Wywołanie funkcji wait( addr_stat) odpowiada
wywołąniu waitpid(-1,addr_stat,0).
Wywołanie funkcji waitpid wygląda następująco:
waitpid( pid_t pid , int *addr_stat ,int options)
Wartość pid
może być:
>0 oznacza oczekiwanie na proces potomny o identyfikatorze równym pid
=0 oznacza oczekiwanie na proces potomny, mający taki sam identyfikator
grupy jak proces wywołujący waitpid
=-1 oznacza oczekiwanie na dowolny proces potomny
<-1 oznacza oczekiwanie na proces potomny o identyfikatorze grupy
równym co do wartości bezwzględnej argumentowi pid
Wartość options
może wynosić:
WNOHANG oznacza natychmiastowy powrót z funkcji, w przypadku gdy nie ma
żadnego zakończonego procesu potomnego
WNOTRACE oznacza powrót z funkcji po znalezieniu dowolnego zatrzymanego
potomka, który nie był jeszcze uwzględniony w funkcji wait.
Funkcja wait przekazuje dwie wartości:
1) zwraca identyfikator zakończonego lub zatrzymanego procesu potomnego
2) pod podany adres wpisuje przyczynę zakończenia procesu. Jeśli był to
proces ZOMBIE to wpisywana
jest zawartość pola exit_code. W przypadku procesu STOPPED
wartość z exit_code przesuwana
jest o osiem bitów w lewo, zaś na wolne miejsce wpisywana jest wartosć
0x7f. Dzięki takiej organizacji proces macierzysty zawsze może rozróżnić,
czy proces potomny, który przestał działać jest zatrzymany, czy tez był
procesem ZOMBIE i z jakiego powodu.
proces potomny: 8 starszych bitów 8 młodszych bitów wywołał exit argument dla exit 0x00 zabity sygnałem 0x00 numer sygnału (*) zatrzymany numer sygnału 0x7f
3) jeżeli ustawiona była opcja WNOHANG
i proces nie ma zakończonych lub zatrzymanych potomków to zwracane jest
0
(*) - w tym bajcie oprócz numeru sygnału zapisanego na 5-ciu
najmłodszych bitach jest także zapisywana na najstarszym bicie informacja
czy proces wygenerował plik core (zrzut pamięci)
Po wystąpieniu błędu funkcja biblioteczna
wait zwraca -1, a do zmiennej errno
wpisuje kod błędu otrzymany z wywołania sys_wait4.
Możliwe błędy to:
- ECHILD (proces wywołujący
nie ma potomków określonych przez pid)
- EFAULT (adres podany jako
parametr jest niewłaściwy - należy do przestrzeni w której proces nie może
pisać)
- ERESTARTSYS (w trakcie oczekiwania
na śmierć potomka proces dostał niespodziewany sygnał, tzn. różny od SIGCHLD i nie zablokowany)
Implementacją funkcji waitpid jest funkcja
sys_wait4.
int sys_wait4( pid_t pid, unsigned int *stat_addr, int options,
struct rusage *ru)
{
sprawdź poprawność podanych argumentów i w przypadku argumentów niepoprawnych
zwróć odpowiedni błąd;
sprawdź czy adres podany jako argument ru
jest poprawny, jeżeli nie to zwróć błąd;
sprawdź czy opcja podana w parametrze options
jest jedną z dostępnych opcji, jeżeli nie to zwróć błąd EINVAL;
wstaw proces do swojej kolejki wait_chldexit (pole
struktury task_struct );
dla każdego potomka p wykonaj {
sprawdź czy p należy do zbioru procesów określonych przez pid, jeżeli nie
to przejdź do następnego potomka;
jeżeli stan p = TASK_STOPPED {
jeżeli proces ten był już uwzględniony we wcześniejszych wywołaniach
wait to przejdź do następnego potomka;
zapisz dane o użytkowaniu procesora przez p do struktury ru;
wpisz pod adres addr_stat wartość pola exit_code zatrzymanego procesu odpowiednio
przesuniętą;
zwróć pid znalezionego procesu;
}
jeżeli stan p=TAST_ZOMBIE {
zwiększ procesowi macierzystemu czas wykorzystania CPU o czas zużyty przez
potomka;
zapisz dane o użytkowaniu procesora przez p do struktury ru;
pod adres sddr_stat wpisz wartość pola exit_code zakończonego procesu;
zwolnij miejsce w tablicy procesów po zakończonym procesie;
zwróć pid zakończonego procesu;
}
}
jeżeli nie ma procesu potomnego odpowiadającego argumentom funkcji to funkcja
zwraca błąd ECHILD;
jeżeli wszystkie procesy potomne działają i ustawiona jest opcja WNOHANG
to zwróć 0;
jeżeli nadszedł jakiś nieoczekiwany sygnał, tzn. różny od SIGCHLD i nie
zablokowany to zwróć błąd ERASTARTSYS;
zaśnij dopuszczając przerwania
;
po obudzeniu od nowa przeglądaj synów;
}
Proces może ustawić obsługę sygnału SIGCHLD na SIG_IGN. Oznacza to, ze proces macierzysty nie jest zainteresowany stanem końcowym swoich procesów potomnych, zatem nie ma sensu przechowywać w systemie procesów ZOMBIE. Dlatego w momencie obsługi sygnału SIGCHLD (do_signal), jeśli proces go ignoruje, jądro samo (za proces) będzie wywoływać funkcję sys_wait4 z opcją WNOHANG do skutku, tzn. aż nie będzie procesów ZOMBIE.