1 /* Copyright (C) 2004-2022 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 <pthread.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 
24 #define N 10
25 #define ROUNDS 1000
26 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
27 static pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER;
28 static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
29 static pthread_barrier_t b;
30 static int count;
31 
32 static void *
tf(void * p)33 tf (void *p)
34 {
35   int i;
36   for (i = 0; i < ROUNDS; ++i)
37     {
38       pthread_mutex_lock (&mut);
39 
40       if (++count == N)
41 	pthread_cond_signal (&cond2);
42 
43 #ifdef TIMED
44       struct timeval tv;
45       gettimeofday (&tv, NULL);
46       struct timespec ts;
47       /* Wait three seconds.  */
48       ts.tv_sec = tv.tv_sec + 3;
49       ts.tv_nsec = tv.tv_usec * 1000;
50       pthread_cond_timedwait (&cond, &mut, &ts);
51 #else
52       pthread_cond_wait (&cond, &mut);
53 #endif
54 
55       pthread_mutex_unlock (&mut);
56 
57       int err = pthread_barrier_wait (&b);
58       if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
59 	{
60 	  puts ("child: barrier_wait failed");
61 	  exit (1);
62 	}
63 
64       err = pthread_barrier_wait (&b);
65       if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
66 	{
67 	  puts ("child: barrier_wait failed");
68 	  exit (1);
69 	}
70     }
71 
72   return NULL;
73 }
74 
75 
76 static int
do_test(void)77 do_test (void)
78 {
79   if (pthread_barrier_init (&b, NULL, N + 1) != 0)
80     {
81       puts ("barrier_init failed");
82       return 1;
83     }
84 
85   pthread_mutex_lock (&mut);
86 
87   int i, j, err;
88   pthread_t th[N];
89   for (i = 0; i < N; ++i)
90     if ((err = pthread_create (&th[i], NULL, tf, NULL)) != 0)
91       {
92 	printf ("cannot create thread %d: %s\n", i, strerror (err));
93 	return 1;
94       }
95 
96   for (i = 0; i < ROUNDS; ++i)
97     {
98       /* Make sure we discard spurious wake-ups.  */
99       do
100 	pthread_cond_wait (&cond2, &mut);
101       while (count != N);
102 
103       if (i & 1)
104         pthread_mutex_unlock (&mut);
105 
106       if (i & 2)
107 	pthread_cond_broadcast (&cond);
108       else if (i & 4)
109 	for (j = 0; j < N; ++j)
110 	  pthread_cond_signal (&cond);
111       else
112 	{
113 	  for (j = 0; j < (i / 8) % N; ++j)
114 	    pthread_cond_signal (&cond);
115 	  pthread_cond_broadcast (&cond);
116 	}
117 
118       if ((i & 1) == 0)
119         pthread_mutex_unlock (&mut);
120 
121       err = pthread_cond_destroy (&cond);
122       if (err)
123 	{
124 	  printf ("pthread_cond_destroy failed: %s\n", strerror (err));
125 	  return 1;
126 	}
127 
128       /* Now clobber the cond variable which has been successfully
129          destroyed above.  */
130       memset (&cond, (char) i, sizeof (cond));
131 
132       err = pthread_barrier_wait (&b);
133       if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
134 	{
135 	  puts ("parent: barrier_wait failed");
136 	  return 1;
137 	}
138 
139       pthread_mutex_lock (&mut);
140 
141       err = pthread_barrier_wait (&b);
142       if (err != 0 && err != PTHREAD_BARRIER_SERIAL_THREAD)
143 	{
144 	  puts ("parent: barrier_wait failed");
145 	  return 1;
146 	}
147 
148       count = 0;
149       err = pthread_cond_init (&cond, NULL);
150       if (err)
151 	{
152 	  printf ("pthread_cond_init failed: %s\n", strerror (err));
153 	  return 1;
154 	}
155     }
156 
157   for (i = 0; i < N; ++i)
158     if ((err = pthread_join (th[i], NULL)) != 0)
159       {
160 	printf ("failed to join thread %d: %s\n", i, strerror (err));
161 	return 1;
162       }
163 
164   puts ("done");
165 
166   return 0;
167 }
168 
169 
170 #define TEST_FUNCTION do_test ()
171 #include "../test-skeleton.c"
172