attributes(7) Miscellaneous Information Manual attributes(7)

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:

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

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.
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.
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.
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.
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:

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.
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.
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ą).
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.
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ą.

pthreads(7), signal-safety(7)

Autorami polskiego tłumaczenia niniejszej strony podręcznika są: 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.

1 listopada 2023 r. Linux man-pages 6.06