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() will indicate that the thread resources
20 * can be reclaimed as soon as the thread terminates.
21 * This means that pthread_join() will fail on such a thread.
22
23 * The steps are:
24 *
25 * -> create a thread with a joinable state
26 * -> detach the thread, either from inside the thread or from outside
27 * -> try and join the thread, and check an error is returned.
28
29 * The test fails if pthread_join succeeds.
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 <errno.h>
53#include <assert.h>
54/********************************************************************************************/
55/******************************   Test framework   *****************************************/
56/********************************************************************************************/
57#include "../testfrmw/testfrmw.h"
58#include "../testfrmw/testfrmw.c"
59 /* This header is responsible for defining the following macros:
60  * UNRESOLVED(ret, descr);
61  *    where descr is a description of the error and ret is an int (error code for example)
62  * FAILED(descr);
63  *    where descr is a short text saying why the test has failed.
64  * PASSED();
65  *    No parameter.
66  *
67  * Both three macros shall terminate the calling process.
68  * The testcase shall not terminate in any other maneer.
69  *
70  * The other file defines the functions
71  * void output_init()
72  * void output(char * string, ...)
73  *
74  * Those may be used to output information.
75  */
76
77/********************************************************************************************/
78/********************************** Configuration ******************************************/
79/********************************************************************************************/
80#ifndef VERBOSE
81#define VERBOSE 1
82#endif
83
84/********************************************************************************************/
85/***********************************    Test cases  *****************************************/
86/********************************************************************************************/
87
88#include "../testfrmw/threads_scenarii.c"
89
90/* This file will define the following objects:
91 * scenarii: array of struct __scenario type.
92 * NSCENAR : macro giving the total # of scenarii
93 * scenar_init(): function to call before use the scenarii array.
94 * scenar_fini(): function to call after end of use of the scenarii array.
95 */
96
97/********************************************************************************************/
98/***********************************    Real Test   *****************************************/
99/********************************************************************************************/
100
101void *threaded(void *arg)
102{
103	int ret = 0;
104
105	if (arg != NULL) {
106		ret = pthread_detach(pthread_self());
107		if (ret != 0) {
108			UNRESOLVED(ret, "Failed to detach the thread");
109		}
110	}
111
112	/* Post the semaphore to unlock the main thread in case of a detached thread */
113	do {
114		ret = sem_post(&(scenarii[sc].sem));
115	}
116	while ((ret == -1) && (errno == EINTR));
117	if (ret == -1) {
118		UNRESOLVED(errno, "Failed to post the semaphore");
119	}
120
121	return arg;
122}
123
124int main(void)
125{
126	int ret = 0;
127	pthread_t child;
128
129	output_init();
130
131	scenar_init();
132
133	for (sc = 0; sc < NSCENAR; sc++) {
134#if VERBOSE > 0
135		output("-----\n");
136		output("Starting test with scenario (%i): %s\n", sc,
137		       scenarii[sc].descr);
138#endif
139
140		if (scenarii[sc].detached != 0) {	/* only joinable threads can be detached */
141			ret =
142			    pthread_attr_setdetachstate(&scenarii[sc].ta,
143							PTHREAD_CREATE_JOINABLE);
144			if (ret != 0) {
145				UNRESOLVED(ret,
146					   "Unable to set detachstate back to joinable");
147			}
148		}
149
150		/* for detached scenarii, we will call pthread_detach from inside the thread.
151		   for joinable scenarii, we'll call pthread_detach from this thread. */
152
153		ret =
154		    pthread_create(&child, &scenarii[sc].ta, threaded,
155				   (scenarii[sc].detached != 0) ? &ret : NULL);
156		switch (scenarii[sc].result) {
157		case 0:	/* Operation was expected to succeed */
158			if (ret != 0) {
159				UNRESOLVED(ret, "Failed to create this thread");
160			}
161			break;
162
163		case 1:	/* Operation was expected to fail */
164			if (ret == 0) {
165				UNRESOLVED(-1,
166					   "An error was expected but the thread creation succeeded");
167			}
168#if VERBOSE > 0
169			break;
170
171		case 2:	/* We did not know the expected result */
172		default:
173			if (ret == 0) {
174				output
175				    ("Thread has been created successfully for this scenario\n");
176			} else {
177				output
178				    ("Thread creation failed with the error: %s\n",
179				     strerror(ret));
180			}
181#endif
182		}
183		if (ret == 0) {	/* The new thread is running */
184			/* Just wait for the thread to terminate */
185			do {
186				ret = sem_wait(&(scenarii[sc].sem));
187			}
188			while ((ret == -1) && (errno == EINTR));
189			if (ret == -1) {
190				UNRESOLVED(errno,
191					   "Failed to post the semaphore");
192			}
193
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 check that the thread resources are freed. */
204			ret = pthread_join(child, NULL);
205			if (ret == 0) {
206				FAILED
207				    ("We were able to join a detached thread.");
208			}
209
210			/* Let the thread an additionnal row to cleanup */
211			sched_yield();
212		}
213	}
214
215	scenar_fini();
216#if VERBOSE > 0
217	output("-----\n");
218	output("All test data destroyed\n");
219	output("Test PASSED\n");
220#endif
221
222	PASSED;
223}
224