(root)/
glibc-2.38/
sysdeps/
pthread/
tst-rwlock16.c
       1  /* Copyright (C) 2015-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  /* This tests that with a reader-preferring rwlock, all readers are woken if
      19     one reader "steals" lock ownership from a blocked writer.  */
      20  
      21  #include <errno.h>
      22  #include <pthread.h>
      23  #include <stdio.h>
      24  #include <stdlib.h>
      25  #include <semaphore.h>
      26  #include <unistd.h>
      27  
      28  /* If we strictly prefer writers over readers, a program must not expect
      29     that, in the presence of concurrent writers, one reader will also acquire
      30     the lock when another reader has already done so.  Thus, use the
      31     default rwlock type that does not strictly prefer writers.  */
      32  static pthread_rwlock_t r = PTHREAD_RWLOCK_INITIALIZER;
      33  
      34  static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
      35  static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
      36  
      37  /* Avoid using glibc-internal atomic operations.  */
      38  static sem_t stop;
      39  static int consumer_stop = 0;
      40  
      41  static void *
      42  writer (void *arg)
      43  {
      44    int s;
      45  
      46    do
      47      {
      48        if (pthread_rwlock_wrlock (&r) != 0)
      49  	{
      50  	  puts ("wrlock failed");
      51  	  exit (EXIT_FAILURE);
      52  	}
      53        if (pthread_rwlock_unlock (&r) != 0)
      54  	{
      55  	  puts ("unlock failed");
      56  	  exit (EXIT_FAILURE);
      57  	}
      58        sem_getvalue (&stop, &s);
      59      }
      60    while (s == 0);
      61    return NULL;
      62  }
      63  
      64  static void *
      65  reader_producer (void *arg)
      66  {
      67    int s;
      68  
      69    do
      70      {
      71        if (pthread_rwlock_rdlock (&r) != 0)
      72  	{
      73  	  puts ("rdlock reader failed");
      74  	  exit (EXIT_FAILURE);
      75  	}
      76  
      77        sem_getvalue (&stop, &s);
      78  
      79        pthread_mutex_lock (&m);
      80        if (s != 0)
      81  	consumer_stop = 1;
      82        pthread_cond_signal (&cv);
      83        pthread_mutex_unlock (&m);
      84  
      85        if (pthread_rwlock_unlock (&r) != 0)
      86  	{
      87  	  puts ("unlock reader failed");
      88  	  exit (EXIT_FAILURE);
      89  	}
      90      }
      91    while (s == 0);
      92    puts ("producer finished");
      93    return NULL;
      94  }
      95  
      96  static void *
      97  reader_consumer (void *arg)
      98  {
      99    int s;
     100  
     101    do
     102      {
     103        if (pthread_rwlock_rdlock (&r) != 0)
     104  	{
     105  	  puts ("rdlock reader failed");
     106  	  exit (EXIT_FAILURE);
     107  	}
     108  
     109        pthread_mutex_lock (&m);
     110        s = consumer_stop;
     111        if (s == 0)
     112  	pthread_cond_wait (&cv, &m);
     113        pthread_mutex_unlock (&m);
     114  
     115        if (pthread_rwlock_unlock (&r) != 0)
     116  	{
     117  	  puts ("unlock reader failed");
     118  	  exit (EXIT_FAILURE);
     119  	}
     120      }
     121    while (s == 0);
     122      puts ("consumer finished");
     123    return NULL;
     124  }
     125  
     126  
     127  static int
     128  do_test (void)
     129  {
     130    pthread_t w1, w2, rp, rc;
     131  
     132    if (pthread_create (&w1, NULL, writer, NULL) != 0)
     133      {
     134        puts ("create failed");
     135        return 1;
     136      }
     137    if (pthread_create (&w2, NULL, writer, NULL) != 0)
     138      {
     139        puts ("create failed");
     140        return 1;
     141      }
     142    if (pthread_create (&rc, NULL, reader_consumer, NULL) != 0)
     143      {
     144        puts ("create failed");
     145        return 1;
     146      }
     147    if (pthread_create (&rp, NULL, reader_producer, NULL) != 0)
     148      {
     149        puts ("create failed");
     150        return 1;
     151      }
     152  
     153    sleep (2);
     154    sem_post (&stop);
     155  
     156    if (pthread_join (w1, NULL) != 0)
     157      {
     158        puts ("w1 join failed");
     159        return 1;
     160      }
     161    if (pthread_join (w2, NULL) != 0)
     162      {
     163        puts ("w2 join failed");
     164        return 1;
     165      }
     166    if (pthread_join (rp, NULL) != 0)
     167      {
     168        puts ("reader_producer join failed");
     169        return 1;
     170      }
     171    if (pthread_join (rc, NULL) != 0)
     172      {
     173        puts ("reader_consumer join failed");
     174        return 1;
     175      }
     176  
     177    return 0;
     178  }
     179  
     180  
     181  #define TEST_FUNCTION do_test ()
     182  #include "../test-skeleton.c"