1 /* Copyright (C) 2002-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 <errno.h>
19 #include <pthread.h>
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/mman.h>
26 #include <sys/wait.h>
27 
28 
29 static int
do_test(void)30 do_test (void)
31 {
32   size_t ps = sysconf (_SC_PAGESIZE);
33   char tmpfname[] = "/tmp/tst-mutex4.XXXXXX";
34   char data[ps];
35   void *mem;
36   int fd;
37   pthread_mutex_t *m;
38   pthread_mutexattr_t a;
39   pid_t pid;
40   char *p;
41   int err;
42   int s;
43   pthread_barrier_t *b;
44   pthread_barrierattr_t ba;
45 
46   fd = mkstemp (tmpfname);
47   if (fd == -1)
48     {
49       printf ("cannot open temporary file: %m\n");
50       return 1;
51     }
52 
53   /* Make sure it is always removed.  */
54   unlink (tmpfname);
55 
56   /* Create one page of data.  */
57   memset (data, '\0', ps);
58 
59   /* Write the data to the file.  */
60   if (write (fd, data, ps) != (ssize_t) ps)
61     {
62       puts ("short write");
63       return 1;
64     }
65 
66   mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
67   if (mem == MAP_FAILED)
68     {
69       printf ("mmap failed: %m\n");
70       return 1;
71     }
72 
73   m = (pthread_mutex_t *) (((uintptr_t) mem + __alignof (pthread_mutex_t) - 1)
74 			   & ~(__alignof (pthread_mutex_t) - 1));
75   b = (pthread_barrier_t *) (((uintptr_t) (m + 1)
76 			      + __alignof (pthread_barrier_t) - 1)
77 			     & ~(__alignof (pthread_barrier_t) - 1));
78   p = (char *) (b + 1);
79 
80   if (pthread_mutexattr_init (&a) != 0)
81     {
82       puts ("mutexattr_init failed");
83       return 1;
84     }
85 
86   if (pthread_mutexattr_getpshared (&a, &s) != 0)
87     {
88       puts ("1st mutexattr_getpshared failed");
89       return 1;
90     }
91 
92   if (s != PTHREAD_PROCESS_PRIVATE)
93     {
94       puts ("default pshared value wrong");
95       return 1;
96     }
97 
98   if (pthread_mutexattr_setpshared (&a, PTHREAD_PROCESS_SHARED) != 0)
99     {
100       puts ("mutexattr_setpshared failed");
101       return 1;
102     }
103 
104   if (pthread_mutexattr_getpshared (&a, &s) != 0)
105     {
106       puts ("2nd mutexattr_getpshared failed");
107       return 1;
108     }
109 
110   if (s != PTHREAD_PROCESS_SHARED)
111     {
112       puts ("pshared value after setpshared call wrong");
113       return 1;
114     }
115 
116 #ifdef ENABLE_PI
117   if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0)
118     {
119       puts ("pthread_mutexattr_setprotocol failed");
120       return 1;
121     }
122 #endif
123 
124   if ((err = pthread_mutex_init (m, &a)) != 0)
125     {
126 #ifdef ENABLE_PI
127       if (err == ENOTSUP)
128 	{
129 	  puts ("PI mutexes unsupported");
130 	  return 0;
131 	}
132 #endif
133       puts ("mutex_init failed");
134       return 1;
135     }
136 
137   if (pthread_mutex_lock (m) != 0)
138     {
139       puts ("mutex_lock failed");
140       return 1;
141     }
142 
143   if (pthread_mutexattr_destroy (&a) != 0)
144     {
145       puts ("mutexattr_destroy failed");
146       return 1;
147     }
148 
149   if (pthread_barrierattr_init (&ba) != 0)
150     {
151       puts ("barrierattr_init failed");
152       return 1;
153     }
154 
155   if (pthread_barrierattr_setpshared (&ba, PTHREAD_PROCESS_SHARED) != 0)
156     {
157       puts ("barrierattr_setpshared failed");
158       return 1;
159     }
160 
161   if (pthread_barrier_init (b, &ba, 2) != 0)
162     {
163       puts ("barrier_init failed");
164       return 1;
165     }
166 
167   if (pthread_barrierattr_destroy (&ba) != 0)
168     {
169       puts ("barrierattr_destroy failed");
170       return 1;
171     }
172 
173   err = pthread_mutex_trylock (m);
174   if (err == 0)
175     {
176       puts ("mutex_trylock succeeded");
177       return 1;
178     }
179   else if (err != EBUSY)
180     {
181       puts ("mutex_trylock didn't return EBUSY");
182       return 1;
183     }
184 
185   *p = 0;
186 
187   if (pthread_mutex_unlock (m) != 0)
188     {
189       puts ("parent: 1st mutex_unlock failed");
190       return 1;
191     }
192 
193   puts ("going to fork now");
194   pid = fork ();
195   if (pid == -1)
196     {
197       puts ("fork failed");
198       return 1;
199     }
200   else if (pid == 0)
201     {
202       if (pthread_mutex_lock (m) != 0)
203 	{
204 	  puts ("child: mutex_lock failed");
205 	  return 1;
206 	}
207 
208       int e = pthread_barrier_wait (b);
209       if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
210 	{
211 	  puts ("child: barrier_wait failed");
212 	  return 1;
213 	}
214 
215       if ((*p)++ != 0)
216 	{
217 	  puts ("child: *p != 0");
218 	  return 1;
219 	}
220 
221       if (pthread_mutex_unlock (m) != 0)
222 	{
223 	  puts ("child: mutex_unlock failed");
224 	  return 1;
225 	}
226 
227       puts ("child done");
228     }
229   else
230     {
231       int e = pthread_barrier_wait (b);
232       if (e != 0 && e != PTHREAD_BARRIER_SERIAL_THREAD)
233 	{
234 	  puts ("parent: barrier_wait failed");
235 	  return 1;
236 	}
237 
238       if (pthread_mutex_lock (m) != 0)
239 	{
240 	  puts ("parent: 2nd mutex_lock failed");
241 	  return 1;
242 	}
243 
244       if (*p != 1)
245 	{
246 	  puts ("*p != 1");
247 	  return 1;
248 	}
249 
250       if (pthread_mutex_unlock (m) != 0)
251 	{
252 	  puts ("parent: 2nd mutex_unlock failed");
253 	  return 1;
254 	}
255 
256       if (pthread_mutex_destroy (m) != 0)
257 	{
258 	  puts ("mutex_destroy failed");
259 	  return 1;
260 	}
261 
262       if (pthread_barrier_destroy (b) != 0)
263 	{
264 	  puts ("barrier_destroy failed");
265 	  return 1;
266 	}
267 
268       puts ("parent done");
269     }
270 
271   return 0;
272 }
273 
274 #define TEST_FUNCTION do_test ()
275 #include "../test-skeleton.c"
276