(root)/
glibc-2.38/
sysdeps/
pthread/
tst-robust8.c
       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  #include <pthreadP.h>
      12  
      13  
      14  
      15  static void prepare (void);
      16  #define PREPARE(argc, argv) prepare ()
      17  static int do_test (void);
      18  #define TEST_FUNCTION do_test ()
      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 (&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 (&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  #ifdef __PTHREAD_NPTL
     257  	      printf("nusers = %d\n", (int) map[n].__data.__nusers);
     258  #endif
     259  	      return 1;
     260  	    }
     261  	}
     262      }
     263  
     264    if (pthread_mutexattr_destroy (&ma) != 0)
     265      {
     266        puts ("mutexattr_destroy failed");
     267        return 1;
     268      }
     269  
     270    if (munmap (map, N * sizeof (pthread_mutex_t)) != 0)
     271      {
     272        puts ("munmap failed");
     273        return 1;
     274      }
     275  
     276    return 0;
     277  }