|  | #include <pthread.h> | 
|  | #include <signal.h> | 
|  | #include <stdint.h> | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <string.h> | 
|  | #include <unistd.h> | 
|  | #include <sys/mman.h> | 
|  | #include <sys/wait.h> | 
|  |  | 
|  |  | 
|  |  | 
|  |  | 
|  | static void prepare (void); | 
|  | #define PREPARE(argc, argv) prepare () | 
|  | static int do_test (void); | 
|  | #define TEST_FUNCTION do_test () | 
|  | #define TIMEOUT 5 | 
|  | #include "../test-skeleton.c" | 
|  |  | 
|  |  | 
|  | static int fd; | 
|  | #define N 100 | 
|  |  | 
|  | static void | 
|  | prepare (void) | 
|  | { | 
|  | fd = create_temp_file ("tst-robust8", NULL); | 
|  | if (fd == -1) | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  |  | 
|  | #define THESIGNAL SIGKILL | 
|  | #define ROUNDS 5 | 
|  | #define THREADS 9 | 
|  |  | 
|  |  | 
|  | static const struct timespec before = { 0, 0 }; | 
|  |  | 
|  |  | 
|  | static pthread_mutex_t *map; | 
|  |  | 
|  |  | 
|  | static void * | 
|  | tf (void *arg) | 
|  | { | 
|  | long int nr = (long int) arg; | 
|  | int fct = nr % 3; | 
|  |  | 
|  | uint8_t state[N]; | 
|  | memset (state, '\0', sizeof (state)); | 
|  |  | 
|  | while (1) | 
|  | { | 
|  | int r = random () % N; | 
|  | if (state[r] == 0) | 
|  | { | 
|  | int e; | 
|  |  | 
|  | switch (fct) | 
|  | { | 
|  | case 0: | 
|  | e = pthread_mutex_lock (&map[r]); | 
|  | if (e != 0) | 
|  | { | 
|  | printf ("mutex_lock of %d in thread %ld failed with %d\n", | 
|  | r, nr, e); | 
|  | exit (1); | 
|  | } | 
|  | state[r] = 1; | 
|  | break; | 
|  | case 1: | 
|  | e = pthread_mutex_timedlock (&map[r], &before); | 
|  | if (e != 0 && e != ETIMEDOUT) | 
|  | { | 
|  | printf ("\ | 
|  | mutex_timedlock of %d in thread %ld failed with %d\n", | 
|  | r, nr, e); | 
|  | exit (1); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | e = pthread_mutex_trylock (&map[r]); | 
|  | if (e != 0 && e != EBUSY) | 
|  | { | 
|  | printf ("mutex_trylock of %d in thread %ld failed with %d\n", | 
|  | r, nr, e); | 
|  | exit (1); | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | if (e == EOWNERDEAD) | 
|  | pthread_mutex_consistent_np (&map[r]); | 
|  |  | 
|  | if (e == 0 || e == EOWNERDEAD) | 
|  | state[r] = 1; | 
|  | } | 
|  | else | 
|  | { | 
|  | int e = pthread_mutex_unlock (&map[r]); | 
|  | if (e != 0) | 
|  | { | 
|  | printf ("mutex_unlock of %d in thread %ld failed with %d\n", | 
|  | r, nr, e); | 
|  | exit (1); | 
|  | } | 
|  |  | 
|  | state[r] = 0; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  |  | 
|  | static void | 
|  | child (int round) | 
|  | { | 
|  | for (int thread = 1; thread <= THREADS; ++thread) | 
|  | { | 
|  | pthread_t th; | 
|  | if (pthread_create (&th, NULL, tf, (void *) (long int) thread) != 0) | 
|  | { | 
|  | printf ("cannot create thread %d in round %d\n", thread, round); | 
|  | exit (1); | 
|  | } | 
|  | } | 
|  |  | 
|  | struct timespec ts; | 
|  | ts.tv_sec = 0; | 
|  | ts.tv_nsec = 1000000000 / ROUNDS; | 
|  | while (nanosleep (&ts, &ts) != 0) | 
|  | /* nothing */; | 
|  |  | 
|  | /* Time to die.  */ | 
|  | kill (getpid (), THESIGNAL); | 
|  |  | 
|  | /* We better never get here.  */ | 
|  | abort (); | 
|  | } | 
|  |  | 
|  |  | 
|  | static int | 
|  | do_test (void) | 
|  | { | 
|  | if (ftruncate (fd, N * sizeof (pthread_mutex_t)) != 0) | 
|  | { | 
|  | puts ("cannot size new file"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | map = mmap (NULL, N * sizeof (pthread_mutex_t), PROT_READ | PROT_WRITE, | 
|  | MAP_SHARED, fd, 0); | 
|  | if (map == MAP_FAILED) | 
|  | { | 
|  | puts ("mapping failed"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | pthread_mutexattr_t ma; | 
|  | if (pthread_mutexattr_init (&ma) != 0) | 
|  | { | 
|  | puts ("mutexattr_init failed"); | 
|  | return 0; | 
|  | } | 
|  | if (pthread_mutexattr_setrobust_np (&ma, PTHREAD_MUTEX_ROBUST_NP) != 0) | 
|  | { | 
|  | puts ("mutexattr_setrobust failed"); | 
|  | return 1; | 
|  | } | 
|  | if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0) | 
|  | { | 
|  | puts ("mutexattr_setpshared failed"); | 
|  | return 1; | 
|  | } | 
|  | #ifdef ENABLE_PI | 
|  | if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT) != 0) | 
|  | { | 
|  | puts ("pthread_mutexattr_setprotocol failed"); | 
|  | return 1; | 
|  | } | 
|  | #endif | 
|  |  | 
|  | for (int round = 1; round <= ROUNDS; ++round) | 
|  | { | 
|  | for (int n = 0; n < N; ++n) | 
|  | { | 
|  | int e = pthread_mutex_init (&map[n], &ma); | 
|  | if (e == ENOTSUP) | 
|  | { | 
|  | #ifdef ENABLE_PI | 
|  | puts ("cannot support pshared robust PI mutexes"); | 
|  | #else | 
|  | puts ("cannot support pshared robust mutexes"); | 
|  | #endif | 
|  | return 0; | 
|  | } | 
|  | if (e != 0) | 
|  | { | 
|  | printf ("mutex_init %d in round %d failed\n", n + 1, round); | 
|  | return 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | pid_t p = fork (); | 
|  | if (p == -1) | 
|  | { | 
|  | printf ("fork in round %d failed\n", round); | 
|  | return 1; | 
|  | } | 
|  | if (p == 0) | 
|  | child (round); | 
|  |  | 
|  | int status; | 
|  | if (TEMP_FAILURE_RETRY (waitpid (p, &status, 0)) != p) | 
|  | { | 
|  | printf ("waitpid in round %d failed\n", round); | 
|  | return 1; | 
|  | } | 
|  | if (!WIFSIGNALED (status)) | 
|  | { | 
|  | printf ("child did not die of a signal in round %d\n", round); | 
|  | return 1; | 
|  | } | 
|  | if (WTERMSIG (status) != THESIGNAL) | 
|  | { | 
|  | printf ("child did not die of signal %d in round %d\n", | 
|  | THESIGNAL, round); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | for (int n = 0; n < N; ++n) | 
|  | { | 
|  | int e = pthread_mutex_lock (&map[n]); | 
|  | if (e != 0 && e != EOWNERDEAD) | 
|  | { | 
|  | printf ("mutex_lock %d failed in round %d\n", n + 1, round); | 
|  | return 1; | 
|  | } | 
|  | } | 
|  |  | 
|  | for (int n = 0; n < N; ++n) | 
|  | if (pthread_mutex_unlock (&map[n]) != 0) | 
|  | { | 
|  | printf ("mutex_unlock %d failed in round %d\n", n + 1, round); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | for (int n = 0; n < N; ++n) | 
|  | { | 
|  | int e = pthread_mutex_destroy (&map[n]); | 
|  | if (e != 0) | 
|  | { | 
|  | printf ("mutex_destroy %d in round %d failed with %d\n", | 
|  | n + 1, round, e); | 
|  | printf("nusers = %d\n", (int) map[n].__data.__nusers); | 
|  | return 1; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | if (pthread_mutexattr_destroy (&ma) != 0) | 
|  | { | 
|  | puts ("mutexattr_destroy failed"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | if (munmap (map, N * sizeof (pthread_mutex_t)) != 0) | 
|  | { | 
|  | puts ("munmap failed"); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | return 0; | 
|  | } |