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.
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; }