getrlimit(2) | System Calls Manual | getrlimit(2) |
NAZWA
getrlimit, setrlimit, prlimit - pobiera/ustawia limity zasobów
BIBLIOTEKA
Standardowa biblioteka C (libc, -lc)
SKŁADNIA
#include <sys/resource.h>
int getrlimit(int resource, struct rlimit *rlim); int setrlimit(int resource, const struct rlimit *rlim);
int prlimit(pid_t pid, int resource, const struct rlimit *_Nullable new_limit, struct rlimit *_Nullable old_limit);
struct rlimit { rlim_t rlim_cur; /* Soft limit */ rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */ };
typedef /* ... */ rlim_t; /* Unsigned integer type */
prlimit():
_GNU_SOURCE
OPIS
The getrlimit() and setrlimit() system calls get and set resource limits. Each resource has an associated soft and hard limit, as defined by the rlimit structure.
Ograniczenie miękkie jest wartością odpowiedniego zasobu wymuszoną przez jądro. Ograniczenie sztywne działa jako górna granica dla ograniczenia miękkiego: proces nieuprzywilejowany może sobie ustawić ograniczenie miękkie tylko w zakresie od 0 do ograniczenia sztywnego oraz (nieodwracalnie) obniżyć swoje ograniczenie sztywne. Proces uprzywilejowany (w Linuksie: proces z przywilejem CAP_SYS_RESOURCE (ang. capability) w swojej pierwotnej przestrzeni nazw użytkownika) może dowolnie zmieniać każdą z wartości ograniczenia.
Wartość RLIM_INFINITY określa brak ograniczenia dla zasobu (zarówno w strukturze zwracanej przez getrlimit(), jak i w strukturze przekazywanej do setrlimit()).
Argument resource musi być jednym z:
- RLIMIT_AS
- Jest to maksymalny rozmiar pamięci wirtualnej procesu (przestrzeni adresowej). Limit jest określony w bajtach i zaokrąglony w dół, do systemowego rozmiaru strony. Limit dotyczy wywołań do brk(2), mmap(2) i mremap(2), które po jego przekroczeniu zawiodą z błędem ENOMEM. Dodatkowo, zawiedzie automatyczne rozszerzenie stosu (i wygeneruje sygnał SIGSEGV zabijający proces, jeśli za pomocą sigaltstack(2) nie stał się dostępny alternatywny stos). Ze względu na to, że wartość ta ma typ long, na komputerach z 32-bitowym long limit ten wynosi co najwyżej 2 GiB lub zasób ten jest nieograniczony.
- RLIMIT_CORE
- Maksymalny rozmiar pliku core (zob. core(5)) w bajtach, który może zrzucić proces. Wartość 0 oznacza, że pliki zrzutu nie są tworzone. Gdy wartość jest niezerowa, większe zrzuty są przycinane do wskazanego rozmiaru.
- RLIMIT_CPU
- Limit, w sekundach, czasu procesora (CPU), jaki może użyć proces. Gdy proces osiąga swoje ograniczenie miękkie, jest do niego wysyłany sygnał SIGXCPU. Domyślną reakcją na ten sygnał jest przerwanie procesu. Jednakże, sygnał może zostać przechwycony i procedura obsługi może przekazać sterowanie do programu głównego. Jeśli proces nadal będzie używać zasoby procesora, będzie do niego co sekundę wysyłany sygnał SIGXCPU aż do osiągnięcia ograniczenia sztywnego, kiedy to wysyłany jest sygnał SIGKILL. (Ostatni punkt opisuje zachowanie Linuksa. W zależności od implementacji procesy kontynuujące używanie zasobów procesora po osiągnięciu ograniczenia miękkiego są różnie traktowane. Aplikacje przenośne, które mają potrzebę przechwycenia tego sygnału, powinny zakończyć się w sposób kontrolowany w chwili otrzymaniu pierwszego SIGXCPU.)
- RLIMIT_DATA
- Maksymalny rozmiar segmentu danych procesu (dane zainicjowane, dane niezainicjowane i sterta). Limit jest podawany w bajtach i jest zaokrąglany w dół, do systemowego rozmiaru strony. Ograniczenie to wpływa na wywołania brk(2), sbrk(2) i (od Linuksa 4.7) mmap(2), które kończą się niepomyślnie, zgłaszając błąd ENOMEM w momencie natrafienia na miękkie ograniczenie tego zasobu.
- RLIMIT_FSIZE
- Maksymalny rozmiar plików w bajtach, jakie może utworzyć dany proces. Próba rozszerzenia pliku ponad to ograniczenie kończy się otrzymaniem sygnału SIGXFSZ. Domyślnie, sygnał ten kończy działanie procesu, ale proces może go przechwycić. Wówczas odpowiednia funkcja systemowa (np. write(2), truncate(2)) kończy się błędem EFBIG.
- RLIMIT_LOCKS (Linux 2.4.0 do Linuksa 2.4.24)
- Ograniczenie łącznej liczby blokad flock(2) i dzierżaw fcntl(2), które może ustanowić proces.
- RLIMIT_MEMLOCK
- Maksymalna liczba bajtów pamięci, które mogą być zablokowane w RAM. Limit jest w praktyce zaokrąglany w dół do najbliższej wielokrotności systemowego rozmiaru strony. Limit dotyczy mlock(2), mlockall(2) oraz operacji MAP_LOCKED mmap(2). Od Linuksa 2.6.9, limit dotyczy również operacji SHM_LOCK shmctl(2), gdzie ustawia maksymalną sumę bajtów segmentów pamięci dzielonej (zob. shmget(2)), które mogą być zablokowane przez rzeczywisty identyfikator użytkownika procesu wywołującego. Blokady SHM_LOCK shmctl(2) są liczone oddzielnie od blokad pamięci na proces, ustanowionych przez mlock(2), mlockall(2) i MAP_LOCKED mmap(2); proces może zablokować bajty do tego limitu w każdej z tych dwóch kategorii.
- Przed Linuksem 2.6.9, limit ten kontrolował wielkość pamięci, która mogła być zablokowana przez proces uprzywilejowany. Od Linuksa 2.6.9, na wielkość pamięci, jaka może być zablokowana przez proces uprzywilejowany nie są nakładane limity, a opisywany limit dotyczy w zamian procesów nieuprzywilejowanych.
- RLIMIT_MSGQUEUE (od Linuksa 2.6.8)
- Limit liczby bajtów, które mogą być przydzielone kolejkom komunikatów POSIX dla rzeczywistego identyfikatora użytkownika procesu wywołującego. Limit ten jest wymuszony na mq_open(3). Każda kolejka komunikatów, którą tworzy użytkownika wlicza się do tego limitu (do momentu jej usunięcia) zgodnie ze wzorem:
- Od Linuksa 3.5:
-
bytes = attr.mq_maxmsg * sizeof(struct msg_msg) + MIN(attr.mq_maxmsg, MQ_PRIO_MAX) * sizeof(struct posix_msg_tree_node)+ /* Do narzutu */ attr.mq_maxmsg * attr.mq_msgsize; /* Do danych komunikatów */
- Linux 3.4 i wcześniejsze:
-
bytes = attr.mq_maxmsg * sizeof(struct msg_msg *) + /* Do narzutu */ attr.mq_maxmsg * attr.mq_msgsize; /* Do danych komunikatów */
- gdzie attr jest strukturą mq_attr określoną jako czwarty argument do mq_open(3), a struktury msg_msg i posix_msg_tree_node są wewnętrznymi strukturami jądra.
- Składowa „narzutu” we wzorze bierze pod uwagę bajty narzutu wymagane przez implementację i zapewnia, że użytkownik nie może utworzyć nieskończonej liczby komunikatów o zerowej długości (takie komunikaty wciąż zajmują nieco pamięci systemowej ze względu na narzut księgowania).
- RLIMIT_NICE (od Linuksa 2.6.12, lecz zob. USTERKI poniżej)
- Określa górną granicę, do której można zwiększyć wartość nice procesu za pomocą setpriority(2) lub nice(2). Rzeczywista górna granica jest obliczana jako 20 - rlim_cur. Użyteczny zakres tego limitu wynosi zatem od 1 (co odpowiada wartości nice 19) do 40 (co odpowiada wartości nice -20). Ten nietypowy zakres był konieczny, ponieważ liczby ujemne nie mogą stanowić wartości limitów zasobów, gdyż zwykle mają specjalne znaczenie. Na przykład RLIM_INFINITY jest zwykle równoważne -1. Więcej szczegółów na temat wartości nice można znaleźć w podręczniku sched(7).
- RLIMIT_NOFILE
- Określa wartość o jeden większą niż maksymalna liczba deskryptorów plików, które dany proces może otworzyć. Próby (open(), pipe(), dup() itd.) przekroczenia tego limitu dają błąd EMFILE (historycznie limit ten nosił nazwę RLIMIT_OFILE na BSD).
- Od Linuksa 4.5, limit ten definiuje również maksymalną liczbę deskryptorów pliku, jakie proces nieuprzywilejowany (bez przywileju CAP_SYS_RESOURCE (ang. capability)) może mieć „w locie” do innych procesów, przy przekazywaniu za pomocą gniazd domeny Uniksa. Limit ten dotyczy wywołania systemowego sendmsg(2). Więcej szczegółów w podręczniku unix(7).
- RLIMIT_NPROC
- Limit liczby istniejących procesów (lub, precyzyjniej w Linuksie, wątków) dla rzeczywistego identyfikatora użytkownika procesu wywołującego. Jeśli liczba bieżących procesów, będących własnością rzeczywistego identyfikatora użytkownika tego procesu, jest większa lub równa limitowi, fork() zawiedzie z błędem EAGAIN.
- Limit RLIMIT_NPROC nie jest wymuszany na procesach z przywilejem CAP_SYS_ADMIN lub CAP_SYS_RESOURCE (ang. capability) i procesach z rzeczywistym identyfikatorem użytkownika równym 0.
- RLIMIT_RSS
- Limit (w bajtach) rezydentnych stron procesu (liczba stron pamięci wirtualnej pozostających w RAM). Ograniczenie to działa tylko w Linuksie 2.4.x, gdzie x < 30, i dotyczy jedynie wywołań madvise(2) z użyciem MADV_WILLNEED.
- RLIMIT_RTPRIO (od Linuksa 2.6.12, lecz zob. USTERKI)
- Górna granica, jaką można ustawić dla priorytetu czasu rzeczywistego, dla danego procesu, za pomocą sched_setscheduler(2) i sched_setparam(2).
- Więcej informacji o politykach szeregowania zadań czasu rzeczywistego opisano w podręczniku sched(7).
- RLIMIT_RTTIME (od Linuksa 2.6.25)
- Limit (w mikrosekundach) czasu procesora, jaki proces korzystający z szeregowania zadań czasu rzeczywistego może użyć, bez czynienia blokującego wywołania systemowego. Do celu tego limitu, za każdym razem, gdy proces tworzy blokujące wywołanie systemowe, licznik użytego czasu procesora jest resetowany do zera. Licznik czasu procesora nie jest resetowany, jeśli proces kontynuuje próbę użycia procesora, lecz jest wywłaszczony, przydzielona mu jednostka czasu wyczerpała się lub wywoła sched_yield(2).
- Po osiągnięciu limitu miękkiego, do procesu wysyłany jest sygnał SIGXCPU. Jeśli proces go przechwyci lub zignoruje i będzie kontynuował używanie czasu procesora, sygnał SIGXCPU będzie generowany co sekundę, do momentu osiągnięcia limitu sztywnego, gdy proces otrzyma sygnał SIGKILL.
- Limit ten ma na celu zapobiegnięcie zablokowania systemu przez zbiegłe procesy czasu rzeczywistego.
- Więcej informacji o politykach szeregowania zadań czasu rzeczywistego opisano w podręczniku sched(7).
- RLIMIT_SIGPENDING (od Linuksa 2.6.8)
- Limit liczby sygnałów, jakie mogą być zakolejkowane dla rzeczywistego identyfikatora użytkownika procesu wywołującego. Do celu sprawdzania tego limitu liczą się sygnały zwykłe i czasu rzeczywistego. Limit jest jednak wymuszany jedynie dla sigqueue(3); można zawsze skorzystać z kill(2), aby zakolejkować po jednym z każdego sygnału, który nie występuje w kolejce do procesu.
- RLIMIT_STACK
- Maksymalny rozmiar stosu procesu w bajtach. W chwili osiągnięcia tego ograniczenia, generowany jest sygnał SIGSEGV. W celu obsłużenia tego sygnału proces musi założyć alternatywny stos dla sygnałów (sigaltstack(2)).
- Od Linuksa 2.6.23, limit ten określa również wielkość przestrzeni używanej dla argumentów wiersza polecenia oraz zmiennych środowiskowych procesu; więcej szczegółów w podręczniku execve(2).
prlimit()
Typowo linuksowe wywołanie systemowe prlimit() łączy i rozszerza funkcjonalność setrlimit() i getrlimit(). Można go używać do ustawienia i pobrania limitów zasobów dowolnego procesu.
Argument resource ma takie samo znaczenie jak w przypadku setrlimit() i getrlimit().
Jeśli argument new_limit nie wynosi NULL, to struktura rlimit, na którą on wskazuje, jest używana do ustawienia nowych wartości limitów miękkich i sztywnych resource. Jeśli argument old_limit nie wynosi NULL, to pomyślne wywołanie prlimit() umieszcza poprzednie limity miękkie i sztywne resource w strukturze rlimit, na którą wskazuje old_limit.
Argument pid określa identyfikator procesu, na którym wywołanie ma operować. Jeśli pid wynosi 0, to wywołanie stosuje się do procesu wywołującego. Aby ustawić lub pobrać zasoby procesu innego niż własny, wywołujący musi mieć przywilej CAP_SYS_RESOURCE (ang. capability) w przestrzeni nazw użytkownika procesu, którego limity zasobów są zmieniane lub identyfikatory: rzeczywisty, efektywny i zapisany suid procesu docelowego muszą odpowiadać identyfikatorowi rzeczywistemu procesu wywołującego oraz identyfikatory: rzeczywisty, efektywny i zapisany suid procesu docelowego muszą odpowiadać rzeczywistemu identyfikatorowi grupy wywołującego.
WARTOŚĆ ZWRACANA
W przypadku powodzenia, te wywołania zwracają 0. W razie wystąpienia błędu zwracane jest -1 i ustawiane errno, wskazując błąd.
BŁĘDY
- EFAULT
- Argument wskaźnika wskazuje na położenie poza dostępną przestrzeń adresową.
- EINVAL
- WArtość określona w resource nie jest prawidłowa; albo — w przypadku setrlimit() lub prlimit(): rlim->rlim_cur był większy niż rlim->rlim_max.
- EPERM
- Proces nieuprzywilejowany próbował zwiększyć limit sztywny; do dokonania tego konieczny jest przywilej CAP_SYS_RESOURCE (ang. capability).
- EPERM
- Wywołujący próbował zwiększyć limit sztywny RLIMIT_NOFILE ponad wartość maksymalną określoną w /proc/sys/fs/nr_open (zob. proc(5))
- EPERM
- (prlimit()) Proces wywołujący nie miał uprawnień do ustawiania limitów dla procesu podanego w pid.
- ESRCH
- Nie udało się znaleźć procesu o identyfikatorze podanym w pid.
ATRYBUTY
Informacje o pojęciach używanych w tym rozdziale można znaleźć w podręczniku attributes(7).
Interfejs | Atrybut | Wartość |
getrlimit(), setrlimit(), prlimit() | Bezpieczeństwo wątkowe | MT-bezpieczne |
STANDARDY
- getrlimit()
- setrlimit()
- POSIX.1-2008.
- prlimit()
- Linux.
RLIMIT_MEMLOCK i RLIMIT_NPROC pochodzą z BSD i nie są określone w POSIX.1; są obecne w systemach BSD i Linux, ale z różnymi implementacjami. RLIMIT_RSS pochodzi z BSD i nie jest określone w POSIX.1; jest jednak obecne w większości implementacji. RLIMIT_MSGQUEUE, RLIMIT_NICE, RLIMIT_RTPRIO, RLIMIT_RTTIME i RLIMIT_SIGPENDING są typowo linuksowe.
HISTORIA
- getrlimit()
- setrlimit()
- POSIX.1-2001, SVr4, 4.3BSD.
- prlimit()
- Linux 2.6.36, glibc 2.13.
UWAGI
Proces potomny utworzony za pomocą fork(2) dziedziczy limity zasobów swojego procesu macierzystego. Limity zasobów są zachowywane przez execve(2).
Limity zasobów są atrybutami przypisanymi procesowi i są dzielone przez wszystkie wątki procesu.
Zmniejszenie miękkiego limitu zasobu poniżej jego aktualnego użycia przez proces powiedzie się (lecz zapobiegnie dalszemu zwiększeniu użycia zasobu przez proces).
Można ustawić limity zasobów powłoki za pomocą wbudowanego polecenia ulimit (limit w csh(1)). Limity zasobów powłoki są dziedziczone przez procesy tworzone do wykonywania poleceń powłoki.
Od Linuksa 2.6.24, limity zasobów dowolnego procesu można sprawdzić za pomocą /proc/pid/limits; zob. proc(5).
Dawne systemy udostępniały funkcję vlimit() o podobnym zastosowaniu do setrlimit(). Ze względu na kompatybilność wsteczną, glibc również udostępnia vlimit(). Wszystkie nowe aplikacje powinny używać wyłącznie setrlimit().
Różnice ABI biblioteki C/jądra
Od glibc 2.13, funkcje opakowujące getrlimit() i setrlimit() z glibc nie przywołują już odpowiadających im wywołań systemowych, lecz używają prlimit(), ze względów opisanych w USTERKACH.
Nazwą opakowującej funkcji z glibc jest prlimit(); nazwą wywołania systemowego jest prlimit64().
USTERKI
W starszych jądrach Linux, sygnały SIGXCPU i SIGKILL dostarczane, gdy proces napotkał miękkie i sztywne limity RLIMIT_CPU, dostarczano jedną sekundę (procesorową) później, niż powinno to nastąpić. Poprawiono to w Linuksie 2.6.8.
W jądrach Linux 2.6.x wcześniejszych niż Linux 2.6.17, limit RLIMIT_CPU wynoszący 0 był nieprawidłowo traktowany jako „brak limitu” (jak RLIM_INFINITY). Od Linuksa 2.6.17, ustawienie limitu 0 jest stosowane, ale faktycznie skutkuje limitem 1 sekundy.
Błąd jądra powodował, że RLIMIT_RTPRIO nie działał w Linuksie 2.6.12; problem poprawiono w Linuksie 2.6.13.
W Linuksie 2.6.12, istniała niezgodność o jeden pomiędzy zakresami priorytetów zwracanymi przez getpriority(2) i RLIMIT_NICE. Dawało te efekt, że faktyczna górna granica wartości nice była obliczana jako 19 - rlim_cur. Poprawiono to w Linuksie 2.6.13.
Od Linuksa 2.6.12, jeśli proces osiąga swój miękki limit RLIMIT_CPU i posiada procedurę obsługi SIGXCPU, to, oprócz przywołania procedury obsługi, jądro zwiększa miękki limit o jedną sekundę. Zachowanie to powtarza się, jeśli proces kontynuuje używanie czasu procesora, aż do osiągnięcia limitu sztywnego, gdy proces jest zabijany. Inne implementacje nie zmieniają miękkiego limitu RLIMIT_CPU w ten sposób, a zachowanie Linuksa prawdopodobnie nie jest zgodne ze standardami; przenośne aplikacje powinny unikać polegania na tym typowo linuksowym zachowaniu. Typowo linuksowy limit RLIMIT_RTTIME działa w ten sam sposób, gdy osiągnie się miękki limit.
Jądra przed Linuksem 2.4.22 nie diagnozują błędu EINVAL w przypadku setrlimit(), gdy rlim->rlim_cur było większe niż rlim->rlim_max.
Ze względu na kompatybilność, Linux nie zwraca błędu, gdy próba ustawienia RLIMIT_CPU zawodzi.
Reprezentacja „dużych” wartości limitu zasobu na platformach 32-bitowych
Funkcje opakowujące getrlimit() i setrlimit() z glibc używają 64-bitowego typu danych rlim_t, nawet na platformach 32-bitowych. Jednakże typ danych rlim_t używany w wywołaniach systemowych getrlimit() i setrlimit() jest (32-bitowym) unsigned long. Co więcej, w Linuksie jądro reprezentuje limit zasobów na platformach 32-bitowych jako unsigned long. Jednak 32-bitowy typ danych nie jest wystarczająco szeroki. Najtrudniejsza sytuacja występuje odnośnie limitu RLIMIT_FSIZE określającego maksymalny rozmiar, do jakiego może zostać zwiększony plik: aby być użytecznym, limit ten musi być reprezentowany przez typ, który jest tak szeroki, jak typ używany do reprezentowania przesunięć pliku tj. tak szeroki jak 64-bitowe off_t (zakładając, że program skompilowano z _FILE_OFFSET_BITS=64).
Aby obejść to ograniczenie, w przypadku gdy program próbował ustawić limit zasobów na wartość większą niż może być reprezentowana w 32-bitowym unsigned long, funkcja opakowująca setrlimit() z glibc po cichu konwertowała wartość limitu na RLIM_INFINITY. Innymi słowy, żądany limit zasobów był po cichu ignorowany.
OD glibc 2.13, glibc obchodzi to ograniczenie wywołań systemowych getrlimit() i setrlimit() implementując setrlimit() i getrlimit() jako funkcje opakowujące wywołujące prlimit().
PRZYKŁADY
Poniższy program demonstruje użycie prlimit().
#define _GNU_SOURCE #define _FILE_OFFSET_BITS 64 #include <err.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <sys/resource.h> #include <time.h> int main(int argc, char *argv[]) { pid_t pid; struct rlimit old, new; struct rlimit *newp; if (!(argc == 2 || argc == 4)) { fprintf(stderr, "Usage: %s <pid> [<new-soft-limit> " "<new-hard-limit>]\n", argv[0]); exit(EXIT_FAILURE); } pid = atoi(argv[1]); /* PID of target process */ newp = NULL; if (argc == 4) { new.rlim_cur = atoi(argv[2]); new.rlim_max = atoi(argv[3]); newp = &new; } /* Set CPU time limit of target process; retrieve and display previous limit */ if (prlimit(pid, RLIMIT_CPU, newp, &old) == -1) err(EXIT_FAILURE, "prlimit-1"); printf("Previous limits: soft=%jd; hard=%jd\n", (intmax_t) old.rlim_cur, (intmax_t) old.rlim_max); /* Retrieve and display new CPU time limit */ if (prlimit(pid, RLIMIT_CPU, NULL, &old) == -1) err(EXIT_FAILURE, "prlimit-2"); printf("New limits: soft=%jd; hard=%jd\n", (intmax_t) old.rlim_cur, (intmax_t) old.rlim_max); exit(EXIT_SUCCESS); }
ZOBACZ TAKŻE
prlimit(1), dup(2), fcntl(2), fork(2), getrusage(2), mlock(2), mmap(2), open(2), quotactl(2), sbrk(2), shmctl(2), malloc(3), sigqueue(3), ulimit(3), core(5), capabilities(7), cgroups(7), credentials(7), signal(7)
TŁUMACZENIE
Autorami polskiego tłumaczenia niniejszej strony podręcznika są: Przemek Borys <pborys@dione.ids.pl>, Andrzej Krzysztofowicz <ankry@green.mf.pg.gda.pl> i 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.
17 czerwca 2024 r. | Linux man-pages 6.9.1 |