La cancelación de pthread_cond_wait () se bloquea con PRIO_INHERIT mutex

Actualización, 4/10 2012: Corregido por el parche libc

Tengo un problema cancelando hilos enpthread_cond_wait, que usan mutexes con elPTHREAD_PRIO_INHERIT conjunto de atributos. Sin embargo, esto solo sucede en ciertas plataformas.

El siguiente ejemplo mínimo demuestra esto: (compilar cong++ <filename>.cpp -lpthread)

#include <pthread.h>
#include <iostream>

pthread_mutex_t mutex;
pthread_cond_t cond;

void clean(void *arg) {
    std::cout << "clean: Unlocking mutex..." << std::endl;
    pthread_mutex_unlock((pthread_mutex_t*)arg);
    std::cout << "clean: Mutex unlocked..." << std::endl;
}

void *threadFunc(void *arg) {
    int ret = 0;
    pthread_mutexattr_t mutexAttr;
    ret = pthread_mutexattr_init(&mutexAttr); std::cout << "ret = " << ret << std::endl;

    //Comment out the following line, and everything works
    ret = pthread_mutexattr_setprotocol(&mutexAttr, PTHREAD_PRIO_INHERIT); std::cout << "ret = " << ret << std::endl;

    ret = pthread_mutex_init(&mutex, &mutexAttr); std::cout << "ret = " << ret << std::endl;
    ret = pthread_cond_init(&cond, 0); std::cout << "ret = " << ret << std::endl;

    std::cout << "threadFunc: Init done, entering wait..." << std::endl;

    pthread_cleanup_push(clean, (void *) &mutex);
    ret = pthread_mutex_lock(&mutex); std::cout << "ret = " << ret << std::endl;
    while(1) {
        ret = pthread_cond_wait(&cond, &mutex); std::cout << "ret = " << ret << std::endl;
    }
    pthread_cleanup_pop(1);

    return 0;
}

int main() {
    pthread_t thread;
    int ret = 0;
    ret = pthread_create(&thread, 0, threadFunc, 0); std::cout << "ret = " << ret << std::endl;

    std::cout << "main: Thread created, waiting a bit..." << std::endl;
    sleep(2);

    std::cout << "main: Cancelling threadFunc..." << std::endl;
    ret = pthread_cancel(thread); std::cout << "ret = " << ret << std::endl;

    std::cout << "main: Joining threadFunc..." << std::endl;
    ret = pthread_join(thread, NULL); std::cout << "ret = " << ret << std::endl;

    std::cout << "main: Joined threadFunc, done!" << std::endl;
    return 0;
}

Cada vez que lo ejecuto,main() colgadopthread_join(). Un rastro gdb muestra lo siguiente:

Thread 2 (Thread 0xb7d15b70 (LWP 257)):
#0  0xb7fde430 in __kernel_vsyscall ()
#1  0xb7fcf362 in __lll_lock_wait () at ../nptl/sysdeps/unix/sysv/linux/i386/i686/../i486/lowlevellock.S:142
#2  0xb7fcc9f9 in __condvar_w_cleanup () at ../nptl/sysdeps/unix/sysv/linux/i386/i686/../i486/pthread_cond_wait.S:434
#3  0x08048fbe in threadFunc (arg=0x0) at /home/pthread_cond_wait.cpp:22
#4  0xb7fc8ca0 in start_thread (arg=0xb7d15b70) at pthread_create.c:301
#5  0xb7de73ae in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:130

Thread 1 (Thread 0xb7d166d0 (LWP 254)):
#0  0xb7fde430 in __kernel_vsyscall ()
#1  0xb7fc9d64 in pthread_join (threadid=3083950960, thread_return=0x0) at pthread_join.c:89
#2  0x0804914a in main () at /home/pthread_cond_wait.cpp:41

SiPTHREAD_PRIO_INHERIT no está configurado en el mutex, todo funciona como debería y el programa sale de forma limpia.

Plataformas con problemas:

Tablero AMD Fusion integrado, ejecutando unPTXDist Linux 3.2.9-rt16 basado en 32 bits (conRTpatch dieciséis). Estamos usando el más nuevoOSELAS i686 cross toolchain (2011.11.1), utilizando gcc 4.6.2, glibc 2.14.1, binutils 2.21.1a, kernel 2.6.39.La misma placa con la cadena de herramientas 2011.03.1 también (gcc 4.5.2 / glibc 2.13 / binutils 2.18 / kernel 2.6.36).

Plataformas sin problemas:

Nuestra propia placa ARM, que también ejecuta un PTXDist Linux (32-bit 2.6.29.6-rt23), usa el conjunto de herramientas cruzadas OSELAS arm-v4t (1.99.3) con gcc 4.3.2 / glibc 2.8 / binutils 2.18 / kernel 2.6.27 .Mi computadora portátil (Intel Core i7), que ejecuta Ubuntu 11.04 de 64 bits (virtualizado / kernel 2.6.38.15-generic), gcc 4.5.2 / eglibc 2.13-0ubuntu13.1 / binutils 2.21.0.20110327.

He estado buscando soluciones en la red y he encontrado algunos parches que he probado, pero sin ningún efecto:

Hacer que las variables de condición sean prioritarias a la herencia.Manejo de EAGAIN desde FUTEX_WAIT_REQUEUE_PI

¿Estamos haciendo algo mal en nuestro código, que simplemente funciona en ciertas plataformas, o es un error en los sistemas subyacentes? Si alguien tiene alguna idea sobre dónde buscar, o conoce algún parche o similar para probar, me encantaría saberlo.

¡Gracias!

Actualizaciones:

Discusión de la lista de correo libc-helpinforme de error de Glibc

Respuestas a la pregunta(1)

Su respuesta a la pregunta