Выбрать главу

У каждого ресурса есть два лимита: жесткий и нежесткий. Второе значение никогда не может быть больше первого, и лишь процессы с привилегиями супер пользователя имеют право менять жесткий лимит. Обычно приложение уменьшает нежесткий лимит, ограничивая потребление системных ресурсов.

Обе функции принимают два аргумента: код, задающий тип ограничения, и указатель на структуру типа rlimit. Функция getrlimit() заполняет поля этой структуры, тогда как функция setrlimit() проверяет их и соответствующим образом меняет лимит. У структуры rlimit два поля: в поле rlim_cur содержится значение нежесткого лимита, а в поле rlim_max — значение жесткого лимита.

Ниже перечислены коды наиболее полезных лимитов, допускающих возможность изменения.

■ RLIMIT_CPU. Это максимальный интервал времени центрального процессора (в секундах), занимаемый программой. Именно столько времени отводится программе на доступ к процессору. В случае превышения данного ограничения программа будет завершена по сигналу SIGXCPU.

■ RLIMIT_DATA. Это максимальный объем памяти, который программа может запросить для своих данных. Запросы на дополнительную память будут отвергнуты системой.

■ RLIMIT_NPROC. Это максимальное число дочерних процессов, которые могут быть запущены пользователем. Если процесс вызывает функцию fork(), а лимит уже исчерпал, функция завершается ошибкой.

■ RLIMIT_NOFILE. Это максимальное число файлов, которые могут быть одновременно открыты процессом.

Программа, приведенная в листинге 8.4, задает односекундный лимит использования центрального процессора, после чего переходит в бесконечный цикл. Как только программа превышает установленный ею же лимит, ОС Linux уничтожает ее.

Листинг 8.4. (limit-cpu.c) Задание ограничения на использование нейтрального процессора

#include <sys/resource.h>

#include <sys/time.h>

#include <unistd.h>

int main() {

 struct rlimit rl;

 /* Определяем текущие лимиты. */

 getrlimit(RLIMIT_CPU, &rl);

 /* Ограничиваем время доступа к процессору

    одной секундой. */

 rl.rlim_cur = 1;

 setrlimit(RLIMIT_CPU, &rl);

 /* Переходим в бесконечный цикл. */

 while(1);

 return 0;

}

Когда программа завершается по сигналу SIGXCPU, интерпретатор команд выдает поясняющее сообщение:

% ./limit_cpu

CPU time limit exceeded

8.6. Функция getrusage(): статистика процессов

Функция getrusage() запрашивает у ядра статистику работы процессов. Если первый аргумент функции равен RUSAGE_SELF, процесс получит информацию о самом себе. Если же первым аргументом является константа RUSAGE_CHILDREN, будет выдана информация обо всех его завершившихся дочерних процессах. Второй аргумент — это указатель на структуру типа rusage, в которую заносятся статистические данные.

Перечислим наиболее интересные поля этой структуры.

■ ru_utime. Здесь находится структура типа timeval, в которой указано, сколько пользовательского времени (в секундах) ушло на выполнение процесса. Это время, затраченное центральным процессором на выполнение программного кода, а не системных вызовов.

■ ru_stime. Здесь находится структура типа timeval, в которой указано, сколько системного времени (в секундах) ушло на выполнение процесса. Это время, затраченное центральным процессором на выполнение системных вызовов от имени данного процесса.

■ ru_maxrss. Это максимальный объем физической памяти, которую процесс занимал в какой-то момент своего выполнения.

В листинге 8.5 приведена функция, которая показывает, сколько пользовательского и системного времени потребил текущий процесс.

Листинг 8.5. (prinf-cpu-times.c) Определение пользовательского и системного времени, затраченного на выполнение текущего процесса

#include <stdio.h>

#include <sys/resource.h>

#include <sys/time.h>

#include <unistd.h>

void print_cpu_time() {

 struct rusage usage;

 getrusage(RUSAGE_SELF, &usage);

 printf("CPU time: %ld.%061d sec user, %ld.%061d sec system\n",

  usage.ru_utime.tv_sec, usage.ru_utime.tv_usec,

  usage.ru_stime.tv_sec, usage.ru_stime.tv_usec);

}