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