HOWTO · C

Use a função waitpid em C

Este artigo apresenta como usar a função waitpid em C

Nesta página

Use waitpid quando um processo pai precisar coletar o status de um processo filho, seja de um filho específico ou de qualquer filho elegível. Os argumentos selecionam o filho e as mudanças de estado a serem relatadas; o status retornado deve ser decodificado com as macros de <sys/wait.h>, em vez de ser tratado diretamente como um código de saída.

Use waitpid para aguardar um processo filho específico

Um processo pode criar um filho com fork. O filho continua a partir do ponto da chamada, enquanto o pai recebe o ID do processo filho. O pai deve coletar um filho encerrado com uma função da família wait, para obter o status de término e permitir que o processo seja recolhido pelo sistema.

A chamada tem o formato waitpid(pid, &status, options). Um pid positivo seleciona esse processo filho. -1 seleciona qualquer filho cujo estado corresponda às opções, que é a seleção usada por wait; 0 seleciona os filhos do grupo de processos do chamador; e um valor menor que -1 seleciona os filhos do grupo de processos cujo ID é o valor absoluto de pid. Portanto, waitpid é útil para direcionar a espera a um filho, mas não é a única interface da família wait para aguardar filhos.

O segundo argumento aponta para um inteiro no qual o kernel armazena um status codificado quando o estado de um filho é relatado. Passe um ponteiro válido quando precisar desse status. O terceiro argumento é uma máscara de bits de opções. Com as opções definidas como 0, a chamada aguarda o término do filho selecionado. Ela bloqueia se nenhuma mudança de estado correspondente estiver pronta.

Escolha quais eventos dos processos filhos relatar

WNOHANG torna a chamada não bloqueante: se nenhum filho selecionado tiver uma mudança de estado que possa ser relatada, waitpid retornará 0 imediatamente. Assim, o processo pai pode fazer outras tarefas e verificar novamente mais tarde. Um valor de retorno positivo é o ID do processo filho cujo status foi gravado. WUNTRACED também relata um filho que parou e ainda não havia sido relatado, enquanto WCONTINUED relata um filho que retomou a execução após uma parada. Essas opções determinam quais mudanças de estado podem satisfazer uma chamada; uma única chamada não acompanha todas as transições futuras. Combine as flags com o operador OR bit a bit, como em WUNTRACED | WCONTINUED.

Decodifique o status retornado por waitpid

O inteiro de status é codificado e deve ser verificado com as macros correspondentes. WIFEXITED(status) identifica um término normal; em seguida, WEXITSTATUS(status) extrai o código de saída. WIFSIGNALED(status) identifica um término causado por sinal, e WTERMSIG(status) informa qual foi esse sinal. Quando a chamada solicita o relato de filhos parados, WIFSTOPPED(status) e WSTOPSIG(status) identificam essa parada. Quando houver suporte e a opção correspondente for solicitada, WIFCONTINUED(status) identifica um filho que retomou a execução. WCOREDUMP está disponível em alguns sistemas; por isso, o código que a usa deve verificar sua disponibilidade com uma diretiva do pré-processador. Essas macros são declaradas em <sys/wait.h>.

Não chame WEXITSTATUS a menos que WIFEXITED seja verdadeiro, nem WTERMSIG a menos que WIFSIGNALED seja verdadeiro. O inteiro não é, por si só, o código de saída do filho; usar as macros evita depender da disposição de bits específica da implementação.

Trate os valores de retorno e os erros

Um resultado de waitpid maior que zero identifica o filho cujo status foi coletado. Um resultado igual a zero significa que nenhum status correspondente está pronto e ocorre com WNOHANG. Um resultado de -1 indica um erro; consulte errno para diagnosticá-lo. Por exemplo, ECHILD significa que não há nenhum filho que corresponda à seleção, enquanto EINTR significa que um sinal capturado interrompeu a espera. Se o programa deve continuar esperando após EINTR, tente a chamada novamente; caso contrário, trate a interrupção de acordo com a política de sinais da aplicação. Uma chamada sem WNOHANG também pode bloquear indefinidamente se o filho selecionado continuar em execução e nenhuma das mudanças de estado solicitadas ocorrer.

Execute um exemplo completo com processo filho

Este exemplo POSIX cria um filho, aguarda especificamente o término dele, repete a chamada se um sinal interromper a espera e imprime o status de saída decodificado. Ele usa fork e waitpid; não depende de outro programa nem de entrada interativa. O código foi feito para um ambiente POSIX com um compilador C e não é apresentado como portável para ISO C. As evidências de execução fornecidas registram uma execução bem-sucedida, com código de saída 0 e a saída exibida abaixo.

Execute este exemplo:

O código e os rótulos ou saídas exibidos nesta seção permanecem em inglês.

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void) {
    pid_t child = fork();
    if (child == -1) {
        perror("fork");
        return EXIT_FAILURE;
    }

    if (child == 0) {
        _exit(7);
    }

    int status;
    pid_t result;
    do {
        result = waitpid(child, &status, 0);
    } while (result == -1 && errno == EINTR);

    if (result == -1) {
        perror("waitpid");
        return EXIT_FAILURE;
    }

    if (WIFEXITED(status)) {
        printf("child exit status: %d\n", WEXITSTATUS(status));
    } else if (WIFSIGNALED(status)) {
        printf("child terminated by signal: %d\n", WTERMSIG(status));
    }

    return EXIT_SUCCESS;
}
child exit status: 7