2011-09-11 17 views
5

Me he encontrado con un problema con el sistema operativo futex de Linux (operación FUTEX_WAIT) que algunas veces regresa temprano aparentemente sin causa. La documentación especifica ciertas condiciones que pueden hacer que regrese pronto (sin un FUTEX_WAKE) pero todas involucran valores de retorno distintos de cero: EAGAIN si el valor en la dirección futex no coincide, ETIMEDOUT para tiempos esperados que expiran, EINTR cuando se interrumpe por una señal (no reinicio), etc. Pero veo un valor de retorno de 0. Lo que, aparte de FUTEX_WAKE o la terminación de un hilo cuyo puntero set_tid_address apunta al futex, podría causar que FUTEX_WAIT devuelva con un valor de retorno de 0?Linux futex syscall spurious Wakes con valor de retorno 0?

En caso de que sea útil, el futex particular, que estaba esperando en es la dirección tid hilo (establecido por el clone syscall con CLONE_CHILD_CLEARTID), y el hilo tenía no terminado. Mi (aparentemente incorrecta) suposición de que la operación FUTEX_WAIT que retorna 0 solo podría ocurrir cuando el hilo terminó conduce a errores serios en la lógica del programa, que he reparado desde entonces mediante bucles y reintentando incluso si devuelve 0, pero ahora tengo curiosidad por a por qué sucedió

Aquí es un caso de prueba mínima:

#define _GNU_SOURCE 
#include <sched.h> 
#include <sys/syscall.h> 
#include <unistd.h> 
#include <linux/futex.h> 
#include <signal.h> 

static char stack[32768]; 
static int tid; 

static int foo(void *p) 
{ 
     syscall(SYS_getpid); 
     syscall(SYS_getpid); 
     syscall(SYS_exit, 0); 
} 

int main() 
{ 
     int pid = getpid(); 
     for (;;) { 
       int x = clone(foo, stack+sizeof stack, 
         CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND 
         |CLONE_THREAD|CLONE_SYSVSEM //|CLONE_SETTLS 
         |CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID 
         |CLONE_DETACHED, 
         0, &tid, 0, &tid); 
       syscall(SYS_futex, &tid, FUTEX_WAIT, x, 0); 
       /* Should fail... */ 
       syscall(SYS_tgkill, pid, tid, SIGKILL); 
     } 
} 

se deja correr por un tiempo, por lo que finalmente debe terminar con Killed (SIGKILL), que sólo es posible si el hilo todavía existe cuando el FUTEX_WAIT devoluciones.

Antes de que cualquiera asuma que esto es solo el núcleo despertando el futex antes de que termine destruyendo el hilo (lo que de hecho podría estar ocurriendo en mi caso de prueba mínimo aquí), observo que en mi código original corriendo en el hilo bien después de FUTEX_WAIT devuelto.

+0

Creo que es posible que necesitemos ver un ejemplo mínimo; es difícil encontrar consejos importantes, ya que se desconoce mucho (publicaré mi presentimiento como una respuesta temporal de todos modos, porque es un gran comentario) – sehe

+0

De hecho, veré si puedo armar un mínimo ejemplo. –

+0

hm, creo que la página del manual no está clara. las condiciones bajo el valor de retorno de 'FUTEX_WAIT' califica las condiciones no nulas como condiciones de * error *, no solo diagnósticos. Luego, más tarde dice "En caso de error, todas las operaciones devuelven -1 y configuran errno para indicar el error". Por otro lado, las condiciones aquí no se repiten en la sección ** ERRORES **. –

Respuesta

0

¿Podría estar lidiando con una condición de carrera entre si las operaciones principales o secundarias se completan primero? Probablemente pueda investigar esta teoría durmiendo poco al principio de su foo() o inmediatamente después del clon() para determinar si una secuencia forzada de eventos enmascara el problema. No recomiendo arreglar nada de esa manera, pero podría ser útil investigarlo. Tal vez el futex no está listo para ser atendido hasta que el niño llegue más lejos a través de su inicialización, pero el clon del padre tiene suficiente para regresar a la persona que llama?

En concreto, la presencia de la opción CLONE_VFORK parece implicar que se trata de un escenario peligroso. Es posible que necesite un mecanismo de señalización bidireccional para que el niño le indique al padre que ha llegado lo suficientemente lejos como para esperar con seguridad al niño.

+0

Si 'tid' no se había escrito con el valor tid en el momento en que se llama' FUTEX_WAIT', la operación volvería con 'EAGAIN' en lugar de 0 . (De todos modos, el punto de la bandera 'CLONE_PARENT_SETTID' para' clon' es asegurar que el valor haya sido escrito antes de que cualquiera de los hilos pueda ejecutarse.) No veo ninguna posibilidad para una carrera aquí en el espacio de usuario ya que nada interesante está sucediendo en el espacio de usuario ... –

Cuestiones relacionadas