diff options
Diffstat (limited to 'nptl/tst-robust8.c')
-rw-r--r-- | nptl/tst-robust8.c | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/nptl/tst-robust8.c b/nptl/tst-robust8.c new file mode 100644 index 0000000000..19682e594f --- /dev/null +++ b/nptl/tst-robust8.c @@ -0,0 +1,264 @@ +#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 3 +#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; + } + + 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) + { + puts ("cannot support pshared robust mutexes"); + 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; +} |