chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / nptl / tst-cancel16.c
1 /* Copyright (C) 2003 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
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 <unistd.h>
26 #include <sys/mman.h>
27 #include <sys/wait.h>
28
29
30 static pthread_barrier_t b2;
31 static int fd;
32 static int called;
33
34
35 static void
36 cl (void *arg)
37 {
38   called = 1;
39 }
40
41
42 static void *
43 tf (void *arg)
44 {
45   int r = pthread_barrier_wait (&b2);
46   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
47     {
48       puts ("child thread: barrier_wait failed");
49       exit (1);
50     }
51
52   pthread_cleanup_push (cl, NULL);
53
54   /* This call should never return.  */
55   (void) lockf (fd, F_LOCK, 0);
56
57   pthread_cleanup_pop (0);
58
59   return NULL;
60 }
61
62
63 static int
64 do_test (void)
65 {
66   char fname[] = "/tmp/cancel16XXXXXX";
67   fd = mkstemp (fname);
68   if (fd == -1)
69     {
70       puts ("mkstemp failed");
71       return 1;
72     }
73   unlink (fname);
74
75   char mem[sizeof (pthread_barrier_t)];
76   memset (mem, '\0', sizeof (mem));
77   if (TEMP_FAILURE_RETRY (pwrite (fd, mem, sizeof (mem), 0)) != sizeof (mem))
78     {
79       puts ("pwrite failed");
80       return 1;
81     }
82
83   void *p = mmap (NULL, sizeof (mem), PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
84   if (p == MAP_FAILED)
85     {
86       puts ("mmap failed");
87       return 1;
88     }
89   pthread_barrier_t *b = (pthread_barrier_t *) p;
90
91   pthread_barrierattr_t ba;
92   if (pthread_barrierattr_init (&ba) != 0)
93     {
94       puts ("barrierattr_init failed");
95       return 1;
96     }
97   if (pthread_barrierattr_setpshared (&ba, 1) != 0)
98     {
99       puts ("barrierattr_setshared failed");
100       return 1;
101     }
102
103   if (pthread_barrier_init (b, &ba, 2) != 0)
104     {
105       puts ("1st barrier_init failed");
106       return 1;
107     }
108   if (pthread_barrierattr_destroy (&ba) != 0)
109     {
110       puts ("barrier_destroy failed");
111       return 1;
112     }
113
114   pid_t pid = fork ();
115   if (pid == 0)
116     {
117       /* Child.  Lock the file and wait.  */
118       if (lockf (fd, F_LOCK, 0) != 0)
119         {
120           puts ("child process: lockf failed");
121           _exit (1);
122         }
123
124       int r = pthread_barrier_wait (b);
125       if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
126         {
127           puts ("child process: 1st barrier_wait failed");
128           _exit (1);
129         }
130
131       /* Make sure the process dies.  */
132       alarm (5);
133
134       r = pthread_barrier_wait (b);
135       if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
136         {
137           puts ("child process: 2nd barrier_wait failed");
138           _exit (1);
139         }
140
141       _exit (0);
142     }
143   if (pid == -1)
144     {
145       puts ("fork failed");
146       return 1;
147     }
148
149   int r = pthread_barrier_wait (b);
150   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
151     {
152       puts ("main: 1st barrier_wait failed");
153       _exit (1);
154     }
155
156   if (pthread_barrier_init (&b2, NULL, 2) != 0)
157     {
158       puts ("2nd barrier_init failed");
159       return 1;
160     }
161
162   pthread_t th;
163   if (pthread_create (&th, NULL, tf, NULL) != 0)
164     {
165       puts ("create failed");
166       return 1;
167     }
168
169   r = pthread_barrier_wait (&b2);
170   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
171     {
172       puts ("main: 2nd barrier_wait failed");
173       return 1;
174     }
175
176   /* Delay.  */
177   sleep (1);
178
179   if (pthread_cancel (th) != 0)
180     {
181       puts ("cancel failed");
182       return 1;
183     }
184
185   void *result;
186   if (pthread_join (th, &result) != 0)
187     {
188       puts ("join failed");
189       return 1;
190     }
191   if (result != PTHREAD_CANCELED)
192     {
193       puts ("thread not canceled");
194       return 1;
195     }
196   if (called == 0)
197     {
198       puts ("cleanup handler not called");
199       return 1;
200     }
201
202   r = pthread_barrier_wait (b);
203   if (r != 0 && r != PTHREAD_BARRIER_SERIAL_THREAD)
204     {
205       puts ("main: 3rd barrier_wait failed");
206       return 1;
207     }
208
209   int status;
210   if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
211     {
212       puts ("waitpid failed");
213       return 1;
214     }
215   if (WEXITSTATUS (status) != 0)
216     {
217       printf ("child process exits with %d\n", WEXITSTATUS (status));
218       return 1;
219     }
220
221   if (lockf (fd, F_LOCK, 0) != 0)
222     {
223       puts ("main: lockf failed");
224       return 1;
225     }
226
227   return 0;
228 }
229
230 #define TEST_FUNCTION do_test ()
231 #include "../test-skeleton.c"