En la mayoría de las implementaciones de subprocesos POSIX, se requiere cierta inicialización en el subproceso recién creado antes de que esté en un estado consistente capaz de ejecutar código de aplicación. Esto puede implicar desbloquear bloqueos en la estructura de subprocesos, inicializar el "registro de subprocesos" en implementaciones que usan uno, inicializar datos locales de subprocesos (ya sea TLS de nivel de compilador o datos específicos de subprocesos de POSIX), etc. No puedo encontrar un garantizar que toda esta inicialización finalizará antes de que el hilo pueda recibir señales; lo más cercano que puedo encontrar está en 2.4.3:¿Las señales de garantía POSIX no se entregarán a un subproceso parcialmente inicializado?
La siguiente tabla define un conjunto de funciones que deben ser de seguridad asíncrona. Por lo tanto, las aplicaciones pueden invocarlos, sin restricciones, funciones capturadora de señales:
...
Es de suponer que algunas de estas funciones (por lo menos fork
, que tiene que inspeccionar el estado global establecido por el pthread_atfork
función) depende de que el hilo esté en un estado consistente e inicializado.
Una cosa que me molesta es que he leído mucho de la fuente glibc/nptl, y no puedo encontrar ninguna sincronización explícita para evitar que una señal sea manejada por el hilo recién creado antes de que esté completamente inicializada. Esperaría que el hilo llamara al pthread_create
para bloquear todas las señales antes de llamar al clone
, y para que el nuevo hilo las desbloquee una vez que finalice la inicialización, pero no puedo encontrar ningún código para ese efecto ni lo veo en strace
.
Guau, al llamar 'fork()' desde un manejador de señal cuando se han configurado manejadores 'pthread_atfork()' ... Realmente * tienes que saber lo que estás haciendo (y confiar en la implementación de tu biblioteca) ¡para eso! Especialmente si (como es normalmente el caso) el manipulador prefork agarra un grupo de cerraduras para garantizar que los datos que representan son consistentes antes de la horquilla - cualquiera de estos bloqueos podría en principio mantenerse (o peor, en proceso de adquisición) por el hilo que maneja la señal, lo que significa que los datos son irreparablemente inconsistentes (¡o el proceso puede estancarse!). Muy bien :-) – psmears
Bueno, 'fork' figura como una de las funciones de seguridad de señal asíncrona, pero estoy de acuerdo en que casi todas las cosas útiles que una función' pthread_atfork'-registered podría hacer no son asincrónicas -seguro. Todavía hay algunos usos válidos, por ejemplo, si su manejador 'pthread_atfork' simplemente reinicia los datos con valores fijos, destruye los mutexes de control e inicializa los nuevos (todo en el proceso hijo, por supuesto). –
Lo más inquietante es lo que ocurre si una biblioteca (que no se sabe que está enhebrada por la aplicación de llamada, incluso cargada dinámicamente de forma indirecta como dependencia de otra biblioteca) configura controladores 'pthread_atexit' que no son seguros para señales asíncronas. La aplicación de llamada podría esperar que 'fork' sea asincrónico-signal-safe (como está documentado) y lo llame desde un manejador de señal. Creo que a lo que me refiero con este experimento de pensamiento es que expone una falla en el modelo de transparencia de uso de hilos por bibliotecas que se introdujo para crear pthread_atfork. –