| lh | 9ed821d | 2023-04-07 01:36:19 -0700 | [diff] [blame] | 1 | #include <pthread.h> | 
 | 2 | #include <signal.h> | 
 | 3 | #include <stdint.h> | 
 | 4 | #include <stdio.h> | 
 | 5 | #include <stdlib.h> | 
 | 6 | #include <string.h> | 
 | 7 | #include <unistd.h> | 
 | 8 | #include <sys/mman.h> | 
 | 9 | #include <sys/wait.h> | 
 | 10 |  | 
 | 11 |  | 
 | 12 |  | 
 | 13 |  | 
 | 14 | static void prepare (void); | 
 | 15 | #define PREPARE(argc, argv) prepare () | 
 | 16 | static int do_test (void); | 
 | 17 | #define TEST_FUNCTION do_test () | 
 | 18 | #define TIMEOUT 5 | 
 | 19 | #include "../test-skeleton.c" | 
 | 20 |  | 
 | 21 |  | 
 | 22 | static int fd; | 
 | 23 | #define N 100 | 
 | 24 |  | 
 | 25 | static void | 
 | 26 | prepare (void) | 
 | 27 | { | 
 | 28 |   fd = create_temp_file ("tst-robust8", NULL); | 
 | 29 |   if (fd == -1) | 
 | 30 |     exit (1); | 
 | 31 | } | 
 | 32 |  | 
 | 33 |  | 
 | 34 | #define THESIGNAL SIGKILL | 
 | 35 | #define ROUNDS 5 | 
 | 36 | #define THREADS 9 | 
 | 37 |  | 
 | 38 |  | 
 | 39 | static const struct timespec before = { 0, 0 }; | 
 | 40 |  | 
 | 41 |  | 
 | 42 | static pthread_mutex_t *map; | 
 | 43 |  | 
 | 44 |  | 
 | 45 | static void * | 
 | 46 | tf (void *arg) | 
 | 47 | { | 
 | 48 |   long int nr = (long int) arg; | 
 | 49 |   int fct = nr % 3; | 
 | 50 |  | 
 | 51 |   uint8_t state[N]; | 
 | 52 |   memset (state, '\0', sizeof (state)); | 
 | 53 |  | 
 | 54 |   while (1) | 
 | 55 |     { | 
 | 56 |       int r = random () % N; | 
 | 57 |       if (state[r] == 0) | 
 | 58 | 	{ | 
 | 59 | 	  int e; | 
 | 60 |  | 
 | 61 | 	  switch (fct) | 
 | 62 | 	    { | 
 | 63 | 	    case 0: | 
 | 64 | 	      e = pthread_mutex_lock (&map[r]); | 
 | 65 | 	      if (e != 0) | 
 | 66 | 		{ | 
 | 67 | 		  printf ("mutex_lock of %d in thread %ld failed with %d\n", | 
 | 68 | 			  r, nr, e); | 
 | 69 | 		  exit (1); | 
 | 70 | 		} | 
 | 71 | 	      state[r] = 1; | 
 | 72 | 	      break; | 
 | 73 | 	    case 1: | 
 | 74 | 	      e = pthread_mutex_timedlock (&map[r], &before); | 
 | 75 | 	      if (e != 0 && e != ETIMEDOUT) | 
 | 76 | 		{ | 
 | 77 | 		  printf ("\ | 
 | 78 | mutex_timedlock of %d in thread %ld failed with %d\n", | 
 | 79 | 			  r, nr, e); | 
 | 80 | 		  exit (1); | 
 | 81 | 		} | 
 | 82 | 	      break; | 
 | 83 | 	    default: | 
 | 84 | 	      e = pthread_mutex_trylock (&map[r]); | 
 | 85 | 	      if (e != 0 && e != EBUSY) | 
 | 86 | 		{ | 
 | 87 | 		  printf ("mutex_trylock of %d in thread %ld failed with %d\n", | 
 | 88 | 			  r, nr, e); | 
 | 89 | 		  exit (1); | 
 | 90 | 		} | 
 | 91 | 	      break; | 
 | 92 | 	    } | 
 | 93 |  | 
 | 94 | 	  if (e == EOWNERDEAD) | 
 | 95 | 	    pthread_mutex_consistent_np (&map[r]); | 
 | 96 |  | 
 | 97 | 	  if (e == 0 || e == EOWNERDEAD) | 
 | 98 | 	    state[r] = 1; | 
 | 99 | 	} | 
 | 100 |       else | 
 | 101 | 	{ | 
 | 102 | 	  int e = pthread_mutex_unlock (&map[r]); | 
 | 103 | 	  if (e != 0) | 
 | 104 | 	    { | 
 | 105 | 	      printf ("mutex_unlock of %d in thread %ld failed with %d\n", | 
 | 106 | 		      r, nr, e); | 
 | 107 | 	      exit (1); | 
 | 108 | 	    } | 
 | 109 |  | 
 | 110 | 	  state[r] = 0; | 
 | 111 | 	} | 
 | 112 |     } | 
 | 113 | } | 
 | 114 |  | 
 | 115 |  | 
 | 116 | static void | 
 | 117 | child (int round) | 
 | 118 | { | 
 | 119 |   for (int thread = 1; thread <= THREADS; ++thread) | 
 | 120 |     { | 
 | 121 |       pthread_t th; | 
 | 122 |       if (pthread_create (&th, NULL, tf, (void *) (long int) thread) != 0) | 
 | 123 | 	{ | 
 | 124 | 	  printf ("cannot create thread %d in round %d\n", thread, round); | 
 | 125 | 	  exit (1); | 
 | 126 | 	} | 
 | 127 |     } | 
 | 128 |  | 
 | 129 |   struct timespec ts; | 
 | 130 |   ts.tv_sec = 0; | 
 | 131 |   ts.tv_nsec = 1000000000 / ROUNDS; | 
 | 132 |   while (nanosleep (&ts, &ts) != 0) | 
 | 133 |     /* nothing */; | 
 | 134 |  | 
 | 135 |   /* Time to die.  */ | 
 | 136 |   kill (getpid (), THESIGNAL); | 
 | 137 |  | 
 | 138 |   /* We better never get here.  */ | 
 | 139 |   abort (); | 
 | 140 | } | 
 | 141 |  | 
 | 142 |  | 
 | 143 | static int | 
 | 144 | do_test (void) | 
 | 145 | { | 
 | 146 |   if (ftruncate (fd, N * sizeof (pthread_mutex_t)) != 0) | 
 | 147 |     { | 
 | 148 |       puts ("cannot size new file"); | 
 | 149 |       return 1; | 
 | 150 |     } | 
 | 151 |  | 
 | 152 |   map = mmap (NULL, N * sizeof (pthread_mutex_t), PROT_READ | PROT_WRITE, | 
 | 153 | 	      MAP_SHARED, fd, 0); | 
 | 154 |   if (map == MAP_FAILED) | 
 | 155 |     { | 
 | 156 |       puts ("mapping failed"); | 
 | 157 |       return 1; | 
 | 158 |     } | 
 | 159 |  | 
 | 160 |   pthread_mutexattr_t ma; | 
 | 161 |   if (pthread_mutexattr_init (&ma) != 0) | 
 | 162 |     { | 
 | 163 |       puts ("mutexattr_init failed"); | 
 | 164 |       return 0; | 
 | 165 |     } | 
 | 166 |   if (pthread_mutexattr_setrobust_np (&ma, PTHREAD_MUTEX_ROBUST_NP) != 0) | 
 | 167 |     { | 
 | 168 |       puts ("mutexattr_setrobust failed"); | 
 | 169 |       return 1; | 
 | 170 |     } | 
 | 171 |   if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0) | 
 | 172 |     { | 
 | 173 |       puts ("mutexattr_setpshared failed"); | 
 | 174 |       return 1; | 
 | 175 |     } | 
 | 176 | #ifdef ENABLE_PI | 
 | 177 |   if (pthread_mutexattr_setprotocol (&ma, PTHREAD_PRIO_INHERIT) != 0) | 
 | 178 |     { | 
 | 179 |       puts ("pthread_mutexattr_setprotocol failed"); | 
 | 180 |       return 1; | 
 | 181 |     } | 
 | 182 | #endif | 
 | 183 |  | 
 | 184 |   for (int round = 1; round <= ROUNDS; ++round) | 
 | 185 |     { | 
 | 186 |       for (int n = 0; n < N; ++n) | 
 | 187 | 	{ | 
 | 188 | 	  int e = pthread_mutex_init (&map[n], &ma); | 
 | 189 | 	  if (e == ENOTSUP) | 
 | 190 | 	    { | 
 | 191 | #ifdef ENABLE_PI | 
 | 192 | 	      puts ("cannot support pshared robust PI mutexes"); | 
 | 193 | #else | 
 | 194 | 	      puts ("cannot support pshared robust mutexes"); | 
 | 195 | #endif | 
 | 196 | 	      return 0; | 
 | 197 | 	    } | 
 | 198 | 	  if (e != 0) | 
 | 199 | 	    { | 
 | 200 | 	      printf ("mutex_init %d in round %d failed\n", n + 1, round); | 
 | 201 | 	      return 1; | 
 | 202 | 	    } | 
 | 203 | 	} | 
 | 204 |  | 
 | 205 |       pid_t p = fork (); | 
 | 206 |       if (p == -1) | 
 | 207 | 	{ | 
 | 208 | 	  printf ("fork in round %d failed\n", round); | 
 | 209 | 	  return 1; | 
 | 210 | 	} | 
 | 211 |       if (p == 0) | 
 | 212 | 	child (round); | 
 | 213 |  | 
 | 214 |       int status; | 
 | 215 |       if (TEMP_FAILURE_RETRY (waitpid (p, &status, 0)) != p) | 
 | 216 | 	{ | 
 | 217 | 	  printf ("waitpid in round %d failed\n", round); | 
 | 218 | 	  return 1; | 
 | 219 | 	} | 
 | 220 |       if (!WIFSIGNALED (status)) | 
 | 221 | 	{ | 
 | 222 | 	  printf ("child did not die of a signal in round %d\n", round); | 
 | 223 | 	  return 1; | 
 | 224 | 	} | 
 | 225 |       if (WTERMSIG (status) != THESIGNAL) | 
 | 226 | 	{ | 
 | 227 | 	  printf ("child did not die of signal %d in round %d\n", | 
 | 228 | 		  THESIGNAL, round); | 
 | 229 | 	  return 1; | 
 | 230 | 	} | 
 | 231 |  | 
 | 232 |       for (int n = 0; n < N; ++n) | 
 | 233 | 	{ | 
 | 234 | 	  int e = pthread_mutex_lock (&map[n]); | 
 | 235 | 	  if (e != 0 && e != EOWNERDEAD) | 
 | 236 | 	    { | 
 | 237 | 	      printf ("mutex_lock %d failed in round %d\n", n + 1, round); | 
 | 238 | 	      return 1; | 
 | 239 | 	    } | 
 | 240 | 	} | 
 | 241 |  | 
 | 242 |       for (int n = 0; n < N; ++n) | 
 | 243 | 	if (pthread_mutex_unlock (&map[n]) != 0) | 
 | 244 | 	  { | 
 | 245 | 	    printf ("mutex_unlock %d failed in round %d\n", n + 1, round); | 
 | 246 | 	    return 1; | 
 | 247 | 	  } | 
 | 248 |  | 
 | 249 |       for (int n = 0; n < N; ++n) | 
 | 250 | 	{ | 
 | 251 | 	  int e = pthread_mutex_destroy (&map[n]); | 
 | 252 | 	  if (e != 0) | 
 | 253 | 	    { | 
 | 254 | 	      printf ("mutex_destroy %d in round %d failed with %d\n", | 
 | 255 | 		      n + 1, round, e); | 
 | 256 | 	      printf("nusers = %d\n", (int) map[n].__data.__nusers); | 
 | 257 | 	      return 1; | 
 | 258 | 	    } | 
 | 259 | 	} | 
 | 260 |     } | 
 | 261 |  | 
 | 262 |   if (pthread_mutexattr_destroy (&ma) != 0) | 
 | 263 |     { | 
 | 264 |       puts ("mutexattr_destroy failed"); | 
 | 265 |       return 1; | 
 | 266 |     } | 
 | 267 |  | 
 | 268 |   if (munmap (map, N * sizeof (pthread_mutex_t)) != 0) | 
 | 269 |     { | 
 | 270 |       puts ("munmap failed"); | 
 | 271 |       return 1; | 
 | 272 |     } | 
 | 273 |  | 
 | 274 |   return 0; | 
 | 275 | } |