Estoy escribiendo una biblioteca C que en algún momento bifurca otro proceso y luego espera a que se complete.
Me gustaría escribir el código que espera a que se complete el proceso secundario de la manera más robusta y genérica, para ocuparme de todos los escenarios posibles, como que el proceso de llamada genere otros procesos secundarios, reciba señales, etc.
¿El siguiente código C usa waitpid correctamente, es decir, de la manera más robusta?
void waitForChildProcess(int child_pid) { int rc, err; do { //waiting only for my own child and only for its termination. //The status value is irrelevant (I think) because option '0' should mean //to only wait for a child termination event // and I don't care about the child's exit code: rc = waitpid(child_pid, NULL, 0); err = errno; } while (rc == -1 && err == EINTR); //ignoring a signal }Sí, waitpid(child_pid, ...) es la forma más robusta.
Devolverá child_pid si el proceso secundario ha salido, -1 con errno establecido si se produce un error ( ECHILD si el proceso secundario no existe (nunca se creó o ya se cosechó) o no es un elemento secundario de este proceso, EINVAL si las opciones (tercer parámetro) tenían un valor no válido, o EINTR si se entregó una señal a un controlador de señal que no estaba instalado con banderas SA_RESTART), o 0 si se especificó la opción WNOHANG (tercer parámetro) y el proceso secundario aún no ha salido .
Sin embargo, recomendaría un ligero cambio:
/* Wait for child process to exit. * @child_pid Process ID of the child process * @status Pointer to where the child status * is stored; may be NULL * @return 0 if success * -1 if an error occurs, see errno. */ int waitForChildProcess(pid_t child_pid, int *status) { int rc; if (child_pid <= 1) { errno = EINVAL; return -1; } do { rc = waipid(child_pid, status, 0); } while (rc == -1 && errno == EINTR); if (rc == child_pid) return 0; /* This should not happen, but let's be careful. */ if (rc != -1) errno = ECHILD; return -1; } En los sistemas Linux y POSIXy, los ID de proceso son números enteros positivos. Como puede ver en la página del manual man 2 waitpid , los PID cero y negativos se refieren a grupos de procesos y -1 a cualquier proceso secundario. El proceso 1 es especial, init ; es el que nunca sale y configura el resto del espacio de usuario. Entonces, el PID más pequeño que un hijo del proceso actual puede tener es 2.
Considero sensato usar los tipos adecuados para estos: pid_t para ID de proceso y, por ejemplo, size_t para tamaños de memoria de objetos (incluido el valor de retorno de, por ejemplo strlen() .
Proporcionar el indicador de status (para que la persona que llama pueda verificarlo con WIFEXITED() + WEXITSTATUS() o WIFSIGNALED() + WTERMSIG() ) es conveniente, ya que cualquier persona que llame no esté interesada en él puede proporcionar un NULL . ( NULL está explícitamente permitido para el puntero de estado de wait() y waitpid() .
Técnicamente, con options==0 , waitpid() solo debería devolver el PID secundario o -1 (con errno establecido). Sin embargo, dado que el cheque es tan barato, prefiero tratar todo lo demás como un error ECHILD, ya que da los resultados más sólidos.
La persona que llama es libre de ignorar el valor de retorno. Sin embargo, si quieren saberlo, el valor devuelto es 0 si tiene éxito, de lo contrario -1 con errno establecido (y strerror(errno) proporciona la razón textual).