attributes - pojęcia bezpieczeństwa POSIX
Uwaga: tekst niniejszej strony podręcznika
systemowego powstał w oparciu o materiał z rozdziału
„POSIX Safety Concepts” podręcznika biblioteki GNU C.
Więcej szczegółów na temat poniższych
tematów można znaleźć tamże.
Różne strony podręcznika systemowego
zawierają rozdział ATRYBUTY opisujący
bezpieczeństwa wywoływania funkcji w różnych
sytuacjach. Niniejszy rozdział opisuje funkcje z
następującymi oznaczeniami bezpieczeństwa:
- MT-bezpieczne
- Funkcje MT-bezpieczne, MT-Safe lub wątkowo-bezpieczne
można bezpiecznie wywołać w obecności innych
wątków. Cząstka MT w nazwie oznacza
wielowątkowość (ang. Multi Thread).
- Bycie MT-bezpieczną nie oznacza, że funkcja jest
niepodzielna, ani że używa jakichś mechanizmów
synchronizacji pamięci, udostępnianych przez POSIX
użytkownikom. Możliwe jest nawet, że wywołania
kolejnych funkcji MT-bezpiecznych nie da w efekcie kombinacji
MT-bezpiecznej. Przykładowo, jeśli istnieje wątek
wywołujący dwie funkcje MT-bezpieczne jedna po drugiej, nie
gwarantuje to zachowania równoważnego niepodzielnemu
wykonaniu kombinacji obu funkcji, ponieważ
współbieżne wywołania w różnych
wątkach mogą ze sobą oddziaływać w
destrukcyjny sposób.
- Optymalizacje całych programów, które mogą
doprowadzić do wyodrębnienia funkcji jako podprogramu
(funkcji otwartej) na przestrzeni interfejsów biblioteki,
mogą doprowadzić do niebezpiecznej zmiany kolejności,
dlatego nie zaleca się dokonywania takiego wyodrębniania na
przestrzeni interfejsu biblioteki GNU C. Udokumentowany status
MT-bezpieczny nie jest gwarantowany przy optymalizacji całych
programów. Jednak funkcje zdefiniowane w widocznych dla
użytkownika nagłówkach, są zaprojektowane jako
bezpieczne do wyodrębniania.
- MT-niebezpieczne
- Funkcje MT-niebezpieczne lub MT-Unsafe nie są
bezpieczne do wywołania w programach wielowątkowych.
Inne słowa kluczowe pojawiające się w uwagach
nt. bezpieczeństwa zdefiniowano w kolejnych rozdziałach.
Dla niektórych funkcjonalności czyniących
funkcje niebezpiecznymi do wywołania w pewnych sytuacjach, znane
są sposoby ominięcia kłopotów z
bezpieczeństwem, nie wymagające całkowitej rezygnacji z
ich wywoływania. Poniższe słowa kluczowe odnoszą
się do takich funkcjonalności i każda z definicji
wskazuje, jak należy ograniczyć cały program, aby
uniknąć problemu z bezpieczeństwem wskazanych danym
słowem kluczowym. Jedynie po zaobserwowaniu i odniesieniu się
do powodów, które czynią funkcję
niebezpieczną, za pomocą nałożenia
udokumentowanych ograniczeń, funkcja staje się bezpieczna do
wywołania w danym kontekście.
- init
- Funkcje oznaczone jako init w kontekście problemów
bezpieczeństwa wątkowego, przeprowadzają przy
pierwszym wywołaniu inicjalizację, która jest
MT-niebezpieczna.
- Wywołanie takiej funkcji przynajmniej raz w trybie pojedynczego
wątku, usuwa ten konkretny powód do uznania tej funkcji jako
MT-niebezpiecznej. Jeśli nie występują inne powody,
to funkcję można bezpiecznie wywoływać po
uruchomieniu innych wątków.
- race
- Funkcje oznaczone jak race w kontekście problemów
bezpieczeństwa wątkowego działają na obiektach
w sposób, który może powodować wyścig
do danych lub inne formy destrukcyjnej interferencji przy
współbieżnym wykonaniu. W niektórych
przypadkach te obiekty są przekazywane do funkcji przez
użytkowników; w innych są one używane przez
funkcje do zwrócenia wartości użytkownikom; w jeszcze
innych nie są nawet ujawniane użytkownikom.
- const
- Funkcje oznaczone jako const w kontekście problemów
bezpieczeństwa wątkowego, modyfikują w sposób
nieatomowy obiekty wewnętrzne, które mogą być
raczej rozważane jako stałe, ponieważ znaczna
część biblioteki GNU C korzysta z nich bez
synchronizacji. W przeciwieństwie do race, które
powoduje uznanie za MT-niebezpieczną zarówno
odczytujących jak i zapisujących obiekty wewnętrzne,
to oznaczenie odnosi się wyłącznie do
zapisujących. Zapisujący pozostają MT-niebezpieczni
przy wywołaniu, lecz obowiązkowa później
stałość obiektów, które
modyfikują, umożliwia uznanie odczytujących za
MT-bezpiecznych (o ile nie pozostają inne powody do uznania ich za
niebezpiecznych), ponieważ brak synchronizacji nie jest problemem,
gdy obiekty są faktycznie stałe.
- Identyfikator, który występuje po oznaczeniu const
pojawi się jako adnotacja bezpieczeństwa przy
odczytujących. Programy, które chcą
przeciwdziałać temu problemowi bezpieczeństwa, jednak
tak aby móc wywołać zapisujących, mogą
użyć nierekurencyjnej blokady odczytu i zapisu
powiązanej z identyfikatorem i chronić wszystkie
wywołania do funkcji oznaczonej jako const, po której
następuje identyfikator blokady zapisu oraz wszystkie
wywołania do funkcji oznaczonej samym identyfikatorem za
pomocą blokady odczytu.
- sig
- Funkcje oznaczone jako sig w kontekście problemów
bezpieczeństwa wątkowego mogą tymczasowo
instalować procedurę obsługi sygnału do
celów wewnętrznych, która może
interferować z innymi użyciami sygnału, wymienionymi
po dwukropku.
- Temu problemowi bezpieczeństwa można
przeciwdziałać, upewniając się, że w
trakcie wywołania nie dojdzie do innego użycia
sygnału. Zalecane jest: utrzymywanie nierekurencyjnej blokady mutex
(wzajemnego wykluczania) podczas wywoływania wszystkich funkcji
używających tego samego sygnału tymczasowego;
blokowanie tego sygnału przed wywołaniem i
późniejsze resetowanie jego procedury obsługi.
- term
- Funkcje oznaczone jako term w kontekście problemów
bezpieczeństwa wątkowego mogą zmieniać
ustawienia terminala w zalecany sposób, głównie:
wywoływać tcgetattr(3), modyfikować
niektóre znaczniki (flagi) i później
wywoływać tcsetattr(3), co otwiera okno, w
którym zmiany wykonane przez inne wątki są tracone. Z
tego względu funkcje oznaczone jako term są
MT-niebezpieczne.
- Zaleca się dlatego aplikacjom używającym terminala
unikać równoczesnej i wielobieżnej interakcji z
terminalem, nie używając mogących się tak
zachowywać procedur obsługi sygnału lub
sygnałów blokujących i utrzymywać
blokadę przy ponownym wywoływaniu tych funkcji i interakcji
z terminalem. Blokady tej powinno się używać
również do wzajemnego wykluczania w przypadku funkcji
oznaczonych jako race:tcattr(fd), gdzie fd jest deskryptorem
pliku kontrolującego terminala. Wywołujący
może użyć następujących blokad
wzajemnego wykluczania (mutex): pojedynczej (dla ułatwienia) albo
po jednej na terminal, nawet gdy są one opisane
różnymi deskryptorami pliku.
Do funkcji mogą być dołączone
dodatkowe słowa kluczowe wskazujące funkcjonalności,
które co prawda nie czynią funkcji niebezpiecznej do
wywołania, ale powinny być wzięte pod uwagę w
określonych klasach programów:
- locale
- Funkcje z adnotacją locale w kontekście
problemów bezpieczeństwa wątkowego odczytują z
obiektu locale (tłumaczenia) bez jakiejkolwiek formy
synchronizacji. Funkcje z adnotacją locale wywoływane
równolegle ze zmianą locale mogą zachowywać
się w sposób nieodnoszący się do
żadnych z aktywnych locale podczas ich wykonania, lecz z
nieprzewidywalną ich mieszanką.
- Funkcje te nie są jednak oznaczane jako MT-niebezpieczne. To
funkcje modyfikujące obiekt locale są oznaczane uwagą
const:locale i są uważane za niebezpieczne. Z tego
powodu, funkcje modyfikujące nie powinny być
wywoływane, gdy działa kilka wątków lub
włączone są sygnały asynchroniczne. W tych
kontekstach locale mogą być rozważane jako efektywnie
stałe, co czyni omawiane w powyższym akapicie funkcje
bezpiecznymi.
- env
- Funkcje oznaczone jako env w kontekście problemów
bezpieczeństwa wątkowego uzyskują dostęp do
środowiska za pomocą getenv(3) lub podobnego, bez
żadnej ochrony zapewniającej bezpieczeństwo w
obecności równoległych modyfikacji.
- Funkcje te nie są jednak oznaczane jako MT-niebezpieczne. To
funkcje modyfikujące środowisko są oznaczane
uwagą const:env i są uważane za niebezpieczne.
Z tego powodu, funkcje modyfikujące nie powinny być
wywoływane, gdy działa kilka wątków lub
włączone są sygnały asynchroniczne. W tych
kontekstach środowisko może być rozważane jako
efektywnie stałe, co czyni omawiane w powyższym akapicie
funkcje bezpiecznymi.
- hostid
- Funkcje oznaczone jako hostid w kontekście problemów
bezpieczeństwa wątkowego odczytują z systemowych
struktur danych identyfikator stacji („host id”). Te
struktury danych zwykle nie mogą być modyfikowane w
sposób niepodzielny. Ze względu na założenie,
że identyfikator stacji nie powinien się zmieniać,
funkcje odczytujące go (gethostid(3)) są
uważane za bezpieczne, natomiast funkcje go modyfikujące
(sethostid(3)) są oznaczane jako const:hostid
wskazując, że ich wywołanie może
wymagać szczególnej uwagi. W tym konkretnym przypadku,
szczególna uwagę należy zwrócić na
koordynację na poziomie systemu (a nie jedynie
wewnątrzprocesową).
- sigintr
- Funkcje oznaczone jako sigintr w kontekście problemów
bezpieczeństwa wątkowego uzyskują dostęp do
wewnętrznej struktury danych _sigintr biblioteki GNU C, bez
żadnej ochrony zapewniającej bezpieczeństwo w
momencie równoległej modyfikacji.
- Funkcje te nie są jednak oznaczane jako MT-niebezpieczne. To
funkcje modyfikujące struktury danych są oznaczane
uwagą const:sigintr i są uważane za
niebezpieczne. Z tego powodu, funkcje modyfikujące nie powinny
być wywoływane, gdy działa kilka wątków
lub włączone są sygnały asynchroniczne. W tych
kontekstach struktury danych mogą być rozważane jako
efektywnie stałe, co czyni omawiane w powyższym akapicie
funkcje bezpiecznymi.
- cwd
- Funkcje oznaczone jako cwd w kontekście problemów
bezpieczeństwa wątkowego mogą tymczasowo
zmieniać bieżący katalog roboczy podczas wykonania,
co może spowodować ustalanie ścieżek
względnych w sposób nieoczekiwany dla innych
wątków lub przy procedurach obsługi
odwoływania lub asynchronicznych sygnałach.
- Nie jest to wystarczający powód do oznaczania funkcji z
taką adnotacją jako MT-niebezpiecznej, lecz gdy zachowanie
to jest opcjonalne (np. nftw(3) z FTW_CHDIR), unikanie
takiej opcji może być dobrą alternatywą do
używania pełnych ścieżek lub
wywołań systemowych odnoszących się do
deskryptorów pliku (np. openat(2)).
- :identyfikator
- Po adnotacjach może czasem wystąpić identyfikator,
który ma pogrupować funkcje, które np.
uzyskują dostęp do struktur danych w niebezpieczny
sposób, jak w przypadku race i const lub
udostępniać szczegółowe informacje, takie jak
nazwa sygnału w funkcji oznaczonej jako sig. Przewiduje
się, że może to w przyszłości
dotyczyć również lock i corrupt.
- W większości przypadku identyfikator wymieni zestaw funkcji,
ale czasami może nazwać obiekty globalne, argumenty funkcji
lub powiązane z nimi identyfikowalne
właściwości lub fragmenty logiczne. Stosowania
notacja to np. :buf(arg) aby wskazać bufor powiązany
z argumentem arg lub :tcattr(fd) aby wskazać atrybuty
terminala deskryptora pliku fd.
- Najczęstszym zastosowanie identyfikatorów jest
udostępnienie logicznych grup funkcji i argumentów,
które muszą być chronione przez te same mechanizmy
synchronizacji, aby zapewnić bezpieczne operowanie w danym
kontekście.
- /warunek
- Część uwag bezpieczeństwa może
być warunkowa co oznacza, że mają zastosowanie tylko
gdy prawdziwe jest wyrażenie warunkowe dotyczące
argumentów, zmiennych globalnych albo nawet wartości
jądra. Na przykład /!ps i /one_per_line
wskazują, że wcześniejsza uwaga ma zastosowanie
tylko, gdy argumentem ps jest NULL, albo zmienna globalna
one_per_line jest niezerowa.
- Jeśli wszystkie uwagi czyniące funkcję
niebezpieczną są opatrzone takimi warunkami i żaden z
wskazanych warunków nie jest spełniony, to funkcja
może być uważana za bezpieczną.
Tłumaczenie niniejszej strony podręcznika:
Michał Kułach <michal.kulach@gmail.com>
Niniejsze tłumaczenie jest wolną
dokumentacją. Bliższe informacje o warunkach licencji
można uzyskać zapoznając się z
GNU General
Public License w wersji 3 lub nowszej. Nie przyjmuje się
ŻADNEJ ODPOWIEDZIALNOŚCI.
Błędy w tłumaczeniu strony podręcznika
prosimy zgłaszać na adres listy dyskusyjnej
manpages-pl-list@lists.sourceforge.net.