Initial revision
[kopensolaris-gnu/glibc.git] / nptl / tst-cond6.c
1 /* Copyright (C) 2002 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2002.
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, write to the Free
17    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18    02111-1307 USA.  */
19
20 #include <errno.h>
21 #include <pthread.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <unistd.h>
27 #include <sys/mman.h>
28 #include <sys/time.h>
29 #include <sys/wait.h>
30
31
32 int *condition;
33
34
35 int
36 main (void)
37 {
38   size_t ps = sysconf (_SC_PAGESIZE);
39   char tmpfname[] = "/tmp/tst-cond6.XXXXXX";
40   char data[ps];
41   void *mem;
42   int fd;
43   pthread_mutexattr_t ma;
44   pthread_mutex_t *mut1;
45   pthread_mutex_t *mut2;
46   pthread_condattr_t ca;
47   pthread_cond_t *cond;
48   pid_t pid;
49   int result = 0;
50
51   fd = mkstemp (tmpfname);
52   if (fd == -1)
53     {
54       printf ("cannot open temporary file: %m\n");
55       exit (1);
56     }
57
58   /* Make sure it is always removed.  */
59   unlink (tmpfname);
60
61   /* Create one page of data.  */
62   memset (data, '\0', ps);
63
64   /* Write the data to the file.  */
65   if (write (fd, data, ps) != ps)
66     {
67       puts ("short write");
68       exit (1);
69     }
70
71   mem = mmap (NULL, ps, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
72   if (mem == MAP_FAILED)
73     {
74       printf ("mmap failed: %m\n");
75       exit (1);
76     }
77
78   mut1 = (pthread_mutex_t *) (((uintptr_t) mem
79                                + __alignof (pthread_mutex_t))
80                               & ~(__alignof (pthread_mutex_t) - 1));
81   mut2 = mut1 + 1;
82
83   cond = (pthread_cond_t *) (((uintptr_t) (mut2 + 1)
84                               + __alignof (pthread_cond_t))
85                              & ~(__alignof (pthread_cond_t) - 1));
86
87   condition = (int *) (((uintptr_t) (cond + 1) + __alignof (int))
88                        & ~(__alignof (int) - 1));
89
90   if (pthread_mutexattr_init (&ma) != 0)
91     {
92       puts ("mutexattr_init failed");
93       exit (1);
94     }
95
96   if (pthread_mutexattr_setpshared (&ma, PTHREAD_PROCESS_SHARED) != 0)
97     {
98       puts ("mutexattr_setpshared failed");
99       exit (1);
100     }
101
102   if (pthread_mutex_init (mut1, &ma) != 0)
103     {
104       puts ("1st mutex_init failed");
105       exit (1);
106     }
107
108   if (pthread_mutex_init (mut2, &ma) != 0)
109     {
110       puts ("2nd mutex_init failed");
111       exit (1);
112     }
113
114   if (pthread_condattr_init (&ca) != 0)
115     {
116       puts ("condattr_init failed");
117       exit (1);
118     }
119
120   if (pthread_condattr_setpshared (&ca, PTHREAD_PROCESS_SHARED) != 0)
121     {
122       puts ("condattr_setpshared failed");
123       exit (1);
124     }
125
126   if (pthread_cond_init (cond, &ca) != 0)
127     {
128       puts ("cond_init failed");
129       exit (1);
130     }
131
132   if (pthread_mutex_lock (mut1) != 0)
133     {
134       puts ("parent: 1st mutex_lock failed");
135       exit (1);
136     }
137
138   puts ("going to fork now");
139   pid = fork ();
140   if (pid == -1)
141     {
142       puts ("fork failed");
143       exit (1);
144     }
145   else if (pid == 0)
146     {
147       struct timespec ts;
148       struct timeval tv;
149
150       if (pthread_mutex_lock (mut2) != 0)
151         {
152           puts ("child: mutex_lock failed");
153           exit (1);
154         }
155
156       if (pthread_mutex_unlock (mut1) != 0)
157         {
158           puts ("child: 1st mutex_unlock failed");
159           exit (1);
160         }
161
162       /* Waiting for the condition will fail.  But we want the timeout
163          here.  */
164       if (gettimeofday (&tv, NULL) != 0)
165         {
166           puts ("gettimeofday failed");
167           exit (1);
168         }
169
170       TIMEVAL_TO_TIMESPEC (&tv, &ts);
171       ts.tv_nsec += 500000000;
172       if (ts.tv_nsec >= 1000000000)
173         {
174           ts.tv_nsec -= 1000000000;
175           ++ts.tv_sec;
176         }
177
178       do
179         if (pthread_cond_timedwait (cond, mut2, &ts) != 0)
180           {
181             puts ("child: cond_wait failed");
182             exit (1);
183           }
184       while (*condition == 0);
185
186       if (pthread_mutex_unlock (mut2) != 0)
187         {
188           puts ("child: 2nd mutex_unlock failed");
189           exit (1);
190         }
191
192       puts ("child done");
193     }
194   else
195     {
196       int status;
197
198       if (pthread_mutex_lock (mut1) != 0)
199         {
200           puts ("parent: 2nd mutex_lock failed");
201           exit (1);
202         }
203
204       if (pthread_mutex_lock (mut2) != 0)
205         {
206           puts ("parent: 3rd mutex_lock failed");
207           exit (1);
208         }
209
210       if (pthread_cond_signal (cond) != 0)
211         {
212           puts ("parent: cond_signal failed");
213           exit (1);
214         }
215
216       *condition = 1;
217
218       if (pthread_mutex_unlock (mut2) != 0)
219         {
220           puts ("parent: mutex_unlock failed");
221           exit (1);
222         }
223
224       puts ("waiting for child");
225
226       waitpid (pid, &status, 0);
227       result |= status;
228
229       puts ("parent done");
230     }
231
232  return result;
233 }