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