• 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  * pthread_detach() does not force a thread to terminate.
20 
21  * The steps are:
22  *
23  * -> Create a thread
24  * -> detach the thread
25  * -> wait for the thread to post a semaphore.
26 
27  * The test fails if the semaphore is not posted within a certain duration.
28 
29  */
30 
31 /********************************************************************************************/
32 /****************************** standard includes *****************************************/
33 /********************************************************************************************/
34 #include <pthread.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <unistd.h>
40 
41 #include <sched.h>
42 #include <semaphore.h>
43 #include <time.h>
44 #include <errno.h>
45 #include <assert.h>
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 (error code for example)
54   * FAILED(descr);
55   *    where descr is a short text saying why the test has failed.
56   * PASSED();
57   *    No parameter.
58   *
59   * Both three macros shall terminate the calling process.
60   * The testcase shall not terminate in any other maneer.
61   *
62   * The other file defines the functions
63   * void output_init()
64   * void output(char * string, ...)
65   *
66   * Those may be used to output information.
67   */
68 
69 /********************************************************************************************/
70 /********************************** Configuration ******************************************/
71 /********************************************************************************************/
72 #ifndef VERBOSE
73 #define VERBOSE 1
74 #endif
75 
76 #define TIMEOUT 5
77 
78 /********************************************************************************************/
79 /***********************************    Test cases  *****************************************/
80 /********************************************************************************************/
81 
82 #include "../testfrmw/threads_scenarii.c"
83 
84 /* This file will define the following objects:
85  * scenarii: array of struct __scenario type.
86  * NSCENAR : macro giving the total # of scenarii
87  * scenar_init(): function to call before use the scenarii array.
88  * scenar_fini(): function to call after end of use of the scenarii array.
89  */
90 
91 /********************************************************************************************/
92 /***********************************    Real Test   *****************************************/
93 /********************************************************************************************/
94 
95 sem_t sem_sync;
96 
threaded(void * arg)97 void *threaded(void *arg)
98 {
99 	int ret = 0;
100 
101 	if (arg != NULL) {
102 		ret = pthread_detach(pthread_self());
103 		if (ret != 0) {
104 			UNRESOLVED(ret, "Failed to detach the thread");
105 		}
106 	}
107 	/* Wait for this semaphore which indicates that pthread_detach has been called */
108 	do {
109 		ret = sem_wait(&sem_sync);
110 	}
111 	while ((ret == -1) && (errno == EINTR));
112 	if (ret == -1) {
113 		UNRESOLVED(errno, "Failed to wait for the semaphore");
114 	}
115 
116 	/* Post the semaphore to indicate the main thread we're alive */
117 	do {
118 		ret = sem_post(&(scenarii[sc].sem));
119 	}
120 	while ((ret == -1) && (errno == EINTR));
121 	if (ret == -1) {
122 		UNRESOLVED(errno, "Failed to post the semaphore");
123 	}
124 
125 	return arg;
126 }
127 
main(void)128 int main(void)
129 {
130 	int ret = 0;
131 	pthread_t child;
132 	struct timespec ts;
133 
134 	output_init();
135 
136 	scenar_init();
137 
138 	ret = sem_init(&sem_sync, 0, 0);
139 	if (ret != 0) {
140 		UNRESOLVED(ret, "Failed to initialize a semaphore");
141 	}
142 
143 	for (sc = 0; sc < NSCENAR; sc++) {
144 #if VERBOSE > 0
145 		output("-----\n");
146 		output("Starting test with scenario (%i): %s\n", sc,
147 		       scenarii[sc].descr);
148 #endif
149 
150 		if (scenarii[sc].detached != 0) {	/* only joinable threads can be detached */
151 			ret =
152 			    pthread_attr_setdetachstate(&scenarii[sc].ta,
153 							PTHREAD_CREATE_JOINABLE);
154 			if (ret != 0) {
155 				UNRESOLVED(ret,
156 					   "Unable to set detachstate back to joinable");
157 			}
158 		}
159 
160 		/* for detached scenarii, we will call pthread_detach from inside the thread.
161 		   for joinable scenarii, we'll call pthread_detach from this thread. */
162 
163 		ret =
164 		    pthread_create(&child, &scenarii[sc].ta, threaded,
165 				   (scenarii[sc].detached != 0) ? &ret : NULL);
166 		switch (scenarii[sc].result) {
167 		case 0:	/* Operation was expected to succeed */
168 			if (ret != 0) {
169 				UNRESOLVED(ret, "Failed to create this thread");
170 			}
171 			break;
172 
173 		case 1:	/* Operation was expected to fail */
174 			if (ret == 0) {
175 				UNRESOLVED(-1,
176 					   "An error was expected but the thread creation succeeded");
177 			}
178 #if VERBOSE > 0
179 			break;
180 
181 		case 2:	/* We did not know the expected result */
182 		default:
183 			if (ret == 0) {
184 				output
185 				    ("Thread has been created successfully for this scenario\n");
186 			} else {
187 				output
188 				    ("Thread creation failed with the error: %s\n",
189 				     strerror(ret));
190 			}
191 #endif
192 		}
193 		if (ret == 0) {	/* The new thread is running */
194 			/* If we must detach from here, we do it now. */
195 			if (scenarii[sc].detached == 0) {
196 				ret = pthread_detach(child);
197 				if (ret != 0) {
198 					UNRESOLVED(ret,
199 						   "Failed to detach the child thread.");
200 				}
201 			}
202 
203 			/* Now, allow the thread to terminate */
204 			do {
205 				ret = sem_post(&sem_sync);
206 			}
207 			while ((ret == -1) && (errno == EINTR));
208 			if (ret == -1) {
209 				UNRESOLVED(errno,
210 					   "Failed to post the semaphore");
211 			}
212 
213 			/* Just wait for the thread to terminate */
214 			ret = clock_gettime(CLOCK_REALTIME, &ts);
215 			if (ret != 0) {
216 				UNRESOLVED(ret, "Failed to get time");
217 			}
218 
219 			ts.tv_sec += TIMEOUT;
220 
221 			do {
222 				ret = sem_timedwait(&(scenarii[sc].sem), &ts);
223 			}
224 			while ((ret == -1) && (errno == EINTR));
225 			if (ret == -1) {
226 				if (errno == ETIMEDOUT) {
227 					FAILED
228 					    ("pthread_detach made the thread terminate");
229 				}
230 				/* else */
231 				UNRESOLVED(errno,
232 					   "Failed to wait for the semaphore");
233 			}
234 
235 			/* Let the thread an additionnal row to cleanup */
236 			sched_yield();
237 		}
238 	}
239 
240 	ret = sem_destroy(&sem_sync);
241 	if (ret != 0) {
242 		UNRESOLVED(ret, "Failed to destroy the semaphore");
243 	}
244 
245 	scenar_fini();
246 #if VERBOSE > 0
247 	output("-----\n");
248 	output("All test data destroyed\n");
249 	output("Test PASSED\n");
250 #endif
251 
252 	PASSED;
253 }
254