1/* Copyright (C) 2015-2024 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. */
32static pthread_rwlock_t r = PTHREAD_RWLOCK_INITIALIZER;
33
34static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
35static pthread_cond_t cv = PTHREAD_COND_INITIALIZER;
36
37/* Avoid using glibc-internal atomic operations. */
38static sem_t stop;
39static int consumer_stop = 0;
40
41static void *
42writer (void *arg)
43{
44 int s;
45
46 do
47 {
48 if (pthread_rwlock_wrlock (rwlock: &r) != 0)
49 {
50 puts (s: "wrlock failed");
51 exit (EXIT_FAILURE);
52 }
53 if (pthread_rwlock_unlock (rwlock: &r) != 0)
54 {
55 puts (s: "unlock failed");
56 exit (EXIT_FAILURE);
57 }
58 sem_getvalue (sem: &stop, sval: &s);
59 }
60 while (s == 0);
61 return NULL;
62}
63
64static void *
65reader_producer (void *arg)
66{
67 int s;
68
69 do
70 {
71 if (pthread_rwlock_rdlock (rwlock: &r) != 0)
72 {
73 puts (s: "rdlock reader failed");
74 exit (EXIT_FAILURE);
75 }
76
77 sem_getvalue (sem: &stop, sval: &s);
78
79 pthread_mutex_lock (mutex: &m);
80 if (s != 0)
81 consumer_stop = 1;
82 pthread_cond_signal (cond: &cv);
83 pthread_mutex_unlock (mutex: &m);
84
85 if (pthread_rwlock_unlock (rwlock: &r) != 0)
86 {
87 puts (s: "unlock reader failed");
88 exit (EXIT_FAILURE);
89 }
90 }
91 while (s == 0);
92 puts (s: "producer finished");
93 return NULL;
94}
95
96static void *
97reader_consumer (void *arg)
98{
99 int s;
100
101 do
102 {
103 if (pthread_rwlock_rdlock (rwlock: &r) != 0)
104 {
105 puts (s: "rdlock reader failed");
106 exit (EXIT_FAILURE);
107 }
108
109 pthread_mutex_lock (mutex: &m);
110 s = consumer_stop;
111 if (s == 0)
112 pthread_cond_wait (cond: &cv, mutex: &m);
113 pthread_mutex_unlock (mutex: &m);
114
115 if (pthread_rwlock_unlock (rwlock: &r) != 0)
116 {
117 puts (s: "unlock reader failed");
118 exit (EXIT_FAILURE);
119 }
120 }
121 while (s == 0);
122 puts (s: "consumer finished");
123 return NULL;
124}
125
126
127static int
128do_test (void)
129{
130 pthread_t w1, w2, rp, rc;
131
132 if (pthread_create (newthread: &w1, NULL, start_routine: writer, NULL) != 0)
133 {
134 puts (s: "create failed");
135 return 1;
136 }
137 if (pthread_create (newthread: &w2, NULL, start_routine: writer, NULL) != 0)
138 {
139 puts (s: "create failed");
140 return 1;
141 }
142 if (pthread_create (newthread: &rc, NULL, start_routine: reader_consumer, NULL) != 0)
143 {
144 puts (s: "create failed");
145 return 1;
146 }
147 if (pthread_create (newthread: &rp, NULL, start_routine: reader_producer, NULL) != 0)
148 {
149 puts (s: "create failed");
150 return 1;
151 }
152
153 sleep (seconds: 2);
154 sem_post (sem: &stop);
155
156 if (pthread_join (th: w1, NULL) != 0)
157 {
158 puts (s: "w1 join failed");
159 return 1;
160 }
161 if (pthread_join (th: w2, NULL) != 0)
162 {
163 puts (s: "w2 join failed");
164 return 1;
165 }
166 if (pthread_join (th: rp, NULL) != 0)
167 {
168 puts (s: "reader_producer join failed");
169 return 1;
170 }
171 if (pthread_join (th: rc, NULL) != 0)
172 {
173 puts (s: "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"
183

source code of glibc/sysdeps/pthread/tst-rwlock16.c