Do spisu treści tematu Zarządzanie procesami

Opis funkcji wait

Spis treści


Wprowadzenie

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

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 grup
y 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.

 


Wartości przekazywane przez funkcję

Sytuacje normalne

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)

Sytuacje błędne

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)


Algorytm funkcji

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łaniac
h 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;
}


Funkcja wait a ignorowanie sygnalu śmierci potomka

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.


Bibliografia:

  1. Źródła jądra:
  1. Maurice J. Bach, Budowa systemów operacyjnych UNIX, WNT 1995
  2. W. Richard Stevens, Programowanie zastosowań sieciowych w systemie UNIX , WNT 1995,1996

Autor: Małgorzata Górbiel