HOWTO · C

Utilice la función waitpid en C

Este artículo presenta cómo usar la función waitpid en C

En esta página

Usa waitpid cuando un proceso padre necesite recoger el estado de un proceso hijo, ya sea de uno elegido o de cualquier hijo que cumpla los criterios. Sus argumentos seleccionan el hijo y los cambios de estado que se deben informar; el estado devuelto debe interpretarse con las macros de <sys/wait.h>, no tratarse directamente como un código de salida.

Usa waitpid para esperar a un proceso hijo específico

Un proceso puede crear un hijo con fork. El hijo continúa desde el punto de la llamada, mientras que el padre recibe el ID de proceso del hijo. El padre debe recoger a un hijo terminado mediante una llamada de la familia de funciones de espera, para obtener su estado de terminación y poder liberarlo del sistema.

La llamada tiene la forma waitpid(pid, &status, options). Un pid positivo selecciona ese proceso hijo. -1 selecciona cualquier hijo cuyo estado coincida con las opciones; es el criterio que usa wait. El valor 0 selecciona los hijos del grupo de procesos del proceso que llama, y un valor menor que -1 selecciona los hijos del grupo cuyo ID es el valor absoluto de pid. Por tanto, waitpid permite seleccionar un hijo, pero no es la única interfaz de la familia de espera para esperar a los hijos.

El segundo argumento apunta a un entero en el que el núcleo almacena un estado codificado cuando se informa un cambio de estado del hijo. Pasa un puntero válido si necesitas ese estado. El tercer argumento es una máscara de bits con opciones. Si options vale 0, la llamada espera a que termine el hijo seleccionado. Se bloquea si todavía no hay ningún cambio de estado coincidente disponible.

Elige qué eventos de los hijos se deben informar

WNOHANG hace que la llamada no sea bloqueante: si ningún hijo seleccionado tiene un cambio de estado que se pueda informar, waitpid devuelve 0 de inmediato. Así, el padre puede hacer otras tareas y volver a comprobarlo más tarde. Un valor de retorno positivo es el ID de proceso del hijo cuyo estado se escribió. WUNTRACED también informa de un hijo que se detuvo y cuyo estado aún no se había informado; WCONTINUED informa de un hijo que reanudó su ejecución después de detenerse. Estas opciones especifican qué cambios de estado pueden satisfacer una llamada; una sola llamada no observa todas las transiciones futuras. Combina las opciones con el operador OR bit a bit, por ejemplo, WUNTRACED | WCONTINUED.

Interpreta el estado que devuelve waitpid

El entero de estado está codificado y debe comprobarse con las macros correspondientes. WIFEXITED(status) indica una terminación normal; después, WEXITSTATUS(status) extrae el código de salida. WIFSIGNALED(status) indica que la terminación se debió a una señal, y WTERMSIG(status) devuelve esa señal. Si se solicitan estados de hijos detenidos, WIFSTOPPED(status) y WSTOPSIG(status) identifican la detención. Si está disponible y se solicita, WIFCONTINUED(status) indica que un hijo reanudó su ejecución. WCOREDUMP está disponible en algunos sistemas; si el código la usa, conviene proteger su uso con una comprobación del preprocesador. Estas macros se declaran en <sys/wait.h>.

No llames a WEXITSTATUS a menos que WIFEXITED sea verdadero, ni a WTERMSIG a menos que WIFSIGNALED sea verdadero. El entero no es por sí mismo el código de salida del hijo; usar las macros evita depender de su disposición de bits, que puede variar según la implementación.

Maneja los valores de retorno y los errores

Un resultado de waitpid mayor que cero identifica al hijo cuyo estado se recogió. Un resultado de cero significa que no hay ningún estado coincidente disponible; ocurre con WNOHANG. Un resultado de -1 indica un error; consulta errno para diagnosticarlo. Por ejemplo, ECHILD significa que no hay ningún hijo que coincida con la selección, mientras que EINTR significa que una señal capturada interrumpió la espera. Si el programa debe seguir esperando tras EINTR, vuelve a llamar a la función; de lo contrario, gestiona la interrupción según la política de señales de la aplicación. Una llamada sin WNOHANG también puede bloquearse indefinidamente si el hijo seleccionado sigue ejecutándose y no se produce ningún cambio de estado solicitado.

Ejecuta un ejemplo completo con un proceso hijo

Este ejemplo POSIX crea un hijo, espera específicamente a que termine, vuelve a intentarlo si una señal interrumpe la espera e imprime el estado de salida interpretado. Usa fork y waitpid; no depende de otro programa ni de la entrada interactiva. El código está pensado para un entorno POSIX con un compilador de C y no se presenta como portable según ISO C. La evidencia de ejecución suministrada registra una ejecución correcta, con código de salida 0 y la salida que se muestra a continuación.

Ejecuta este ejemplo:
El código y las etiquetas o salidas visibles de esta sección se mantienen en 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;
}

La etiqueta visible del bloque de salida se conserva en inglés porque el bloque debe permanecer idéntico al original.

child exit status: 7