1 /* Test program for timedout read/write lock functions.
2    Copyright (C) 2000-2022 Free Software Foundation, Inc.
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 License as
6    published by the Free Software Foundation; either version 2.1 of the
7    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; see the file COPYING.LIB.  If
16    not, see <https://www.gnu.org/licenses/>.  */
17 
18 #include <errno.h>
19 #include <error.h>
20 #include <pthread.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <time.h>
24 #include <unistd.h>
25 
26 
27 #define NWRITERS 15
28 #define WRITETRIES 10
29 #define NREADERS 15
30 #define READTRIES 15
31 
32 #define DELAY   1000000
33 
34 #ifndef KIND
35 # define KIND PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
36 #endif
37 
38 static pthread_rwlock_t lock;
39 
40 
41 static void *
writer_thread(void * nr)42 writer_thread (void *nr)
43 {
44   struct timespec delay;
45   int n;
46 
47   delay.tv_sec = 0;
48   delay.tv_nsec = DELAY;
49 
50   for (n = 0; n < WRITETRIES; ++n)
51     {
52       printf ("writer thread %ld tries again\n", (long int) nr);
53 
54       if (pthread_rwlock_wrlock (&lock) != 0)
55 	{
56 	  puts ("wrlock failed");
57 	  exit (1);
58 	}
59 
60       printf ("writer thread %ld succeeded\n", (long int) nr);
61 
62       nanosleep (&delay, NULL);
63 
64       if (pthread_rwlock_unlock (&lock) != 0)
65 	{
66 	  puts ("unlock for writer failed");
67 	  exit (1);
68 	}
69 
70       printf ("writer thread %ld released\n", (long int) nr);
71     }
72 
73   return NULL;
74 }
75 
76 
77 static void *
reader_thread(void * nr)78 reader_thread (void *nr)
79 {
80   struct timespec delay;
81   int n;
82 
83   delay.tv_sec = 0;
84   delay.tv_nsec = DELAY;
85 
86   for (n = 0; n < READTRIES; ++n)
87     {
88       printf ("reader thread %ld tries again\n", (long int) nr);
89 
90       if (pthread_rwlock_rdlock (&lock) != 0)
91 	{
92 	  puts ("rdlock failed");
93 	  exit (1);
94 	}
95 
96       printf ("reader thread %ld succeeded\n", (long int) nr);
97 
98       nanosleep (&delay, NULL);
99 
100       if (pthread_rwlock_unlock (&lock) != 0)
101 	{
102 	  puts ("unlock for reader failed");
103 	  exit (1);
104 	}
105 
106       printf ("reader thread %ld released\n", (long int) nr);
107     }
108 
109   return NULL;
110 }
111 
112 
113 static int
do_test(void)114 do_test (void)
115 {
116   pthread_t thwr[NWRITERS];
117   pthread_t thrd[NREADERS];
118   int n;
119   void *res;
120   pthread_rwlockattr_t a;
121 
122   if (pthread_rwlockattr_init (&a) != 0)
123     {
124       puts ("rwlockattr_t failed");
125       exit (1);
126     }
127 
128   if (pthread_rwlockattr_setkind_np (&a, KIND) != 0)
129     {
130       puts ("rwlockattr_setkind failed");
131       exit (1);
132     }
133 
134   if (pthread_rwlock_init (&lock, &a) != 0)
135     {
136       puts ("rwlock_init failed");
137       exit (1);
138     }
139 
140   /* Make standard error the same as standard output.  */
141   dup2 (1, 2);
142 
143   /* Make sure we see all message, even those on stdout.  */
144   setvbuf (stdout, NULL, _IONBF, 0);
145 
146   for (n = 0; n < NWRITERS; ++n)
147     if (pthread_create (&thwr[n], NULL, writer_thread,
148 			(void *) (long int) n) != 0)
149       {
150 	puts ("writer create failed");
151 	exit (1);
152       }
153 
154   for (n = 0; n < NREADERS; ++n)
155     if (pthread_create (&thrd[n], NULL, reader_thread,
156 			(void *) (long int) n) != 0)
157       {
158 	puts ("reader create failed");
159 	exit (1);
160       }
161 
162   /* Wait for all the threads.  */
163   for (n = 0; n < NWRITERS; ++n)
164     if (pthread_join (thwr[n], &res) != 0)
165       {
166 	puts ("writer join failed");
167 	exit (1);
168       }
169   for (n = 0; n < NREADERS; ++n)
170     if (pthread_join (thrd[n], &res) != 0)
171       {
172 	puts ("reader join failed");
173 	exit (1);
174       }
175 
176   return 0;
177 }
178 
179 #define TIMEOUT 30
180 #define TEST_FUNCTION do_test ()
181 #include "../test-skeleton.c"
182