1 /*
2 * Copyright (c) 2005, Bull S.A.. All rights reserved.
3 * Created by: Sebastien Decugis
4
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
17 * This sample test aims to check the following assertion:
18 *
19 * When pthread_atfork is called several times, the prepare handlers are executed
20 * in reversed order as they were registered, and child and parent handlers are
21 * executed in the same order as they were registered.
22
23 * The steps are:
24 * -> Register some handlers for which call order is traceable.
25
26 * The test fails if the registered handlers are not executed as expected.
27
28 */
29
30 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
31 #define _POSIX_C_SOURCE 200112L
32
33 /******************************************************************************/
34 /*************************** standard includes ********************************/
35 /******************************************************************************/
36 #include <pthread.h>
37 #include <stdarg.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42
43 #include <sys/wait.h>
44 #include <errno.h>
45
46 /******************************************************************************/
47 /*************************** Test framework *******************************/
48 /******************************************************************************/
49 #include "../testfrmw/testfrmw.h"
50 #include "../testfrmw/testfrmw.c"
51 /* This header is responsible for defining the following macros:
52 * UNRESOLVED(ret, descr);
53 * where descr is a description of the error and ret is an int
54 * (error code for example)
55 * FAILED(descr);
56 * where descr is a short text saying why the test has failed.
57 * PASSED();
58 * No parameter.
59 *
60 * Both three macros shall terminate the calling process.
61 * The testcase shall not terminate in any other maneer.
62 *
63 * The other file defines the functions
64 * void output_init()
65 * void output(char * string, ...)
66 *
67 * Those may be used to output information.
68 */
69
70 /******************************************************************************/
71 /**************************** Configuration ***********************************/
72 /******************************************************************************/
73 #ifndef VERBOSE
74 #define VERBOSE 1
75 #endif
76
77 /******************************************************************************/
78 /*************************** Test case ***********************************/
79 /******************************************************************************/
80
81 pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
82
83 int control = 0;
84 int nerrors = 0;
85
86 /* pthread_atfork handlers */
pre3(void)87 void pre3(void)
88 {
89 control++;
90
91 if (control != 1)
92 nerrors++;
93 }
94
pre2(void)95 void pre2(void)
96 {
97 control++;
98
99 if (control != 2)
100 nerrors++;
101 }
102
pre1(void)103 void pre1(void)
104 {
105 control++;
106
107 if (control != 3)
108 nerrors++;
109 }
110
par1(void)111 void par1(void)
112 {
113 control++;
114
115 if (control != 4)
116 nerrors++;
117 }
118
par2(void)119 void par2(void)
120 {
121 control++;
122
123 if (control != 5)
124 nerrors++;
125 }
126
par3(void)127 void par3(void)
128 {
129 control++;
130
131 if (control != 6)
132 nerrors++;
133 }
134
chi1(void)135 void chi1(void)
136 {
137 control += 2;
138
139 if (control != 5)
140 nerrors++;
141 }
142
chi2(void)143 void chi2(void)
144 {
145 control += 2;
146
147 if (control != 7)
148 nerrors++;
149 }
150
chi3(void)151 void chi3(void)
152 {
153 control += 2;
154
155 if (control != 9)
156 nerrors++;
157 }
158
159 /* Thread function */
threaded(void * arg)160 void *threaded(void *arg)
161 {
162 int ret, status;
163 pid_t child, ctl;
164
165 /* Wait main thread has registered the handler */
166 ret = pthread_mutex_lock(&mtx);
167
168 if (ret != 0) {
169 UNRESOLVED(ret, "Failed to lock mutex");
170 }
171
172 ret = pthread_mutex_unlock(&mtx);
173
174 if (ret != 0) {
175 UNRESOLVED(ret, "Failed to unlock mutex");
176 }
177
178 /* fork */
179 child = fork();
180
181 if (child == -1) {
182 UNRESOLVED(errno, "Failed to fork");
183 }
184
185 /* child */
186 if (child == 0) {
187 if (nerrors) {
188 FAILED("Errors occured in the child");
189 }
190
191 /* We're done */
192 exit(PTS_PASS);
193 }
194
195 /* Parent joins the child */
196 ctl = waitpid(child, &status, 0);
197
198 if (ctl != child) {
199 UNRESOLVED(errno, "Waitpid returned the wrong PID");
200 }
201
202 if (!WIFEXITED(status) || (WEXITSTATUS(status) != PTS_PASS)) {
203 FAILED("Child exited abnormally");
204 }
205
206 if (nerrors) {
207 FAILED("Errors occured in the parent (only)");
208 }
209
210 /* quit */
211 return NULL;
212 }
213
214 /* The main test function. */
main(void)215 int main(void)
216 {
217 int ret;
218 pthread_t ch;
219
220 /* Initialize output */
221 output_init();
222
223 ret = pthread_mutex_lock(&mtx);
224
225 if (ret != 0) {
226 UNRESOLVED(ret, "Failed to lock mutex");
227 }
228
229 ret = pthread_create(&ch, NULL, threaded, NULL);
230
231 if (ret != 0) {
232 UNRESOLVED(ret, "Failed to create a thread");
233 }
234
235 /* Register the handlers */
236 ret = pthread_atfork(pre1, par1, chi1);
237
238 if (ret != 0) {
239 UNRESOLVED(ret, "Failed to register the atfork handlers");
240 }
241
242 ret = pthread_atfork(pre2, par2, chi2);
243
244 if (ret != 0) {
245 UNRESOLVED(ret, "Failed to register the atfork handlers");
246 }
247
248 ret = pthread_atfork(pre3, par3, chi3);
249
250 if (ret != 0) {
251 UNRESOLVED(ret, "Failed to register the atfork handlers");
252 }
253
254 /* Let the child go on */
255 ret = pthread_mutex_unlock(&mtx);
256
257 if (ret != 0) {
258 UNRESOLVED(ret, "Failed to unlock mutex");
259 }
260
261 ret = pthread_join(ch, NULL);
262
263 if (ret != 0) {
264 UNRESOLVED(ret, "Failed to join the thread");
265 }
266
267 /* Test passed */
268 #if VERBOSE > 0
269
270 output("Test passed\n");
271
272 #endif
273
274 PASSED;
275 }
276