Фоновые и приостановленные процессы. Реализация оболочки управления заданиями в C - PullRequest
0 голосов
/ 16 мая 2018

Я внедряю оболочку Job Control в C в Linux как проект по теме, связанной с операционными системами.У меня есть функция main (), которая выполняет управление дочерними процессами, помогает с помощью связанного списка, как показано здесь, в котором хранится информация фоновых и приостановленных заданий:

typedef struct job_
{
    pid_t pgid; /* group id = process lider id */
    char * command; /* program name */
    enum job_state state;
    struct job_ *next; /* next job in the list */
} job;

Каждый раз, когда дочерний процесс завершается или останавливается,SIGCHLD отправляется в родительский процесс для информирования об этом.Затем у меня есть обработчик сигнала, как показано здесь, для каждого узла этого связанного списка состояний заданий проверяется, завершился ли процесс, представленный в этом узле, и, если он это сделал, этот узел был удален из связанного списка.Вот код для обработчика SIGCHLD, где 'job_list' - это связанный список, в котором хранится информация:

void mySIGCHLD_Handler(int signum) {
    block_SIGCHLD();
    if (signum == 17) {
        job *current_node = job_list->next, *node_to_delete = NULL;
        int process_status, process_id_deleted;

        while (current_node) {

            /* Wait for a child process to finish.
            *    - WNOHANG: return immediately if the process has not exited
            */
            waitpid(current_node->pgid, &process_status, WNOHANG);

            if (WIFEXITED(process_status) != 0) {
                node_to_delete = current_node;
                current_node = current_node->next;
                process_id_deleted = node_to_delete->pgid;
                if (delete_job(job_list, node_to_delete)) {
                printf("Process #%d deleted from job list\n", process_id_deleted);
                } else {
                    printf("Process #%d could not be deleted from job list\n", process_id_deleted);
                }
            } else {
                current_node = current_node->next;
            }
        }
    }
    unblock_SIGCHLD();
}

Дело в том, что при вызове обработчика некоторые записи не следует удалять, посколькупроцесс, который они представляют, не завершается, а удаляется, когда не должен.Кто-нибудь знает, почему это происходит?

Спасибо и извините за потерянное время :(

1 Ответ

0 голосов
/ 16 мая 2018

Я вижу много проблем в этом коде, но ближайшая проблема, вероятно, здесь:

        waitpid(current_node->pgid, &process_status, WNOHANG);
        if (WIFEXITED(process_status) != 0) {

Когда waitpid(pid, &status, WNOHANG) возвращается, потому что процесс не завершился, он ничего не записывает в status, поэтому последующее if ветвится на мусоре. Вам нужно проверить фактическое возвращаемое значение waitpid, прежде чем предположить, что status имеет смысл.

Наиболее важные другие проблемы:

  • Ядру разрешено отправлять только один SIGCHLD, чтобы сообщить вам о выходе из нескольких процессов. Когда вы получаете SIGCHLD, вам нужно вызывать waitpid(0, &status, WNOHANG) в цикле, пока он не сообщит вам, что больше нет процессов, ожидающих, и вам нужно обработать (без каламбура) все из идентификаторы завершенных процессов, о которых он сообщает.

  • Не безопасно вызывать printf или free из асинхронного обработчика сигнала. Вместо этого добавьте завершенные процессы в список отложенных задач. Обязательно заблокируйте SIGCHLD в коде основного цикла, который использует этот список.

  • Не блокируйте и не разблокируйте SIGCHLD самостоятельно в обработчике; это неизбежное состояние гонки. Вместо этого, пусть ядро ​​сделает это за вас, атомарно, правильно настроив ваш обработчик сигнала: используйте sigaction и не ставьте SA_NODEFER в sa_flags. ( Do положить SA_RESTART в sa_flags, если только у вас нет веских причин не делать этого).

  • Вместо этого буквенное число 17 должно быть постоянной сигнала SIGCHLD. Некоторые номера сигналов были стабильными во всех Unix на протяжении истории, но SIGCHLD не является одним из них.

...