This is the mail archive of the libc-help@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

mmap'ed robust mutexes and possible undefined behaviour


        Hello everybody. First of all, I'm not subscribed to the mailing 
list, so please CC me any responses.

        We found a situation where a robust mutex cannot be recovered
from a stale lock and we're wondering if it's simply an undefined
situation or  a bug in the kernel. Attached you will find the sample
code, which is loosely based on a glibc's test case.The gist of it is as
follows:

1. we open a file.
2. we mmap it and use that mem to store a robust mutex.
3. we lock the mutex.
4. we munmap the file.
5. we close the file.

        The example does steps 1 and 2, then creates creates tw children
who will try  to do steps 3 to 5. Of course only one gets the lock while
the other waits. If the child who  has the lock does the 4th step, then
the other child never recovers the stale lock. In any  other situation
(that is, commenting/removing the code) it works fine.

    This looks suspiciously like undefined behaviour, because it's like
we're pulling  the rug from under the mutex' feet, but in the other hand
looks like a kernel bug because  it doesn't really recover from the
situation. What do you think? 

-- 
(Not so) Random fortune:
22:22 < m4rgin4l_> hendrix no tocaba la viola, violaba la toca
#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);
    /* if this munmap() call is commented, the oher child can recover the lock */
    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;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]