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