printf("Hello world");
execlp("sleep", "sleep", "0", (char *) NULL);
}
27.6. Представьте, что родительский процесс установил обработчик для SIGCHLD и заблокировал этот сигнал. После того как один из его потомков завершается, родитель выполняет вызов wait(), чтобы получить статус потомка. Что произойдет, если родитель разблокирует SIGCHLD? Напишите программу, чтобы проверить свой ответ. Имеет ли это какое-либо отношение к программе, вызывающей функцию system()?
28. Подробнее о создании процесса и выполнении программы
Эта глава дополняет материал, изложенный в главах 24–27, охватывая различные темы, касающиеся создания процесса и выполнения программы. Будет описан учет используемых ресурсов — функция, ядра, которая в момент завершения любого процесса в системе записывает его учетную информацию. Мы рассмотрим системный вызов clone(), который представляет собой низкоуровневый программный интерфейс для создания потоков выполнения в Linux. За этим последует сравнение производительности fork(), vfork() и clone(). В конце будет рассмотрено влияние вызовов fork() и exec() на атрибуты процесса.
Когда система учета ресурсов включена, ядро записывает в общесистемный файл данные о каждом процессе, который оно завершает. Каждая такая запись содержит различные сведения, собираемые ядром, такие как код завершения процесса и сколько тот затратил процессорного времени. Учетный файл можно анализировать с помощью стандартных инструментов (вызов sa(8) предоставляет краткую сводку, а lastcomm(1) показывает информацию о ранее выполненных командах) или специализированных приложений.
В силу исторических причин учет ресурсов изначально применяли для взимания платы с пользователей за работу в многопользовательских UNIX-системах. Однако с его помощью также можно получать сведения о процессах, которые не собираются и не могут предоставляться их родителями.
Система учета ресурсов не описывается в стандарте SUSv3, хотя и доступна в большинстве разновидностей UNIX. Формат записей и местоположение файла, в котором они хранятся, могут варьироваться в зависимости от реализации. В этом разделе мы сосредоточимся на деталях, характерных для Linux, не забывая при этом отмечать некоторые различия, встречающиеся в других системах UNIX.
В Linux система учета ресурсов является опциональным компонентом ядра, который настраивается посредством параметра CONFIG_BSD_PROCESS_ACCT.
Для включения и отключения учета ресурсов привилегированный процесс (CAP_SYS_PACCT) должен воспользоваться системным вызовом acct(). Этот вызов редко применяется в прикладных программах. Обычно учет ресурсов включается при каждом запуске системы путем размещения подходящих команд в загрузочных скриптах.
#define _BSD_SOURCE
#include
int acct(const char *
Возвращает 0 при успешном завершении и –1 при ошибке
Чтобы включить учет ресурсов, аргументу acctfile нужно передать путь к обычному
Программа из листинга 28.1 использует вызов acct() для включения и отключения учета ресурсов. По своим возможностям она похожа на консольную команду accton(8).
Листинг 28.1. Включение и выключение учета ресурсов
procexec/acct_on.c
#define _BSD_SOURCE
#include
#include "tlpi_hdr.h"
int
main(int argc, char *argv[])
{
if (argc > 2 || (argc > 1 && strcmp(argv[1], "-help") == 0))
usageErr("%s [file]\n", argv[0]);
if (acct(argv[1]) == –1)
errExit("acct");
printf("Process accounting %s\n",
(argv[1] == NULL)? "disabled": "enabled");
exit(EXIT_SUCCESS);
}
procexec/acct_on.c
После включения учета ресурсов данные, записанные в структуру acct, сбрасываются в файл при завершении каждого процесса. Структура acct объявлена в заголовочном файле
typedef u_int16_t comp_t; /* См. текст */
struct acct {
char ac_flag; /* Флаги учета (см. текст) */
u_int16_t ac_uid; /* Пользовательский идентификатор процесса */
u_int16_t ac_gid; /* Групповой идентификатор процесса */
u_int16_t ac_tty; /* Управляющий терминал процесса (может
равняться 0, если процесс является демоном) */
u_int32_t ac_btime; /* Начальное время (time_t; секунды с начала эры UNIX) */
comp_t ac_utime; /* Пользовательское процессорное время
(такты системного времени) */
comp_t ac_stime; /* Системное процессорное время
(такты системного времени) */
comp_t ac_etime; /* Прошедшее (реальное) время (такты системного времени) */
comp_t ac_mem; /* Среднее потребление памяти (килобайты) */
comp_t ac_io; /* Байты, переданные вызовами read(2) и write(2)
(не используется) */