#include #include #include #include #include #include #include #include #include #define __USE_UNIX98 #include #define TEST_FILE "test.file" int init_mutex(pthread_mutex_t *mutex) { pthread_mutexattr_t mattr; if (pthread_mutexattr_init(&mattr)) { perror("pthread_mutexattr_init: "); exit(1); } if (pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED)) { perror("pthread_mutexattr_setpshared: "); exit(1); } #ifdef USE_PI if (pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT)) { perror("pthread_mutexattr_setprotocol PI: "); exit(1); } #endif if (pthread_mutexattr_setrobust_np(&mattr, PTHREAD_MUTEX_ROBUST_NP)) { perror("pthread_mutexattr_setrobust_np: "); exit(1); } memset(mutex, 0, sizeof(pthread_mutex_t)); if (pthread_mutex_init(mutex, &mattr)) { perror("mutex_init: "); exit(1); } } int init_test_file(const char *fname) { int fd = open(fname, O_RDWR|O_CREAT, S_IREAD|S_IWRITE); if (fd == -1) { perror("file open:"); exit(1); } if (ftruncate(fd, 4096)) { perror("truncate: "); exit(1); } } pthread_mutex_t *get_mutex_from_file(const char *fname) { int fd = open(fname, O_RDWR, S_IREAD|S_IWRITE); if (fd == -1) { perror("file open: "); exit(1); } void * addr = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { perror("mmap failed: "); exit(1); } /* prefault the shared page */ asm volatile ("" : : "r" (*((unsigned char *)addr))); return (pthread_mutex_t *)addr; } void check_locked_mutex(pthread_mutex_t *mutex) { if (!pthread_mutex_trylock(mutex)) { fprintf(stderr, "mutex is not held\n"); exit(1); } } void sleep_up_to_sec(int sec) { /* srandom(time(NULL)); usleep((random()%sec) * 1000000); */ } int main(int argc, char **argv) { if (argc > 1) { /* First run is just an initialization */ init_test_file(TEST_FILE); pthread_mutex_t * mutex = get_mutex_from_file(TEST_FILE); init_mutex(mutex); exit(0); } pthread_mutex_t * mutex = get_mutex_from_file(TEST_FILE); int i; sleep_up_to_sec(5); for (i = 0; i < 1000; ++i) { int state = pthread_mutex_lock(mutex); if (state == EOWNERDEAD) { // We always perform check for dead process // Therefore may safely mark mutex as recovered printf("ownerdead\n"); pthread_mutex_consistent_np(mutex); }else if (state) { perror("pthread_mutex_lock"); exit(1); } check_locked_mutex(mutex); sleep_up_to_sec(10); if (pthread_mutex_unlock(mutex)) { perror("pthread_mutex_unlock"); exit(1); } } exit(0); }