Какие условия могут привести к сбою вызовов fork() или system() в Linux?

И как узнать, происходят ли какие-либо из них и приводят ли они к ошибке, возвращаемой fork() или system()? Другими словами, если fork() или system() возвращаются с ошибкой, какие вещи в Linux я могу проверить, чтобы диагностировать, почему возникает эта конкретная ошибка?

Например:

  • Просто не хватает памяти (приводит к ошибке ENOMEM) — проверьте использование памяти с помощью «свободно» и т. д.
  • Ядру не хватает памяти для копирования таблиц страниц и другой учетной информации родительского процесса (приводит к ошибке EAGAIN).
  • Существует ли глобальный лимит процесса? (также приводит к ошибке EAGAIN?)
  • Существует ли ограничение на количество процессов для каждого пользователя? Как я могу узнать, что это такое?
  • ...?

person Reed Hedges    schedule 12.05.2009    source источник
comment
Чтобы уточнить, когда вы знаете, что во время fork() произошла ошибка, такая как EAGAIN (errno == EAGAIN), как вы узнаете, что именно вызвало ее (было ли это RLIMIT_NPROC? Была ли это ошибка копирования таблиц страниц или структура задачи , и если да то почему?и как этого избежать?)   -  person Reed Hedges    schedule 13.05.2009
comment
Я также задал другой, но связанный с этим вопрос о таблицах страниц в Linux: stackoverflow.com/questions/853736/   -  person Reed Hedges    schedule 13.05.2009


Ответы (2)


И как можно узнать, происходят ли какие-либо из них?

Проверьте значение errno, если результат (возвращаемое значение) равен -1.

Из справочной страницы в Linux:

ВОЗВРАЩАЕМОЕ ЗНАЧЕНИЕ
В случае успеха родительскому процессу возвращается PID дочернего процесса, а дочернему — 0. В случае сбоя в родительском процессе возвращается -1, дочерний процесс не создается, а errno устанавливается соответствующим образом.

ОШИБКИ
EAGAIN
fork() не может выделить достаточно памяти для копирования таблиц родительских страниц и выделения структуры задачи для дочернего.
EAGAIN
Невозможно создать новый процесс, так как RLIMIT_NPROC вызывающей стороны достигнут предел ресурса. Чтобы превысить это ограничение, процесс должен иметь возможность CAP_SYS_ADMIN или CAP_SYS_RESOURCE.
ENOMEM
fork() не удалось выделить необходимые структуры ядра из-за нехватки памяти.

СООТВЕТСТВУЕТ SVr4, 4.3BSD, POSIX.1-2001.

person lothar    schedule 12.05.2009
comment
Возвращаемое значение равно -1, переменная errno имеет значение EAGAIN, ENOMEM и т. д. - person Chas. Owens; 12.05.2009
comment
@Час. Оуэнс Вот что я сказал. Проверьте значение ошибки, если результат равен -1. - person lothar; 12.05.2009
comment
Ах, я проанализировал это, проверив ошибку на -1, извините. - person Chas. Owens; 12.05.2009
comment
Извините, я был неясен в своем первоначальном комментарии. Я знаю все о кодах ошибок (да, я прочитал справочную страницу перед публикацией в stackoverflow! :), то, что я ищу, - это способы узнать, какие условия в системе привели к этим ошибкам. (Обратите внимание, например, что есть по крайней мере два условия, при которых fork() устанавливает EAGAIN.) - person Reed Hedges; 13.05.2009
comment
@Reed Hedges Я думаю, вы могли бы проверить, исчерпан ли лимит процессов, и сделать вывод, был ли EAGAIN установлен из-за лимита или нет. - person lothar; 13.05.2009

nproc в /etc/security/limits.conf может ограничить количество процессов на пользователя.

Вы можете проверить наличие отказа, изучив возврат от форка. 0 означает, что вы находитесь в дочернем элементе, положительное число — это pid дочернего элемента и означает, что вы находитесь в родительском, а отрицательное число означает, что вилка не удалась. Когда вилка терпит неудачу, она устанавливает внешнюю переменную errno. Вы можете использовать функции в errno.h, чтобы изучить его. Обычно я просто использую perror, чтобы напечатать ошибку (с добавленным к ней текстом) в stderr.

#include <stdio.h>
#include <errno.h>
#include <unistd.h>

int main(int argc, char** argv) {
    pid_t pid;

    pid = fork();
    if (pid == -1) {
        perror("Could not fork: ");
        return 1;
    } else if (pid == 0) {
        printf("in child\n");
        return 0;
    };

    printf("in parent, child is %d\n", pid);

    return 0;
}
person Chas. Owens    schedule 12.05.2009