1 /* Verify that condition variables synchronized by PI mutexes don't hang.
2    Copyright (C) 2012-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <pthread.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <sys/types.h>
25 #include <sys/syscall.h>
26 #include <unistd.h>
27 #include <sys/time.h>
28 #include <time.h>
29 
30 #define THREADS_NUM 5
31 #define MAXITER 50000
32 
33 static pthread_mutex_t mutex;
34 static pthread_mutexattr_t mutex_attr;
35 static pthread_cond_t cond;
36 static pthread_t threads[THREADS_NUM];
37 static int pending = 0;
38 
39 typedef void * (*threadfunc) (void *);
40 
41 void *
thread_fun_timed(void * arg)42 thread_fun_timed (void *arg)
43 {
44   int *ret = arg;
45   int rv, i;
46 
47   printf ("Started thread_fun_timed[%d]\n", *ret);
48 
49   for (i = 0; i < MAXITER / THREADS_NUM; i++)
50     {
51       rv = pthread_mutex_lock (&mutex);
52       if (rv)
53         {
54 	  printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
55 	  *ret = 1;
56 	  goto out;
57 	}
58 
59       while (!pending)
60 	{
61 	  struct timespec ts;
62 	  clock_gettime(CLOCK_REALTIME, &ts);
63 	  ts.tv_sec += 20;
64 	  rv = pthread_cond_timedwait (&cond, &mutex, &ts);
65 
66 	  /* There should be no timeout either.  */
67 	  if (rv)
68             {
69 	      printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv);
70 	      *ret = 1;
71 	      goto out;
72 	    }
73 	}
74 
75       pending--;
76 
77       rv = pthread_mutex_unlock (&mutex);
78       if (rv)
79         {
80 	  printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
81 	  *ret = 1;
82 	  goto out;
83 	}
84     }
85 
86   *ret = 0;
87 
88 out:
89   return ret;
90 }
91 
92 void *
thread_fun(void * arg)93 thread_fun (void *arg)
94 {
95   int *ret = arg;
96   int rv, i;
97 
98   printf ("Started thread_fun[%d]\n", *ret);
99 
100   for (i = 0; i < MAXITER / THREADS_NUM; i++)
101     {
102       rv = pthread_mutex_lock (&mutex);
103       if (rv)
104         {
105 	  printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
106 	  *ret = 1;
107 	  goto out;
108 	}
109 
110       while (!pending)
111 	{
112 	  rv = pthread_cond_wait (&cond, &mutex);
113 
114 	  if (rv)
115             {
116 	      printf ("pthread_cond_wait: %s(%d)\n", strerror (rv), rv);
117 	      *ret = 1;
118 	      goto out;
119 	    }
120 	}
121 
122       pending--;
123 
124       rv = pthread_mutex_unlock (&mutex);
125       if (rv)
126         {
127 	  printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
128 	  *ret = 1;
129 	  goto out;
130 	}
131     }
132 
133   *ret = 0;
134 
135 out:
136   return ret;
137 }
138 
139 static int
do_test_wait(threadfunc f)140 do_test_wait (threadfunc f)
141 {
142   int i;
143   int rv;
144   int counter = 0;
145   int retval[THREADS_NUM];
146 
147   puts ("Starting test");
148 
149   rv = pthread_mutexattr_init (&mutex_attr);
150   if (rv)
151     {
152       printf ("pthread_mutexattr_init: %s(%d)\n", strerror (rv), rv);
153       return 1;
154     }
155 
156   rv = pthread_mutexattr_setprotocol (&mutex_attr, PTHREAD_PRIO_INHERIT);
157   if (rv)
158     {
159       printf ("pthread_mutexattr_setprotocol: %s(%d)\n", strerror (rv), rv);
160       return 1;
161     }
162 
163   rv = pthread_mutex_init (&mutex, &mutex_attr);
164   if (rv)
165     {
166       printf ("pthread_mutex_init: %s(%d)\n", strerror (rv), rv);
167       return 1;
168     }
169 
170   rv = pthread_cond_init (&cond, NULL);
171   if (rv)
172     {
173       printf ("pthread_cond_init: %s(%d)\n", strerror (rv), rv);
174       return 1;
175     }
176 
177   for (i = 0; i < THREADS_NUM; i++)
178     {
179       retval[i] = i;
180       rv = pthread_create (&threads[i], NULL, f, &retval[i]);
181       if (rv)
182         {
183           printf ("pthread_create: %s(%d)\n", strerror (rv), rv);
184           return 1;
185         }
186     }
187 
188   for (; counter < MAXITER; counter++)
189     {
190       rv = pthread_mutex_lock (&mutex);
191       if (rv)
192         {
193           printf ("pthread_mutex_lock: %s(%d)\n", strerror (rv), rv);
194           return 1;
195         }
196 
197       if (!(counter % 100))
198 	printf ("counter: %d\n", counter);
199       pending += 1;
200 
201       rv = pthread_cond_signal (&cond);
202       if (rv)
203         {
204           printf ("pthread_cond_signal: %s(%d)\n", strerror (rv), rv);
205           return 1;
206         }
207 
208       rv = pthread_mutex_unlock (&mutex);
209       if (rv)
210         {
211           printf ("pthread_mutex_unlock: %s(%d)\n", strerror (rv), rv);
212           return 1;
213         }
214     }
215 
216   for (i = 0; i < THREADS_NUM; i++)
217     {
218       void *ret;
219       rv = pthread_join (threads[i], &ret);
220       if (rv)
221         {
222           printf ("pthread_join: %s(%d)\n", strerror (rv), rv);
223           return 1;
224         }
225       if (ret && *(int *)ret)
226         {
227 	  printf ("Thread %d returned with an error\n", i);
228 	  return 1;
229 	}
230     }
231 
232   return 0;
233 }
234 
235 static int
do_test(void)236 do_test (void)
237 {
238   puts ("Testing pthread_cond_wait");
239   int ret = do_test_wait (thread_fun);
240   if (ret)
241     return ret;
242 
243   puts ("Testing pthread_cond_timedwait");
244   return do_test_wait (thread_fun_timed);
245 }
246 
247 #define TEST_FUNCTION do_test ()
248 #include "../test-skeleton.c"
249