(root)/
glibc-2.38/
sysdeps/
pthread/
tst-rwlock12.c
       1  /* Copyright (C) 2002-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <pthread.h>
      20  #include <stdint.h>
      21  #include <stdio.h>
      22  #include <stdlib.h>
      23  #include <string.h>
      24  #include <unistd.h>
      25  #include <sys/mman.h>
      26  #include <sys/wait.h>
      27  
      28  
      29  static int
      30  do_test (void)
      31  {
      32    size_t ps = sysconf (_SC_PAGESIZE);
      33    char tmpfname[] = "/tmp/tst-rwlock12.XXXXXX";
      34    char data[ps];
      35    void *mem;
      36    int fd;
      37    pthread_mutex_t *m;
      38    pthread_mutexattr_t ma;
      39    pthread_rwlock_t *r;
      40    pthread_rwlockattr_t ra;
      41    pid_t pid;
      42    int status = 0;
      43  
      44    fd = mkstemp (tmpfname);
      45    if (fd == -1)
      46      {
      47        printf ("cannot open temporary file: %m\n");
      48        return 1;
      49      }
      50  
      51    /* Make sure it is always removed.  */
      52    unlink (tmpfname);
      53  
      54    /* Create one page of data.  */
      55    memset (data, '\0', ps);
      56  
      57    /* Write the data to the file.  */
      58    if (write (fd, data, ps) != (ssize_t) ps)
      59      {
      60        puts ("short write");
      61        return 1;
      62      }
      63  
      64    mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
      65    if (mem == MAP_FAILED)
      66      {
      67        printf ("mmap failed: %m\n");
      68        return 1;
      69      }
      70  
      71    r = (pthread_rwlock_t *) (((uintptr_t) mem + __alignof (pthread_rwlock_t))
      72  			    & ~(__alignof (pthread_rwlock_t) - 1));
      73    /* The following assumes alignment for a mutex is at least as high
      74       as that for a rwlock.  Which is true in our case.  */
      75    m = (pthread_mutex_t *) (r + 1);
      76  
      77    if (pthread_rwlockattr_init (&ra) != 0)
      78      {
      79        puts ("rwlockattr_init failed");
      80        return 1;
      81      }
      82  
      83    if (pthread_rwlockattr_setpshared (&ra, PTHREAD_PROCESS_SHARED) != 0)
      84      {
      85        puts ("rwlockattr_setpshared failed");
      86        return 1;
      87      }
      88  
      89    if (pthread_rwlock_init (r, &ra) != 0)
      90      {
      91        puts ("rwlock_init failed");
      92        return 1;
      93      }
      94  
      95    if (pthread_mutexattr_init (&ma) != 0)
      96      {
      97        puts ("rwlockattr_init failed");
      98        return 1;
      99      }
     100  
     101    if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0)
     102      {
     103        puts ("mutexattr_setpshared failed");
     104        return 1;
     105      }
     106  
     107    if (pthread_mutex_init (m, &ma) != 0)
     108      {
     109        puts ("mutex_init failed");
     110        return 1;
     111      }
     112  
     113    /* Lock the mutex.  */
     114    if (pthread_mutex_lock (m) != 0)
     115      {
     116        puts ("mutex_lock failed");
     117        return 1;
     118      }
     119  
     120    puts ("going to fork now");
     121    pid = fork ();
     122    if (pid == -1)
     123      {
     124        puts ("fork failed");
     125        return 1;
     126      }
     127    else if (pid == 0)
     128      {
     129        /* Lock the mutex.  */
     130        if (pthread_mutex_lock (m) != 0)
     131  	{
     132  	  puts ("child: mutex_lock failed");
     133  	  return 1;
     134  	}
     135  
     136        /* Try to get the rwlock.  */
     137        if (pthread_rwlock_trywrlock (r) == 0)
     138  	{
     139  	  puts ("rwlock_trywrlock succeeded");
     140  	  return 1;
     141  	}
     142  
     143        /* Try again.  */
     144        struct timespec ts = { .tv_sec = 0, .tv_nsec = 500000000 };
     145        int e = pthread_rwlock_timedwrlock (r, &ts);
     146        if (e == 0)
     147  	{
     148  	  puts ("rwlock_timedwrlock succeeded");
     149  	  return 1;
     150  	}
     151        if (e != ETIMEDOUT)
     152  	{
     153  	  puts ("rwlock_timedwrlock didn't return ETIMEDOUT");
     154  	  status = 1;
     155  	}
     156  
     157        if (pthread_rwlock_tryrdlock (r) == 0)
     158  	{
     159  	  puts ("rwlock_tryrdlock succeeded");
     160  	  return 1;
     161  	}
     162  
     163        e = pthread_rwlock_timedrdlock (r, &ts);
     164        if (e == 0)
     165  	{
     166  	  puts ("rwlock_timedrdlock succeeded");
     167  	  return 1;
     168  	}
     169        if (e != ETIMEDOUT)
     170  	{
     171  	  puts ("rwlock_timedrdlock didn't return ETIMEDOUT");
     172  	  status = 1;
     173  	}
     174      }
     175    else
     176      {
     177        /* Lock the rwlock for writing.  */
     178        if (pthread_rwlock_wrlock (r) != 0)
     179  	{
     180  	  puts ("rwlock_wrlock failed");
     181  	  kill (pid, SIGTERM);
     182  	  return 1;
     183  	}
     184  
     185        /* Allow the child to run.  */
     186        if (pthread_mutex_unlock (m) != 0)
     187  	{
     188  	  puts ("mutex_unlock failed");
     189  	  kill (pid, SIGTERM);
     190  	  return 1;
     191  	}
     192  
     193        /* Just wait for the child.  */
     194        if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
     195  	{
     196  	  puts ("waitpid failed");
     197  	  kill (pid, SIGTERM);
     198  	  return 1;
     199  	}
     200      }
     201  
     202    return status;
     203  }
     204  
     205  #define TEST_FUNCTION do_test ()
     206  #include "../test-skeleton.c"