En su página web sobre el truco del self-pipe , Dan Bernstein explica una condición de carrera select()
e indica, ofrece una solución y concluye que
Por supuesto, lo correcto sería
fork()
devolver un descriptor de archivo, no un ID de proceso.
¿Qué quiere decir con esto? ¿Tiene algo que ver select()
con los procesos secundarios para manejar sus cambios de estado en lugar de tener que usar un controlador de señal para recibir notificaciones de esos cambios de estado?
signals
file-descriptors
fork
Lassi
fuente
fuente
signalfd
algo así fuera en ese entonces.wait()
, había cosas que no podías hacer, así que alguien inventó SIGCHLD, pero fue un mal trabajo. En mi experiencia, y ahora que existen, aspersión agradable, sin bloqueowait3()
,wait4()
y / owaitpid()
llamadas en lugares clave (tal vez su bucle de eventos principal) es una alternativa muy superior.Respuestas:
El problema se describe allí en su fuente,
select()
debe ser interrumpido por señales comoSIGCHLD
, pero en algunos casos no funciona tan bien. Entonces, la solución es hacer que la señal escriba en una tubería, que luego es observadaselect()
. Mirar los descriptores de archivos es para quéselect()
sirve, de modo que se soluciona el problema.La solución alternativa esencialmente convierte el evento de señal en un evento de descriptor de archivo. Si
fork()
acaba de devolver un fd en primer lugar, la solución no sería necesaria, ya que presumiblemente ese fd podría usarse directamente conselect()
.Entonces sí, su descripción en el último párrafo me parece correcta.
Otra razón por la que un fd (o algún otro tipo de identificador de kernel) sería mejor que un número de identificación de proceso simple, es que los PID pueden reutilizarse después de que el proceso falle. Eso puede ser un problema en algunos casos cuando se envían señales a los procesos, puede que no sea posible saber con certeza que el proceso es el que usted cree que es, y no otro que reutilice el mismo PID. (Aunque creo que esto no debería ser un problema al enviar señales a un proceso secundario, ya que el padre tiene que ejecutarse
wait()
en el niño para que se libere su PID).fuente
wait()
.clone
, que es la llamada real del sistema que fork invoca en Linux. La bandera para habilitar esto se llamaCLONE_PIDFD
- Ver por ejemplo lwn.net/Articles/784831 .Es solo una reflexión sobre las líneas de "sería genial si Unix fuera diseñado de manera diferente a como es".
El problema con los PID es que viven en un espacio de nombres global donde podrían reutilizarse para otro proceso, y sería bueno si
fork()
devolviera en el padre algún tipo de identificador que se garantice que siempre se refiera al proceso hijo, y que podría pasar a otros procesos mediante herencia o sockets unix /SCM_RIGHTS
[1].Vea también la discusión aquí para un esfuerzo reciente para "arreglar" eso en Linux, incluida la adición de un indicador
clone()
que hará que devuelva un pid-fd en lugar de un PID.Pero incluso entonces, eso no eliminaría la necesidad de ese hack de auto-tubería [2] o mejores interfaces, ya que las señales que notifican a un proceso padre sobre el estado de un hijo no son las únicas que le gustaría manejar en el bucle principal Del programa. Desafortunadamente, cosas como
epoll(7) + signalfd(2)
en Linux okqueue(2)
en BSD no son estándar: la única interfaz estándar (pero no compatible con sistemas más antiguos) es muy inferiorpselect(2)
.[1] Evitar que el PID se vuelva a
waitpid()
reciclar para cuando la llamada al sistema haya regresado y se haya utilizado su valor de retorno probablemente podría lograrse en los sistemas más nuevos mediante el usowaitid(.., WNOWAIT)
.[2] No comentaría sobre la afirmación de DJ Bernstein de que lo inventó (perdón por la apófisis ;-)).
fuente
Bernstein no da mucho contexto para este comentario de "Cosa correcta", pero me arriesgaré a adivinar: hacer que fork (2) devuelva un PID es inconsistente con los descriptores de archivo abierto (2), creat (2), etc. El resto del sistema Unix podría haber realizado la manipulación del proceso con un descriptor de archivo que representa un proceso, en lugar de un PID. Existe una llamada al sistema signalfd (2) , que permite una interacción algo mejor entre las señales y los descriptores de archivo, y muestra que un proceso que representa un descriptor de archivo podría funcionar.
fuente
pidfd_open
Linux, ver por ejemplo lwn.net/Articles/789023