(root)/
glibc-2.38/
sysdeps/
pthread/
tst-rwlock4.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-rwlock4.XXXXXX";
      34    char data[ps];
      35    void *mem;
      36    int fd;
      37    pthread_rwlock_t *r;
      38    pthread_rwlockattr_t a;
      39    pid_t pid;
      40    char *p;
      41    int err;
      42    int s;
      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    p = (char *) (r + 1);
      74  
      75    if (pthread_rwlockattr_init (&a) != 0)
      76      {
      77        puts ("rwlockattr_init failed");
      78        return 1;
      79      }
      80  
      81    if (pthread_rwlockattr_getpshared (&a, &s) != 0)
      82      {
      83        puts ("1st rwlockattr_getpshared failed");
      84        return 1;
      85      }
      86  
      87    if (s != PTHREAD_PROCESS_PRIVATE)
      88      {
      89        puts ("default pshared value wrong");
      90        return 1;
      91      }
      92  
      93    if (pthread_rwlockattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
      94      {
      95        puts ("rwlockattr_setpshared failed");
      96        return 1;
      97      }
      98  
      99    if (pthread_rwlockattr_getpshared (&a, &s) != 0)
     100      {
     101        puts ("2nd rwlockattr_getpshared failed");
     102        return 1;
     103      }
     104  
     105    if (s != PTHREAD_PROCESS_SHARED)
     106      {
     107        puts ("pshared value after setpshared call wrong");
     108        return 1;
     109      }
     110  
     111    if (pthread_rwlock_init (r, &a) != 0)
     112      {
     113        puts ("rwlock_init failed");
     114        return 1;
     115      }
     116  
     117    if (pthread_rwlock_rdlock (r) != 0)
     118      {
     119        puts ("rwlock_rdlock failed");
     120        return 1;
     121      }
     122  
     123    if (pthread_rwlockattr_destroy (&a) != 0)
     124      {
     125        puts ("rwlockattr_destroy failed");
     126        return 1;
     127      }
     128  
     129    err = pthread_rwlock_trywrlock (r);
     130    if (err == 0)
     131      {
     132        puts ("rwlock_trywrlock succeeded");
     133        return 1;
     134      }
     135    else if (err != EBUSY)
     136      {
     137        puts ("rwlock_trywrlock didn't return EBUSY");
     138        return 1;
     139      }
     140  
     141    *p = 0;
     142  
     143    puts ("going to fork now");
     144    pid = fork ();
     145    if (pid == -1)
     146      {
     147        puts ("fork failed");
     148        return 1;
     149      }
     150    else if (pid == 0)
     151      {
     152        /* Play some lock ping-pong.  It's our turn to unlock first.  */
     153        if ((*p)++ != 0)
     154  	{
     155  	  puts ("child: *p != 0");
     156  	  return 1;
     157  	}
     158  
     159        if (pthread_rwlock_unlock (r) != 0)
     160  	{
     161  	  puts ("child: 1st rwlock_unlock failed");
     162  	  return 1;
     163  	}
     164  
     165        puts ("child done");
     166      }
     167    else
     168      {
     169        if (pthread_rwlock_wrlock (r) != 0)
     170  	{
     171  	  puts ("parent: rwlock_wrlock failed");
     172  	  return 1;
     173  	}
     174  
     175        if (*p != 1)
     176  	{
     177  	  puts ("*p != 1");
     178  	  return 1;
     179  	}
     180  
     181        puts ("parent done");
     182      }
     183  
     184    return 0;
     185  }
     186  
     187  #define TEST_FUNCTION do_test ()
     188  #include "../test-skeleton.c"