GETRLIMIT(2) | Руководство программиста Linux | GETRLIMIT(2) |
getrlimit, setrlimit, prlimit - считывает/устанавливает ограничения использования ресурсов
#include <sys/time.h> #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 *new_limit, struct rlimit *old_limit);
Требования макроса тестирования свойств для glibc (см. feature_test_macros(7)):
prlimit(): _GNU_SOURCE
Системные вызовы getrlimit() и setrlimit() получают и устанавливают ограничения использования ресурсов. Каждому ресурсу назначается мягкое и жёсткое ограничение, определяемое структурой rlimit:
struct rlimit { rlim_t rlim_cur; /* мягкое ограничение */ rlim_t rlim_max; /* жёсткое ограничение (максимум для rlim_cur) */ };
Мягким ограничением является значение, принудительно устанавливаемое ядром для соответствующего ресурса. Жёсткое ограничение работает как максимальное значение для мягкого ограничения: непривилегированные процессы могут определять только свои мягкие ограничения в диапазоне от 0 до жёсткого ограничения, то есть однозначно меньше жёсткого ограничения. Привилегированные процессы (в Linux: имеющие мандат CAP_SYS_RESOURCE в начальном пространстве имён пользователя) могут устанавливать произвольные значения в любых пределах.
Значение RLIM_INFINITY означает отсутствие ограничений для ресурса (в структуре, возвращаемой getrlimit() и в структуре, передаваемой в setrlimit()).
Значение resource должно быть одним из:
bytes = attr.mq_maxmsg * sizeof(struct msg_msg) + min(attr.mq_maxmsg, MQ_PRIO_MAX) * sizeof(struct posix_msg_tree_node)+ /* издержки */ attr.mq_maxmsg * attr.mq_msgsize; /* данные из сообщения */
bytes = attr.mq_maxmsg * sizeof(struct msg_msg *) + /* издержки */ attr.mq_maxmsg * attr.mq_msgsize; /* данные из сообщения */
Системный вызов prlimit(), который есть только в Linux объединяет и расширяет функции setrlimit() и getrlimit(). Он может использоваться для задания и получения ограничений ресурсов произвольного процесса.
Аргумент resource имеет тот же смысл что и в setrlimit() и getrlimit().
Если значение аргумента new_limit не равно NULL, то структура rlimit, на которую он указывает, используется для задания новых значений мягкий и жёстких ограничений для resource. Если значение аргумента old_limit не равно NULL, то успешный вызов prlimit() помещает текущие значения мягких и жёстких ограничений для resource в структуру rlimit, на которую указывает old_limit.
В аргументе pid задаётся идентификатор процесса с которым работает вызов. Если pid равно 0, то вызов применяется к вызывающему процессу. Для установки и получения ресурсов не своего процесса, вызывающий должен иметь мандат CAP_SYS_RESOURCE в пользовательском пространстве имён процесса, ограничения ресурсов которого изменяются или реальный, эффективный и сохранённый идентификатор пользователя процесса назначения должен совпадать с реальным идентификатором пользователя вызывающего и реальный, эффективный и сохранённый идентификатор группы процесса назначения должны совпадать с реальным идентификатором группы вызывающего.
При успешном выполнении возвращается 0. В случае ошибки возвращается -1, а errno устанавливается в соответствующее значение.
Системный вызов prlimit() появился в Linux 2.6.36. Поддержка в glibc доступна начиная с версии 2.13.
Описание терминов данного раздела смотрите в attributes(7).
Интерфейс | Атрибут | Значение |
getrlimit(), setrlimit(), prlimit() | Безвредность в нитях | MT-Safe |
getrlimit(), setrlimit(): POSIX.1-2001, POSIX.1-2008, SVr4, 4.3BSD.
prlimit(): только в Linux.
Ограничение RLIMIT_MEMLOCK и RLIMIT_NPROC появились из BSD и их нет в POSIX.1; они есть в BSD и Linux, но реализации несколько различны. Ограничение RLIMIT_RSS появилось из BSD и его нет в POSIX.1; тем не менее оно есть в большинстве реализаций. Ограничения RLIMIT_MSGQUEUE, RLIMIT_NICE, RLIMIT_RTPRIO, RLIMIT_RTTIME и RLIMIT_SIGPENDING есть только в Linux.
Дочерний процесс, созданный fork(2), наследует ограничения ресурсов родителя. Ограничения ресурсов сохраняются при execve(2).
Атрибуты ограничения ресурсов есть у каждого процесса, они являются общими для всех нитей процесса.
Уменьшение мягкого ограничения ресурса ниже текущего потребления процесса будет выполнено (но в дальнейшем процесс не сможет увеличить потребление ресурса).
Ограничения ресурсов интерпретатора командной строки можно устанавливать с помощью встроенной команды ulimit (limit в csh(1)). Ограничения ресурсов интерпретатора наследуются дочерними процессами, которые он создаёт при выполнении команд.
Начиная с Linux 2.6.24, ограничения ресурсов любого процесса можно узнать с помощью /proc/[pid]/limits; смотрите proc(5).
В старых системах была функция vlimit() с подобным setrlimit() назначением. Для обратной совместимости в glibc также есть функция vlimit(). Во всех новых приложениях должен быть использован setrlimit().
Начиная с версии 2.13, обёрточные функции glibc getrlimit() и setrlimit() больше не вызывают соответствующие системные вызовы, вместо этого вызывается prlimit() по причинам, описанным в разделе ДЕФЕКТЫ.
Обёрточная функция в glibc называется prlimit(); нижележащий системный вызов называется prlimit64().
В старых ядрах Linux сигналы SIGXCPU и SIGKILL, посылаемые когда у процесса обнаруживается достижение мягкого и жёсткого ограничения RLIMIT_CPU, доставляются на одну секунду (ЦП) позднее чем это должно быть. Это исправлено в ядре версии 2.6.8.
В ядрах 2.6.x до версии 2.6.17, ограничение RLIMIT_CPU равное 0, неправильно воспринималось как «без ограничения» (подобно RLIM_INFINITY). Начиная с Linux 2.6.17, установка ограничения в 0 действует, но реально обрабатывается как ограничение в 1 секунду.
Из-за дефекта ядра RLIMIT_RTPRIO не работает в версии 2.6.12; это исправлено в ядре 2.6.13.
В ядре 2.6.12 было несоответствие в единицу между диапазонами приоритетов, возвращаемых getpriority(2) и RLIMIT_NICE. Это приводило к тому, что реальный максимум значения nice вычислялся как 19 - rlim_cur. Исправлено в ядре 2.6.13.
Начиная с Linux 2.6.12, если процесс имеет мягкое ограничение RLIMIT_CPU и установлен обработчик для SIGXCPU, то, помимо вызова обработчика сигнала, ядро увеличивает мягкое ограничение на одну секунду. Такое поведение повторяется, если процесс продолжает потреблять процессорное время, и происходит это до тех пор, пока не будет достигнуто жёсткое ограничение, после чего процесс будет завершён. В других реализациях мягкое ограничение RLIMIT_CPU не меняется подобным образом, и поведение Linux, вероятно, нестандартно; переносимые приложения не должны полагаться на данную специфику Linux. Ограничение Linux RLIMIT_RTTIME демонстрирует такое же поведение, при исчерпании мягкого ограничения.
В ядрах до 2.4.22 не определялась ошибка EINVAL в setrlimit(), если значение rlim->rlim_cur было больше rlim->rlim_max.
В целях совместимости, Linux не возвращает ошибку при неудачной попытке назначения RLIMIT_CPU.
В обёрточных функциях glibc getrlimit() и setrlimit() используется 64-битный тип данных rlim_t, даже на 32-битных платформах. Однако в системных вызовах getrlimit() и setrlimit() тип данных rlim_t приводится к unsigned long (32-битному). Кроме этого, в ядре Linux ограничители ресурсов на 32-битных платформах представлены типом unsigned long. Однако 32-битный тип данных недостаточно велик. Для этого больше подходит RLIMIT_FSIZE, который определяет максимальный размер на который можно увеличить файл; чтобы его можно было использовать, данное ограничение должно быть представлено типом, соразмерным с типом, используемым для представления файловых смещений — 64-битным off_t (предполагается, что программа компилируется в параметром _FILE_OFFSET_BITS=64).
Если программа пытается задать ограничение ресурса значением, большим чем можно представить 32-битным unsigned long, то, чтобы обойти это ограничение ядра, обёрточная функция glibc setrlimit() просто преобразует значение ограничения в RLIM_INFINITY. Иначе говоря, запрашиваемое назначение ограничения ресурса просто игнорируется.
Начиная с версии 2.13, в glibc для обхода ограничений системных вызовов getrlimit() и setrlimit() для реализации обёрточных функций setrlimit() и getrlimit() используется вызов prlimit().
Представленная ниже программа показывает использование prlimit().
#define _GNU_SOURCE #define _FILE_OFFSET_BITS 64 #include <stdio.h> #include <time.h> #include <stdlib.h> #include <unistd.h> #include <sys/resource.h> #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) int main(int argc, char *argv[]) { struct rlimit old, new; struct rlimit *newp; pid_t pid; if (!(argc == 2 || argc == 4)) { fprintf(stderr, "Использование: %s <pid> [<новое-мягкое-ограничение> " "<новое-жёсткое-ограничение>]\n", argv[0]); exit(EXIT_FAILURE); } pid = atoi(argv[1]); /* PID процесса назначения */ newp = NULL; if (argc == 4) { new.rlim_cur = atoi(argv[2]); new.rlim_max = atoi(argv[3]); newp = &new; } /* Установить ограничение на время ЦП процесса назначения; получить и показать предыдущее ограничение */ if (prlimit(pid, RLIMIT_CPU, newp, &old) == -1) errExit("prlimit-1"); printf("Previous limits: soft=%lld; hard=%lld\n", (long long) old.rlim_cur, (long long) old.rlim_max); /* Получить и показать новое ограничение времени ЦП */ if (prlimit(pid, RLIMIT_CPU, NULL, &old) == -1) errExit("prlimit-2"); printf("Новые ограничения: мягкое=%lld; жёсткое=%lld\n", (long long) old.rlim_cur, (long long) 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)
2018-04-30 | Linux |