Other Alias
getrlimit, setrlimitОБЗОР
#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 должно быть одним из:
- RLIMIT_AS
- Максимальный размер виртуальной памяти (адресного пространства) процесса в байтах. Учитывается в вызовах brk(2), mmap(2) и mremap(2), которые завершатся с ошибкой ENOMEM, если будет превышено это ограничение. Также завершится с ошибкой автоматическое расширение стека (и будет сгенерирован сигнал SIGSEGV, по которому завершится процесс, если не было создано с помощью sigaltstack(2) альтернативного стека). Так как значение имеет тип long, на машинах с 32-битным long максимальное значение ограничения будет около 2 ГиБ, или этот ресурс не ограничивается.
- RLIMIT_CORE
- Максимальный размер файла core (смотрите core(5)). Если значение равно 0, то файлы core не создаются. Если значение больше нуля, то создаваемые дампы обрезаются до этого размера.
- RLIMIT_CPU
- Время выполнения на ЦП в секундах. Когда процесс достигает своего мягкого ограничения, то ему отправляется сигнал SIGX CPU. Действием по умолчанию для этого сигнала является завершение процесса. Однако, этот сигнал может быть перехвачен, и обработчик может передать управление в основную программу. Если процесс продолжает потреблять процессорное время, то ему будет отправляться SIGXCPU раз в секунду до тех пор, пока не будет достигнуто жёсткое ограничение, и тогда процессу будет послан сигнал SIGKILL. (Последний пункт описывает поведение Linux. В разных реализациях действия над потребляющими процессорное время после прохождения мягкого ограничения процессами различаются. Переносимые приложения, где требуется перехват сигнала, должны выполнять корректное завершение процесса после первого получения SIGXCPU.)
- RLIMIT_DATA
- Максимальный размер сегмента данных процесса (инициализированные данные, неинициализированные данные, куча). Это ограничение учитывается в вызовах brk(2) и sbrk(2), которые завершатся с ошибкой ENOMEM при достижении мягкого ограничения этого ресурса.
- RLIMIT_FSIZE
- Максимальный размер файлов, создаваемых процессом. Попытки расширить файл сверх этого ограничения приведёт к доставке сигнала SIGXFSZ. По умолчанию по этому сигналу процесс завершается, но процесс может перехватить этот сигнал и в этом случае выполнявшийся системный вызов (например, write(2), truncate(2)) завершится с ошибкой EFBIG.
- RLIMIT_LOCKS (только в ранних версиях Linux 2.4)
- Ограничение на общее количество блокировок flock(2) и аренд fcntl(2), которое может установить процесс.
- RLIMIT_MEMLOCK
- Максимальное количество байт памяти, которое может быть заблокировано в ОЗУ. В целях эффективности это ограничение округляется в меньшую сторону до ближайшего значения, кратного размеру системной страницы. Это ограничение учитывается в mlock(2) и mlockall(2) и в mmap(2) при операции MAP_LOCKED. Начиная с Linux 2.6.9, оно также учитывается в shmctl(2) при операции SHM_LOCK, где определяет максимальное количество байт всех общих сегментов памяти (см. shmget(2)), которые могут быть заблокированы вызывающим процессом с реальным идентификатором пользователя. Блокировки по операции SHM_LOCK у shmctl(2) учитываются отдельно от попроцессных блокировок памяти, устанавливаемых mlock(2), mlockall(2) и mmap(2) операцией MAP_LOCKED; процесс может заблокировать пространство до этого значения заданного ограничения байт в каждой из этих двух категорий. В ядрах Linux до версии 2.6.9 этим ограничением контролировалось количество памяти, которое можно было блокировать привилегированному процессу. Начиная с Linux 2.6.9 это ограничение снято и теперь это ограничение управляет количеством памяти, которое может блокировать непривилегированный процесс.
- RLIMIT_MSGQUEUE (начиная с Linux 2.6.8)
-
Ограничение на количество байт, которое может выделяться для очередей
сообщений POSIX для вызывающего процесса с реальным идентификатором
пользователя. Это ограничение учитывается в mq_open(3). Каждая очередь
сообщений, которую создаёт пользователь, учитывается (пока не будет удалена)
в формуле:
Начиная с Linux 3.5: 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; /* данные из сообщения */ Linux 3.4 и старее: bytes = attr.mq_maxmsg * sizeof(struct msg_msg *) + /* издержки */ attr.mq_maxmsg * attr.mq_msgsize; /* данные из сообщения */
где attr — структура mq_attr, указанная в четвёртом аргументе mq_open(3), а msg_msg и posix_msg_tree_node — внутренние структуры ядра.Дополнение «издержки» (overhead) в формуле нужно учитывает байты расходов требуемые в реализации на то, чтобы пользователь не смог создать бесконечное количество сообщений нулевой длины (для таких сообщений, тем не менее, потребляется системная память для учёта использования системных ресурсов).
- RLIMIT_NICE (начиная с Linux 2.6.12, см. ДЕФЕКТЫ далее)
- Определяет максимум, до которого может быть увеличено значение nice с помощью setpriority(2) или nice(2). Действительный максимум значения nice высчитывается по формуле: 20 - rlim_cur. (Так пришлось поступить из-за того, что отрицательные числа нельзя указывать в значениях ограничений ресурсов, так как они, обычно, имеют специальное предназначение. Например, RLIM_INFINITY, обычно равно -1.)
- RLIMIT_NOFILE
- Определяет значение, на 1 больше максимального количества дескрипторов файлов, которое может открыть этот процесс. Попытки (open(2), pipe(2), dup(2) и т.п.) превысить это ограничение приведут к ошибке EMFILE. (Раньше это ограничение в BSD называлось RLIMIT_OFILE.)
- RLIMIT_NPROC
- Максимальное количество процессов (или, более точно для Linux, нитей), которое может создать вызывающий процесс с реальным идентификатором пользователя. При превышении этого ограничения fork(2) завершается с ошибкой EAGAIN. Данное ограничение не действует на процессы с мандатом CAP_SYS_ADMIN или CAP_SYS_RESOURCE.
- RLIMIT_RSS
- Максимальное ограничение (в байтах) размера постоянного присутствия процесса (числа виртуальных страниц, постоянно присутствующих в ОЗУ). Это ограничение учитывается только начиная с версии Linux 2.4.x, x < 30, и только в вызовах madvise(2) со значением MADV_WILLNEED.
- RLIMIT_RTPRIO (начиная с Linux 2.6.12, смотрите ДЕФЕКТЫ)
- Определяет максимум для приоритета реального времени, который можно установить для процесса с помощью sched_setscheduler(2) и sched_setparam(2).
- RLIMIT_RTTIME (начиная с Linux 2.6.25)
-
Определяет ограничение (в микросекундах) на количество времени ЦП, которое
процесс может быть запланирован выполняться в условиях реального времени без
выполнения блокирующего системного вызова. Для работы ограничения, всякий
раз когда процесс делает блокирующий системный вызов счётчик использованного
времени ЦП сбрасывается в ноль. Счётчик времени ЦП не сбрасывается, если
процесс продолжает пытаться использовать ЦП, но был вытеснен, его выделенное
время на исполнение истекло или он вызвал sched_yield(2).
При достижении мягкого ограничения процессу посылается сигнал SIGXCPU. Если процесс перехватил сигнал, проигнорировал его и продолжает потреблять время ЦП, то раз в секунду будет генерироваться сигнал SIGXCPU до тех пор, пока не будет достигнуто жёсткое ограничение, и процессу не будет послан сигнал SIGKILL.
Это ограничение предназначено для предотвращения блокировки системы вышедшими из под контроля процессами реального времени.
- RLIMIT_SIGPENDING (начиная с Linux 2.6.8)
- Определяет ограничение на количество сигналов, которые могут быть поставлены в очередь вызывающего процесса с реальным пользовательским идентификатором. При проверке ограничения учитываются обычные сигналы и сигналы реального времени. Однако ограничение учитывается только в sigqueue(3); всегда возможно использовать kill(2) для постановки в очередь любого сигнала, которого ещё нет в очереди процесса.
- RLIMIT_STACK
-
Максимальный размер стека процесса в байтах. При достижении этого
ограничения генерируется сигнал SIGSEGV. Для обработки этого сигнала
процесс должен использовать альтернативный стек сигналов
(sigaltstack(2)).
Начиная с Linux 2.6.23, это ограничение также определяет количество места, используемого для аргументов командной строки процесса и его переменных окружения; подробней об этом смотрите в execve(2).
prlimit()
Системный вызов 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 устанавливается в соответствующее значение.ОШИБКИ
- EFAULT
- Аргумент-указатель указывает за пределы доступного адресного пространства.
- EINVAL
- Указано некорректное значение resource; или для setrlimit() или prlimit(): rlim->rlim_cur больше чем rlim->rlim_max.
- EPERM
- Непривилегированный процесс пытался увеличить жёсткое ограничение; для этого требуется мандат CAP_SYS_RESOURCE.
- EPERM
- Вызывающий пытался увеличить жёсткое ограничение RLIMIT_NOFILE, превышая максимум, заданный в /proc/sys/fs/nr_open (смотрите proc(5)).
- EPERM
- Вызывающий процесс не имеет прав для назначения ограничений процессу, указанному в pid.
- ESRCH
- Не удалось найти процесс с идентификатором, указанном в pid.
ВЕРСИИ
Системный вызов 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().
Отличия между библиотекой C и ABI ядра
Начиная с версии 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.
Представление «больших» значений ограничений ресурсов на 32-битных платформах
В обёрточных функциях glibc getrlimit() и setrlimit() используется 64-битный тип данных rlim_t, даже на 32-битных платформах. Однако в системных вызовах getrlimit() и setrlimit() тип данных rlim_t приводится к unsigned long (32-битному). Кроме этого, в ядрах Linux версии до 2.6.36 ограничители ресурсов на 32-битных платформах представлялись как unsigned long. Однако 32-битный тип данных недостаточно велик. Для этого больше подходит RLIMIT_FSIZE, который определяет максимальный размер на который можно увеличить файл; чтобы его можно было использовать, данное ограничение должно быть представлено типом, соразмерным с типом, используемым для представления файловых смещений — 64-битным off_t (предполагается, что программа компилируется в параметром _FILE_OFFSET_BITS=64).Если программа пытается задать ограничение ресурса значением, большим чем можно представить 32-битным unsigned long, то, чтобы обойти это ограничение ядра, обёрточная функция glibc setrlimit() просто преобразует значение ограничения в RLIM_INFINITY. Иначе говоря, запрашиваемое назначение ограничения ресурса просто игнорируется.
Данная проблема касается Linux 2.6.36 с двумя принципиальными отличиями:
- *
- добавлено новое представление ограничений ресурсов в ядре — 64 бита используется даже на 32-битных платформах;
- *
- добавлен системный вызов prlimit(), в котором для аргументов ограничений ресурсов используются 64-битные значения.
Начиная с версии 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_FAILURE); }