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