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