1 /* Copyright (C) 2003-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 <signal.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <sys/mman.h>
25 #include <sys/wait.h>
26 
27 
28 static char fname[] = "/tmp/tst-cond12-XXXXXX";
29 static int fd;
30 
31 
32 static void prepare (void);
33 #define PREPARE(argc, argv) prepare ()
34 
35 static int do_test (void);
36 #define TEST_FUNCTION do_test ()
37 
38 #include "../test-skeleton.c"
39 
40 
41 static void
prepare(void)42 prepare (void)
43 {
44   fd = mkstemp (fname);
45   if (fd == -1)
46     {
47       printf ("mkstemp failed: %m\n");
48       exit (1);
49     }
50   add_temp_file (fname);
51   if (ftruncate (fd, 1000) < 0)
52     {
53       printf ("ftruncate failed: %m\n");
54       exit (1);
55     }
56 }
57 
58 
59 static int
do_test(void)60 do_test (void)
61 {
62   struct
63   {
64     pthread_mutex_t m;
65     pthread_cond_t c;
66     int var;
67   } *p = mmap (NULL, sizeof (*p), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
68   if (p == MAP_FAILED)
69     {
70       printf ("initial mmap failed: %m\n");
71       return 1;
72     }
73 
74   pthread_mutexattr_t ma;
75   if (pthread_mutexattr_init (&ma) != 0)
76     {
77       puts ("mutexattr_init failed");
78       return 1;
79     }
80   if (pthread_mutexattr_setpshared (&ma, 1) != 0)
81     {
82       puts ("mutexattr_setpshared failed");
83       return 1;
84     }
85   if (pthread_mutex_init (&p->m, &ma) != 0)
86     {
87       puts ("mutex_init failed");
88       return 1;
89     }
90   if (pthread_mutexattr_destroy (&ma) != 0)
91     {
92       puts ("mutexattr_destroy failed");
93       return 1;
94     }
95 
96   pthread_condattr_t ca;
97   if (pthread_condattr_init (&ca) != 0)
98     {
99       puts ("condattr_init failed");
100       return 1;
101     }
102   if (pthread_condattr_setpshared (&ca, 1) != 0)
103     {
104       puts ("condattr_setpshared failed");
105       return 1;
106     }
107   if (pthread_cond_init (&p->c, &ca) != 0)
108     {
109       puts ("mutex_init failed");
110       return 1;
111     }
112   if (pthread_condattr_destroy (&ca) != 0)
113     {
114       puts ("condattr_destroy failed");
115       return 1;
116     }
117 
118   if (pthread_mutex_lock (&p->m) != 0)
119     {
120       puts ("initial mutex_lock failed");
121       return 1;
122     }
123 
124   p->var = 42;
125 
126   pid_t pid = fork ();
127   if (pid == -1)
128     {
129       printf ("fork failed: %m\n");
130       return 1;
131     }
132 
133   if (pid == 0)
134     {
135       void *oldp = p;
136       p = mmap (NULL, sizeof (*p), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
137 
138       if (p == oldp)
139 	{
140 	  puts ("child: mapped to same address");
141 	  kill (getppid (), SIGKILL);
142 	  exit (1);
143 	}
144 
145       munmap (oldp, sizeof (*p));
146 
147       if (pthread_mutex_lock (&p->m) != 0)
148 	{
149 	  puts ("child: mutex_lock failed");
150 	  kill (getppid (), SIGKILL);
151 	  exit (1);
152 	}
153 
154       p->var = 0;
155 
156 #ifndef USE_COND_SIGNAL
157       if (pthread_cond_broadcast (&p->c) != 0)
158 	{
159 	  puts ("child: cond_broadcast failed");
160 	  kill (getppid (), SIGKILL);
161 	  exit (1);
162 	}
163 #else
164       if (pthread_cond_signal (&p->c) != 0)
165 	{
166 	  puts ("child: cond_signal failed");
167 	  kill (getppid (), SIGKILL);
168 	  exit (1);
169 	}
170 #endif
171 
172       if (pthread_mutex_unlock (&p->m) != 0)
173 	{
174 	  puts ("child: mutex_unlock failed");
175 	  kill (getppid (), SIGKILL);
176 	  exit (1);
177 	}
178 
179       exit (0);
180     }
181 
182   do
183     pthread_cond_wait (&p->c, &p->m);
184   while (p->var != 0);
185 
186   if (TEMP_FAILURE_RETRY (waitpid (pid, NULL, 0)) != pid)
187     {
188       printf ("waitpid failed: %m\n");
189       kill (pid, SIGKILL);
190       return 1;
191     }
192 
193   return 0;
194 }
195