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