2 * Copyright (c) 2004, Bull S.A.. All rights reserved.
3 * Created by: Sebastien Decugis
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.
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.
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., 59
15 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
18 * This sample test aims to check the following assertion:
20 * If the calling thread is the last thread in the process,
21 * the effect are as if an implicit call to exit(0) had been made.
25 * -> main creates a thread.
26 * -> this thread forks(). The new process contains only 1 thread.
27 * -> the thread in the new process calls pthread_exit(non-0 value).
28 * -> main process joins the child process and checks the behavior
29 * is as if exit(0) had been called.
30 * The checked items are:
31 * -> the return value.
32 * -> the atexit() routines have been called.
36 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
37 #define _POSIX_C_SOURCE 200112L
39 /* Some routines are part of the XSI Extensions */
41 #define _XOPEN_SOURCE 600
44 /********************************************************************************************/
45 /****************************** standard includes *****************************************/
46 /********************************************************************************************/
55 #include <semaphore.h>
61 /********************************************************************************************/
62 /****************************** Test framework *****************************************/
63 /********************************************************************************************/
66 /* This header is responsible for defining the following macros:
67 * UNRESOLVED(ret, descr);
68 * where descr is a description of the error and ret is an int (error code for example)
70 * where descr is a short text saying why the test has failed.
74 * Both three macros shall terminate the calling process.
75 * The testcase shall not terminate in any other maneer.
77 * The other file defines the functions
79 * void output(char * string, ...)
81 * Those may be used to output information.
84 /********************************************************************************************/
85 /********************************** Configuration ******************************************/
86 /********************************************************************************************/
91 /********************************************************************************************/
92 /*********************************** Test cases *****************************************/
93 /********************************************************************************************/
95 #include "threads_scenarii.c"
97 /* This file will define the following objects:
98 * scenarii: array of struct __scenario type.
99 * NSCENAR : macro giving the total # of scenarii
100 * scenar_init(): function to call before use the scenarii array.
101 * scenar_fini(): function to call after end of use of the scenarii array.
104 /********************************************************************************************/
105 /*********************************** Real Test *****************************************/
106 /********************************************************************************************/
108 /* This will be used to control that atexit() has been called */
118 void * threaded (void * arg)
129 if (pid == (pid_t)-1)
131 UNRESOLVED(errno, "Failed to fork()");
139 if (ret != 0) { UNRESOLVED(ret, "Failed to register atexit function"); }
142 /* exit the last (and only) thread */
145 FAILED("pthread_exit() did not terminate the process when there was only 1 thread");
148 /* Only the parent process goes this far */
149 chk = waitpid(pid, &status, 0);
152 output("Expected pid: %i. Got %i\n", (int)pid, (int)chk);
153 UNRESOLVED(errno, "Waitpid failed");
156 if (WIFSIGNALED(status))
158 output("Child process killed with signal %d\n",WTERMSIG(status));
159 UNRESOLVED( -1 , "Child process was killed");
162 if (WIFEXITED(status))
164 ret = WEXITSTATUS(status);
168 UNRESOLVED( -1, "Child process was neither killed nor exited");
173 output("Exit status was: %i\n", ret);
174 FAILED("The child process did not exit with 0 status.");
179 FAILED("pthread_exit() in the last thread did not execute atexit() routines");
182 /* Signal we're done (especially in case of a detached thread) */
183 do { ret = sem_post(&scenarii[sc].sem); }
184 while ((ret == -1) && (errno == EINTR));
185 if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); }
191 int main (int argc, char *argv[])
196 mf =sysconf(_SC_MAPPED_FILES);
202 /* We want to share some memory with the child process */
205 /* We will place the test data in a mmaped file */
206 char filename[] = "/tmp/pthread_exit_6-1-XXXXXX";
212 /* We now create the temp files */
213 fd = mkstemp(filename);
215 { UNRESOLVED(errno, "Temporary file could not be created"); }
217 /* and make sure the file will be deleted when closed */
221 output("Temp file created (%s).\n", filename);
224 sz= (size_t)sysconf(_SC_PAGESIZE);
228 { UNRESOLVED(errno, "Memory allocation failed"); }
230 /* Write the data to the file. */
231 if (write (fd, tmp, sz) != (ssize_t) sz)
232 { UNRESOLVED(sz, "Writting to the file failed"); }
236 /* Now we can map the file in memory */
237 mmaped = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
238 if (mmaped == MAP_FAILED)
239 { UNRESOLVED(errno, "mmap failed"); }
241 ctl = (int *) mmaped;
243 /* Our datatest structure is now in shared memory */
245 output("Testdata allocated in shared memory.\n");
249 for (sc=0; sc < NSCENAR; sc++)
253 output("Starting test with scenario (%i): %s\n", sc, scenarii[sc].descr);
256 ret = pthread_create(&child, &scenarii[sc].ta, threaded, &ctl);
257 switch (scenarii[sc].result)
259 case 0: /* Operation was expected to succeed */
260 if (ret != 0) { UNRESOLVED(ret, "Failed to create this thread"); }
263 case 1: /* Operation was expected to fail */
264 if (ret == 0) { UNRESOLVED(-1, "An error was expected but the thread creation succeeded"); }
267 case 2: /* We did not know the expected result */
271 { output("Thread has been created successfully for this scenario\n"); }
273 { output("Thread creation failed with the error: %s\n", strerror(ret)); }
276 if (ret == 0) /* The new thread is running */
278 if (scenarii[sc].detached == 0)
280 ret = pthread_join(child, NULL);
281 if (ret != 0) { UNRESOLVED(ret, "Unable to join a thread"); }
285 /* Just wait for the thread to terminate */
286 do { ret = sem_wait(&scenarii[sc].sem); }
287 while ((ret == -1) && (errno == EINTR));
288 if (ret == -1) { UNRESOLVED(errno, "Failed to wait for the semaphore"); }
296 output("All test data destroyed\n");
297 output("Test PASSED\n");