| getrlimit(2) | System Calls Manual | getrlimit(2) |
getrlimit, setrlimit, prlimit - pobiera/ustawia limity zasobów
Standardowa biblioteka C (libc, -lc)
#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; /* ograniczenie miękkie */
rlim_t rlim_max; /* ogr. sztywne (górna granica rlim_cur) */
};
typedef /* ... */ rlim_t; /* Typ: liczba całkowita bez znaku */
prlimit():
_GNU_SOURCE
Wywołania systemowe getrlimit() i setrlimit() pobierają i ustawiają limity zasobów. Z każdym z zasobów stowarzyszone jest miękkie i sztywne ograniczenie zdefiniowane w strukturze rlimit.
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:
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 */
bytes = attr.mq_maxmsg * sizeof(struct msg_msg *) +
/* Do narzutu */
attr.mq_maxmsg * attr.mq_msgsize;
/* Do danych komunikatów */
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.
W przypadku powodzenia, te wywołania zwracają 0. W razie wystąpienia błędu zwracane jest -1 i ustawiane errno, wskazując błąd.
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 |
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.
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().
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().
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.
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().
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, "Użycie: %s <pid> [<nowy-limit-miękki> "
"<nowy-limit-sztywny>]\n", argv[0]);
exit(EXIT_FAILURE);
}
pid = atoi(argv[1]); /* PID procesu docelowego */
newp = NULL;
if (argc == 4) {
new.rlim_cur = atoi(argv[2]);
new.rlim_max = atoi(argv[3]);
newp = &new;
}
/* Ustawia limit czasu procesora procesu docelowego; pobiera
i wyświetla poprzedni limit */
if (prlimit(pid, RLIMIT_CPU, newp, &old) == -1)
err(EXIT_FAILURE, "prlimit-1");
printf("Poprzednie limity: miękki=%jd; sztywny=%jd\n",
(intmax_t) old.rlim_cur, (intmax_t) old.rlim_max);
/* Pobiera i wyświetla nowy limit czasu procesora */
if (prlimit(pid, RLIMIT_CPU, NULL, &old) == -1)
err(EXIT_FAILURE, "prlimit-2");
printf("Nowe limity: miękki=%jd; sztywny=%jd\n",
(intmax_t) old.rlim_cur, (intmax_t) old.rlim_max);
exit(EXIT_SUCCESS);
}
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 niniejszej strony podręcznika: 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 |