2010-11-19 3 views
10

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.

+3

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

+0

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). –

+0

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. –

Respuesta

1

(no creo que esto es una respuesta real, pero es demasiado grande para un comentario)

Ésta es una pregunta muy interesante. Miré a través del código glibc para pthread_create para ver cómo se comporta y, a menos que me falta algo, no parece haber ningún comportamiento especial para detener esto (como bloquear todas las señales antes de clone y desbloquearlas en el niño después de alguna configuración {después de registrar el tiempo de creación de subprocesos y el controlador de captura C++ catch all está configurado, lo que ocurre incluso en el código C}).

Esperaba encontrar un comentario que mencionara la posibilidad de esta situación y tal vez incluso una mención de lo que POSIX dijo que hiciera (o una mención de que no decía qué hacer).

Quizás siempre deba envolver pthread_create en el código para bloquear y restaurar señales, y comenzar todas las funciones de subproceso con una llamada de desbloqueo.

Esto bien puede ser un sitio extra en pthreads (o glibc o mi comprensión del código).

+0

Lo mejor que puedo deducir es que si las señales no se bloquean en el nuevo subproceso hasta que finalice la inicialización, la implementación debe al menos garantizar que esto no provoque que se rompa ninguna de las funciones de seguridad de señal asíncrona.Como '__thread' aún no es estándar y, por lo tanto, no forma parte de POSIX, no hay ningún requisito de que las variables de TLS sean accesibles o tengan sus valores correctos. Quizás una implementación posible (aún no he comprobado si glibc hace esto) es ajustar todos los controladores de señal con un controlador que finaliza la inicialización del hilo (si es necesario) antes de llamar al controlador de la aplicación. –

+0

Dudo que glibc envuelva a los manejadores de señal de esa manera. Creo que hacerlo requeriría duplicar el manejo de la señal que hace el kernel, así como bloquear y restaurar señales para cada llamada a 'sigaction' para evitar introducir una condición de carrera. Acabo de mirar y no parece hacer esto. También es algo complicado de hacer, muy difícil y puede requerir que el código de inicio de secuencia habitual sea capaz de reconocer que se ha interrumpido y no debe volver a hacer las cosas que ya se han hecho. – nategoose

+0

No me sorprendería que los viejos manejadores de señal envueltos en LinuxThreads. Fue un hack horrible. :-) –

-1

pthread_create es una llamada de bloqueo. No hay (nuevo) hilo para que envíe la señal antes de la llamada, y allí es un hilo para enviar la señal a después de la llamada, por lo que la llamada devuelve la identificación del hilo.

Por lo tanto, me gustaría concluir que el hilo tiene que ser válido y inicializado en ese momento ...

+0

No sigo. Mi pregunta no es sobre 'pthread_create' enviando una señal al nuevo hilo, sino sobre otras señales (generadas por otros hilos en el mismo proceso, otros procesos, o el núcleo) que se entregan al nuevo hilo antes de que se inicialice. –

+0

Esto no es cierto, pthread_create es (comúnmente) no una llamada atómica. – nos

0

Los mandatos POSIX pthread_create specification esto desde mi comprensión de:

El estado de señal de la nueva La secuencia se inicializará de la siguiente manera:

  • La máscara de señal se heredará del subproceso de creación.
  • El conjunto de señales pendientes para el nuevo hilo estará vacío.

pero no tienen la experiencia suficiente para decir que las cosas son de esta manera en varias implementaciones.

+1

Creo que eso significa estrictamente que el nuevo hilo no hereda ni comparte las señales pendientes de su creador o creador. – nategoose

+0

De hecho. No veo ninguna forma de interpretar esa afirmación diciendo que el hilo no recibirá señales antes de que esté en un estado consistente. –

+0

@R - ¿Cuál es el significado de "estado consistente"? ¿Cuál es el impacto real de obtener una señal antes de este estado constante y un microsegundo después? Es de suponer que aún sería manejado o ignorado o lo que sea. No estoy argumentando tanto como tratando de evaluar el impacto real. – Duck

Cuestiones relacionadas