printf("unrepresentable");
#endif
else
printf("%lld", (long long) rlim.rlim_cur);
printf("; hard=");
if (rlim.rlim_max == RLIM_INFINITY)
printf("infinite\n");
#ifdef RLIM_SAVED_MAX /* Не определено в некоторых системах */
else if (rlim.rlim_max == RLIM_SAVED_MAX)
printf("unrepresentable");
#endif
else
printf("%lld\n", (long long) rlim.rlim_max);
return 0;
}
procres/print_rlimit.c
Листинг 36.3. Установление ограничения RLIMIT_NPROC
procres/rlimit_nproc.c
#include
#include "print_rlimit.h" /* Объявление функции printRlimit() */
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
struct rlimit rl;
int j;
pid_t childPid;
if (argc < 2 || argc > 3 || strcmp(argv[1], "-help") == 0)
usageErr("%s soft-limit [hard-limit]\n", argv[0]);
printRlimit("Initial maximum process limits: ", RLIMIT_NPROC);
/* Устанавливаем новые ограничения для процесса (по умолчанию
жесткое и мягкое совпадают) */
rl.rlim_cur = (argv[1][0] == 'i')? RLIM_INFINITY:
getInt(argv[1], 0, "soft-limit");
rl.rlim_max = (argc == 2)? rl.rlim_cur:
(argv[2][0] == 'i')? RLIM_INFINITY:
getInt(argv[2], 0, "hard-limit");
if (setrlimit(RLIMIT_NPROC, &rl) == –1)
errExit("setrlimit");
printRlimit("New maximum process limits: ", RLIMIT_NPROC);
/* Создаем как можно больше дочерних процессов */
for (j = 1;; j++) {
switch (childPid = fork()) {
case –1: errExit("fork");
case 0: _exit(EXIT_SUCCESS); /* Потомок */
default: /* Родитель выводит сообщение о каждом новом потомке
и позволяет учитывать процессы-"зомби" */
printf("Child %d (PID=%ld) started\n", j, (long) childPid);
break;
}
}
}
procres/rlimit_nproc.c
В некоторых средах программирования типа данных rlim_t может быть недостаточно для представления всего диапазона значений, предусмотренных для определенного ограничения на ресурсы. Это случается в системах, которые предоставляют несколько сред программирования с разными размерами типа rlim_t. Эта проблема обычно возникает, когда среда компиляции с поддержкой больших файлов, в которой структура off_t занимает 64 бита, интегрируется в систему, где значения off_t традиционно 32-битные (в обеих средах размеры rlim_t и off_t совпадают). Это приводит к ситуации, когда процесс с 32-битным типом данных rlim_t, если он запущен программой с 64-битной структурой off_t, может наследовать ограничение на ресурсы (например, ограничение на размер файла), которое превышает максимальное значение rlim_t.
Чтобы помочь переносимым приложениям справляться со случаями, когда ограничение на ресурсы выходит за пределы допустимого диапазона, стандарт SUSv3 предоставляет две константы, обозначающие значения ограничений, которые не могут быть представлены: RLIM_SAVED_CUR и RLIM_SAVED_MAX. Если мягкое ограничение нельзя представить с помощью типа данных rlim_t, вызов getrlimit() возвращает в поле rlim_cur значение RLIM_SAVED_CUR. Точно так же константа RLIM_SAVED_MAX используется для жесткого ограничения, возвращаемого в поле rlim_max.
Если тип rlim_t позволяет представить все возможные значения ограничения на ресурсы, то стандарт SUSv3 разрешает объявить константы RLIM_SAVED_CUR и RLIM_SAVED_MAX равными RLIM_INFINITY. Именно так сделано в Linux; это подразумевает, что rlim_t может вместить любые значения ограничений. Однако это не относится к 32-битным архитектурам, таким как x86-32. В таких системах в среде компиляции больших файлов (то есть когда макросу _FILE_OFFSET_BITS, который проверяет наличие тех или иных возможностей, присваивается значение 64, как описано в разделе 5.10) библиотека glibc содержит 64-битную структуру rlim_t, однако в ядре для представления ограничений на ресурсы используется тип unsigned long, размер которого равен 32 битам. Современные версии glibc решают эту проблему следующим образом: если программа, скомпилированная с макросом _FILE_OFFSET_BITS=64, пытается установить ограничение на ресурсы, которое не вмещается в 32-битный тип unsigned long, тогда обертка для вызова setrlimit() из состава glibc автоматически меняет это значение на RLIM_INFINITY. Иными словами, запрашиваемое ограничение на ресурсы не устанавливается.
Во многих дистрибутивах с архитектурой x86-32 утилиты для работы с файлами обычно скомпилированы с макросом _FILE_OFFSET_BITS=64, поэтому невозможность установить ограничение, которое нельзя представить 32-битным значением, является проблемой, затрагивающей не только программистов, но и конечных пользователей.
С одной стороны, было бы лучше, если бы обертка setrlimit() из состава glibc возвращала ошибку, когда запрашиваемое ограничение не помещается в 32-битный тип unsigned long. Однако в основе проблемы лежит ограничение ядра, и для решения этой проблемы разработчиками glibc был выбран подход, описанный выше.