1 /*
2 * Copyright (c) 2004, 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 * If the calling thread is the last thread in the process,
20 * the effect are as if an implicit call to exit(0) had been made.
21
22 * The steps are:
23 *
24 * -> main creates a thread.
25 * -> this thread forks(). The new process contains only 1 thread.
26 * -> the thread in the new process calls pthread_exit(non-0 value).
27 * -> main process joins the child process and checks the behavior
28 * is as if exit(0) had been called.
29 * The checked items are:
30 * -> the return value.
31 * -> the atexit() routines have been called.
32 */
33
34 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
35 #define _POSIX_C_SOURCE 200112L
36
37 /* Some routines are part of the XSI Extensions */
38 #ifndef WITHOUT_XOPEN
39 #define _XOPEN_SOURCE 600
40 #endif
41
42 /********************************************************************************************/
43 /****************************** standard includes *****************************************/
44 /********************************************************************************************/
45 #include <pthread.h>
46 #include <stdarg.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51
52 #include <sched.h>
53 #include <semaphore.h>
54 #include <errno.h>
55 #include <assert.h>
56 #include <sys/wait.h>
57 #include <sys/mman.h>
58
59 /********************************************************************************************/
60 /****************************** Test framework *****************************************/
61 /********************************************************************************************/
62 #include "../testfrmw/testfrmw.h"
63 #include "../testfrmw/testfrmw.c"
64 /* This header is responsible for defining the following macros:
65 * UNRESOLVED(ret, descr);
66 * where descr is a description of the error and ret is an int (error code for example)
67 * FAILED(descr);
68 * where descr is a short text saying why the test has failed.
69 * PASSED();
70 * No parameter.
71 *
72 * Both three macros shall terminate the calling process.
73 * The testcase shall not terminate in any other maneer.
74 *
75 * The other file defines the functions
76 * void output_init()
77 * void output(char * string, ...)
78 *
79 * Those may be used to output information.
80 */
81
82 /********************************************************************************************/
83 /********************************** Configuration ******************************************/
84 /********************************************************************************************/
85 #ifndef VERBOSE
86 #define VERBOSE 1
87 #endif
88
89 /********************************************************************************************/
90 /*********************************** Test cases *****************************************/
91 /********************************************************************************************/
92
93 #include "../testfrmw/threads_scenarii.c"
94
95 /* This file will define the following objects:
96 * scenarii: array of struct __scenario type.
97 * NSCENAR : macro giving the total # of scenarii
98 * scenar_init(): function to call before use the scenarii array.
99 * scenar_fini(): function to call after end of use of the scenarii array.
100 */
101
102 /********************************************************************************************/
103 /*********************************** Real Test *****************************************/
104 /********************************************************************************************/
105
106 /* This will be used to control that atexit() has been called */
107 int *ctl;
108 long mf;
109
clnp(void)110 void clnp(void)
111 {
112 *ctl = 1;
113 }
114
115 /* Thread routine */
threaded(void * arg)116 void *threaded(void *arg)
117 {
118 int ret = 0;
119
120 pid_t pid, chk;
121 int status;
122
123 if (mf > 0)
124 *ctl = 0;
125
126 #if VERBOSE > 0
127 fflush(stdout);
128 #endif
129
130 pid = fork();
131 if (pid == (pid_t) - 1) {
132 UNRESOLVED(errno, "Failed to fork()");
133 }
134 if (pid == 0) {
135 /* children */
136 if (mf > 0) {
137 ret = atexit(clnp);
138 if (ret != 0) {
139 UNRESOLVED(ret,
140 "Failed to register atexit function");
141 }
142 }
143
144 /* exit the last (and only) thread */
145 pthread_exit(&ret);
146
147 FAILED
148 ("pthread_exit() did not terminate the process when there was only 1 thread");
149 }
150
151 /* Only the parent process goes this far */
152 chk = waitpid(pid, &status, 0);
153 if (chk != pid) {
154 output("Expected pid: %i. Got %i\n", (int)pid, (int)chk);
155 UNRESOLVED(errno, "Waitpid failed");
156 }
157
158 if (WIFSIGNALED(status)) {
159 output("Child process killed with signal %d\n",
160 WTERMSIG(status));
161 UNRESOLVED(-1, "Child process was killed");
162 }
163
164 if (WIFEXITED(status)) {
165 ret = WEXITSTATUS(status);
166 } else {
167 UNRESOLVED(-1, "Child process was neither killed nor exited");
168 }
169
170 if (ret != 0) {
171 output("Exit status was: %i\n", ret);
172 FAILED("The child process did not exit with 0 status.");
173 }
174
175 if (mf > 0)
176 if (*ctl != 1)
177 FAILED
178 ("pthread_exit() in the last thread did not execute atexit() routines");
179
180 /* Signal we're done (especially in case of a detached thread) */
181 do {
182 ret = sem_post(&scenarii[sc].sem);
183 }
184 while ((ret == -1) && (errno == EINTR));
185 if (ret == -1) {
186 UNRESOLVED(errno, "Failed to wait for the semaphore");
187 }
188
189 return NULL;
190 }
191
192 /* Main routine */
main(void)193 int main(void)
194 {
195 int ret = 0;
196 pthread_t child;
197
198 mf = sysconf(_SC_MAPPED_FILES);
199
200 output_init();
201
202 scenar_init();
203
204 /* We want to share some memory with the child process */
205 if (mf > 0) {
206 /* We will place the test data in a mmaped file */
207 char filename[] = "/tmp/pthread_exit_6-1-XXXXXX";
208 size_t sz;
209 void *mmaped;
210 int fd;
211 char *tmp;
212
213 /* We now create the temp files */
214 fd = mkstemp(filename);
215 if (fd == -1) {
216 UNRESOLVED(errno,
217 "Temporary file could not be created");
218 }
219
220 /* and make sure the file will be deleted when closed */
221 unlink(filename);
222
223 #if VERBOSE > 1
224 output("Temp file created (%s).\n", filename);
225 #endif
226
227 sz = (size_t) sysconf(_SC_PAGESIZE);
228
229 tmp = calloc(1, sz);
230 if (tmp == NULL) {
231 UNRESOLVED(errno, "Memory allocation failed");
232 }
233
234 /* Write the data to the file. */
235 if (write(fd, tmp, sz) != (ssize_t) sz) {
236 UNRESOLVED(sz, "Writting to the file failed");
237 }
238
239 free(tmp);
240
241 /* Now we can map the file in memory */
242 mmaped =
243 mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
244 if (mmaped == MAP_FAILED) {
245 UNRESOLVED(errno, "mmap failed");
246 }
247
248 ctl = (int *)mmaped;
249
250 /* Our datatest structure is now in shared memory */
251 #if VERBOSE > 1
252 output("Testdata allocated in shared memory.\n");
253 #endif
254 }
255
256 for (sc = 0; sc < NSCENAR; sc++) {
257 #if VERBOSE > 0
258 output("-----\n");
259 output("Starting test with scenario (%i): %s\n", sc,
260 scenarii[sc].descr);
261 #endif
262
263 ret = pthread_create(&child, &scenarii[sc].ta, threaded, &ctl);
264 switch (scenarii[sc].result) {
265 case 0: /* Operation was expected to succeed */
266 if (ret != 0) {
267 UNRESOLVED(ret, "Failed to create this thread");
268 }
269 break;
270
271 case 1: /* Operation was expected to fail */
272 if (ret == 0) {
273 UNRESOLVED(-1,
274 "An error was expected but the thread creation succeeded");
275 }
276 break;
277
278 case 2: /* We did not know the expected result */
279 default:
280 #if VERBOSE > 0
281 if (ret == 0) {
282 output
283 ("Thread has been created successfully for this scenario\n");
284 } else {
285 output
286 ("Thread creation failed with the error: %s\n",
287 strerror(ret));
288 }
289 #endif
290 }
291 if (ret == 0) { /* The new thread is running */
292 if (scenarii[sc].detached == 0) {
293 ret = pthread_join(child, NULL);
294 if (ret != 0) {
295 UNRESOLVED(ret,
296 "Unable to join a thread");
297 }
298 } else {
299 /* Just wait for the thread to terminate */
300 do {
301 ret = sem_wait(&scenarii[sc].sem);
302 }
303 while ((ret == -1) && (errno == EINTR));
304 if (ret == -1) {
305 UNRESOLVED(errno,
306 "Failed to wait for the semaphore");
307 }
308 }
309 }
310 }
311
312 scenar_fini();
313 #if VERBOSE > 0
314 output("-----\n");
315 output("All test data destroyed\n");
316 output("Test PASSED\n");
317 #endif
318
319 PASSED;
320 }
321