Howard Chu <hyc@symas.com> wrote on 23/11/2014 15:11:29:
> env_close does an munmap of the memory containing the mutex. According
> to the manpages, a robust mutex is supposed to automatically unlock when
> unmapped. Since this is not happening, it appears you've found a kernel
> bug. Regardless, the example is invalid. If you modify the code to just
> exit/abort/die without the bogus call to env_close, the other process
> wakes up correctly. E.g.
>
>
http://pastebin.com/9jieDnUz

        Ok, so now I managed to mimic the situation with pure pthreads functions.
The gist of it is as following:

1. we open a file.
2. we mmap the file and use the mem space to store a mutex.
3. we lock the mutex.
4. we unmmap the file.
5. we close the file.

        Seen like that I'm not sure if there's a defined behaviour for that. I'll
ask in the glibc and/or kernel MLs and I'll come back with the answer.

        Just for the record, here's the full program:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>

void *tf (int n, int f, pthread_mutex_t *m) {
    int err = pthread_mutex_lock (m);
    printf ("ml: %d\n", err);
    if (err == EOWNERDEAD) {
        err = pthread_mutex_consistent_np (m);
        printf ("mc: %d\n", err);
        if (err) {
            puts ("pthread_mutex_consistent_np");
            exit (1);
        }
    } else if (err) {
        puts ("pthread_mutex_lock");
        exit (1);
    }
    printf ("%ld got the lock.\n", n);
    sleep (3);
    /* exit without unlock */
    munmap (m, sizeof (pthread_mutex_t));
    close (f);
    printf ("%ld out\n", n);
    return NULL;
}

int main (void) {
    int err, f;
    pthread_mutex_t *m;
    pthread_mutexattr_t ma;

    pthread_mutexattr_init (&ma);
    err = pthread_mutexattr_setrobust_np (&ma, PTHREAD_MUTEX_ROBUST_NP);
    if (err) {
        puts ("pthread_mutexattr_setrobust_np");
        return 1;
    }
    err = pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED);
    if (err) {
        puts ("pthread_mutexattr_setpshared");
        return 1;
    }
#ifdef ENABLE_PI
    if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT) != 0) {
        puts ("pthread_mutexattr_setprotocol failed");
        return 1;
    }
#endif

    f= open ("mutex.mmap", O_CREAT|O_TRUNC|O_RDWR);
    if (f<0) {
        puts ("open");
        return 1;
    }

    err= ftruncate (f, sizeof (pthread_mutex_t));
    if (err) {
        puts ("ftruncate");
        return 1;
    }

    m= (pthread_mutex_t *) mmap (NULL, sizeof (pthread_mutex_t),
                                 PROT_READ|PROT_WRITE, MAP_SHARED, f, 0);

    err = pthread_mutex_init (m, &ma);
#ifdef ENABLE_PI
    if (err == ENOTSUP) {
        puts ("PI robust mutexes not supported");
        return 0;
    }
#endif
    if (err) {
        puts ("pthread_mutex_init");
        return 1;
    }

    err= fork ();
    if (err==0) {
        tf (1, f, m);
    } else if (err>0) {
        int err2= fork ();
        if (err2==0) {
            tf (2, f, m);
        } else if (err2>0) {
            // sleep (1);
            // kill (err);
            // printf ("child killed\n");
            // sleep (10);
            puts ("main out");
        } else {
            puts ("fork2");
            return 1;
        }
    } else {
        puts ("fork1");
        return 1;
    }
    return 0;
}