Начиная с версии 2.6.8, ядро Linux поддерживает альтернативную версию учетного файла (известную как
Единственным отличием версии 3 является формат записей, хранящихся в учетном файле. Его можно описать следующим образом:
struct acct_v3 {
char ac_flag; /* Флаги учета */
char ac_version; /* Версия учетного файла (3) */
u_int16_t ac_tty; /* Управляющий терминал процесса */
u_int32_t ac_exitcode; /* Код завершения процесса */
u_int32_t ac_uid; /* 32-битный пользовательский идентификатор процесса */
u_int32_t ac_gid; /* 32-битный групповой идентификатор процесса */
u_int32_t ac_pid; /* Идентификатор процесса */
u_int32_t ac_ppid; /* Идентификатор родительского процесса */
u_int32_t ac_btime; /* Начальное время (time_t) */
float ac_etime; /* Прошедшее (реальное) время (такты системного времени) */
comp_t ac_utime; /* Пользовательское процессорное время
(такты системного времени) */
comp_t ac_stime; /* Системное процессорное время
(такты системного времени) */
comp_t ac_mem; /* Среднее потребление памяти (килобайты) */
comp_t ac_io; /* Количество прочитанных/записанных байтов
(не используется) */
comp_t ac_rw; /* Количество прочитанных/записанных блоков
(не используется) */
comp_t ac_minflt; /* Незначительные отказы страницы */
comp_t ac_majflt; /* Значительные отказы страницы */
comp_t ac_swaps; /* Количество сбросов в файл подкачки
(не используется; существует лишь в Linux) */
#define ACCT_COMM 16
char ac_comm[ACCT_COMM]; /* Имя команды */
};
Ниже перечислены главные отличия новой структуры acct_v3 от традиционной acct.
• Добавлено поле ac_version, содержащее номер версии этого формата записей. Для acct_v3 оно всегда равно 3.
• Добавлены поля ac_pid и ac_ppid, содержащие идентификаторы процесса и его родителя.
• Поля ac_uid и ac_gid расширены с 16 до 32 бит, чтобы вместить 32-битные пользовательские и групповые идентификаторы, появившиеся в Linux 2.4 (удлиненные идентификаторы не могут быть корректно представлены в традиционном файле формата acct).
• Тип поля ac_etime поменялся с comp_t на float, чтобы можно было записывать более длинные периоды прошедшего времени.
Аналог программы из листинга 28.2 с поддержкой версии 3 доступен в файле procexec/acct_v3_view.c внутри архива с исходными кодами, прилагающемся к этой книге.
В Linux доступен уникальный для этой системы вызов clone(), предназначенный для создания новых процессов. От fork() и vfork() он отличается тем, что позволяет более точно контролировать этапы создания процесса. Его в основном применяют в библиотеках, отвечающих за работу с потоками выполнения. Поскольку вызов clone() не является переносимым, вам следует избегать его непосредственного использования в прикладных программах. Мы упоминаем его здесь, потому что он послужит хорошим фоном для описания потоков выполнения POSIX в главах 29–33, а также потому, что он помогает осветить дополнительные аспекты вызовов fork() и vfork().
#define _GNU_SOURCE
#include
int clone(int (*
void *
/* pid_t *
Возвращает идентификатор потомка при успешном завершении или –1 в результате ошибки
Как и в случае с fork(), новый процесс, создаваемый вызовом clone(), является почти полной копией своего родителя.
Отличие от fork() состоит в том, что клонированный потомок не продолжает работу с момента вызова, а сначала вызывает функцию, указанную в аргументе func; мы будем называть ее
Клонированный дочерний процесс завершается либо при возврате функции func (в этом случае возвращаемое значение становится кодом завершения процесса), либо при вызове exit() (или _exit()). Родительский процесс может ожидать завершения потомка как обычно — с помощью вызова wait() или аналогичного ему.
Поскольку клонированный потомок может разделять память с родителем (как в случае с vfork()), он не может использовать родительский стек. Вместо этого он должен выделить для своего стека блок памяти подходящего размера и передать указатель на него в аргумент child_stack. В большинстве аппаратных архитектур стек растет сверху вниз, поэтому аргумент child_stack должен указывать на верхний конец выделенного блока.