Программно проверить дочерний процесс зомби в Linux, используя C - PullRequest
0 голосов
/ 25 мая 2018

Я написал простую C-программу в RedHat Linux, которая ждет дочернего процесса, использующего waitpid после вызова execv.

int main( int argc, char * argv[] )
{
    int pid;
    int status = 0;
    int wait_ret;

    const char * process_path = argv[1];

    if ( argc < 2 )
    {
        exit( EXIT_FAILURE );
    }

    pid = fork(); //spawn child process

    if ( 0 == pid ) //child
    {
        int ret = execv( process_path, &argv[1] );

        if ( ret )
        {
            printf( "execv failed: %s\n", strerror( errno ) );
        }

        exit( EXIT_SUCCESS );
    }

    //wait for the child to terminate
    wait_ret = waitpid( pid, &status, WUNTRACED );

    if ( -1 == wait_ret )
    {
        printf( "ERROR: Failed to wait for process termination\n" );
        exit( EXIT_FAILURE );
    }

    // ... handlers for child exit status ...

    return 0;
}

Я использую это как простой сторож для некоторых процессов, которые я запускаю.

Моя проблема в том, что один процесс, в частности, не вызывается waitpid при выходе и вместо этого остается навсегда в состоянии Zombie, пока waitpid зависает.Я не уверен, почему waitpid не может пожинать этот процесс, когда он становится зомби (может быть, дескриптор пропущенного файла или что-то в этом роде).

Я мог бы использовать флаг WNOHANG и опрашивать дочерний файл proc stat для проверкиЗомби, но я бы предпочел более элегантное решение.Может быть, есть какая-нибудь функция, которую я мог бы использовать, чтобы получить статус Zombie, не опрашивая этот файл?

Кто-нибудь знает альтернативу waitpid, которая вернется, когда процесс станет зомби?

ДополнительноИнформация:

Дочерний процесс закрывается вызовом exit( EXIT_FAILURE); в одном из его потоков.

cat /proc/<CHILD_PID>/stat (до выхода):

1037 (my_program) S 1035 58 58 0 -1 4194560 1309 0 22 0 445 1749 0 0 20 0 13 0 4399 22347776 1136 4294967295 3336716288 3338455332 3472776112 3472775232 3335760920 0 0 4 31850 4294967295 0 0 17 0 0 0 26 0 0 333848 038 038 338 038 038 338 4830 33

cat /proc/<CHILD_PID>/stat (после выхода):

1037 (my_program) Z 1035 58 58 0 -1 4227340 1316 0 22 0 464 1834 0 0 20 0 2 0 4399 0 0 4294967295 0 0 0 0 0 00 0 4 31850 4294967295 0 0 17 0 0 0 26 0 0 0 0 0

Обратите внимание, что дочерний PID равен 1037, а родительский PID - 1035 в этом случае.

1 Ответ

0 голосов
/ 02 июня 2018

Моя проблема в том, что один процесс, в частности, не вызывается waitpid при выходе и вместо этого остается навсегда в состоянии Zombie, пока waitpid подвешен? Если я правильно понимаю, вы не хотите, чтобы ребенокстаньте зомби и используйте флаг SA_NOCLDWAIT.Со страницы руководства sigaction()

SA_NOCLDWAIT (начиная с Linux 2.6). Если signum - SIGCHLD, не превращайте детей в зомби, когда они заканчивают свою работу.Смотрите также waitpid (2).Этот флаг имеет смысл только при установлении обработчика для SIGCHLD или при установке расположения этого сигнала в SIG_DFL.

              If the SA_NOCLDWAIT flag is set when establishing a  handler
              for SIGCHLD, POSIX.1 leaves it unspecified whether a SIGCHLD
              signal is generated when a  child  process  terminates.   On
              Linux,  a  SIGCHLD signal is generated in this case; on some
              other implementations, it is not.

Идея состоит в том, когда дочерний процесс завершается первым, родительский сигнал получает сигнал № 17 или SIGCHLD& дочерний процесс станет зомби, так как родитель все еще работает.Итак, как удалить дочерний элемент как можно скорее, он становится зомби, решение - использовать флаги SA_NOCLDWAIT.

Вот пример кода

void my_isr(int n) {
        /* error handling */
}
int main(void) {
        if(fork()==0) { /* child process */
                printf("In child process ..c_pid: %d and p_pid : %d\n",getpid(),getppid());
                sleep(5);
                printf("sleep over .. now exiting \n");
        }
        else { /*parent process */
                struct sigaction v;
                v.sa_handler=my_isr;/* SET THE HANDLER TO ISR */
                v.sa_flags=SA_NOCLDWAIT; /* it will not let child to become zombie */
                sigemptyset(&v.sa_mask);
                sigaction(17,&v,NULL);/* when parent receives SIGCHLD, IT GETS CALLED */
                while(1); /*for observation purpose, to make parent process alive */
        }
        return 0;
}

Просто прокомментируйте / раскомментируйте строку v.sa_flags=SA_NOCLDWAIT; и проанализируйтеповедение путем запуска a.out в одном терминале и проверки ps -el | grep pts/0 в другом терминале.

Кто-нибудь знает альтернативу waitpid, которая вернется, когда процесс станет зомби? use WNOHANG как вы и сказали в справочной странице waitpid()

WUNTRACED также возвращаются, если ребенок остановился (но не отслежен с помощью ptrace (2)).Статус для отслеженных детей, которые остановились, предоставляется, даже если эта опция не указана.

...