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 * When a thread other than the first thread of a process returns,
21 * an implicit call to pthread_exit() is made with the returned value
22 * as a parameter.
23
24 * The steps are:
25 *
26 * Same test as 1-2, 3-2, 4-1, but with return in place of pthread_exit.
27 * The results shall be the same.
28
29  */
30
31
32 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
33 #define _POSIX_C_SOURCE 200112L
34
35 /* Some routines are part of the XSI Extensions */
36#ifndef WITHOUT_XOPEN
37 #define _XOPEN_SOURCE	600
38#endif
39
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.h"
58 #include "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 "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
101int atctl=0;
102pthread_key_t tld[3];
103
104
105/* atexit() routines */
106void at1(void)
107{
108	atctl+=1;
109}
110void at2(void)
111{
112	atctl+=2;
113}
114
115/* TLD destructor */
116void destructor(void * arg)
117{
118	*(int *) arg += 1;
119}
120
121/* Thread routine */
122void * threaded (void * arg)
123{
124	int ret = 0;
125
126	ret = atexit(at2);
127	if (ret != 0)  {  UNRESOLVED(ret, "Failed to register an atexit() routine");  }
128
129	ret = pthread_setspecific(tld[0], arg);
130	if (ret != 0)  {  UNRESOLVED(ret, "Failed to set TLD data");  }
131
132	ret = pthread_setspecific(tld[1], arg);
133	if (ret != 0)  {  UNRESOLVED(ret, "Failed to set TLD data");  }
134
135	ret = pthread_setspecific(tld[2], arg);
136	if (ret != 0)  {  UNRESOLVED(ret, "Failed to set TLD data");  }
137
138	return  NULL + 1;
139
140	FAILED("return did not terminate the thread (oO)");
141	return NULL;
142}
143
144/* Main routine */
145int main (int argc, char *argv[])
146{
147	int ret=0;
148	int ctl=0;
149	void * rval;
150	pthread_t child;
151	int i,j;
152
153	output_init();
154
155	scenar_init();
156
157	for (j=0; j<3; j++)
158	{
159		ret = pthread_key_create(&tld[j], destructor);
160		if (ret != 0)  {  UNRESOLVED(ret, "Failed to create a TLD key");  }
161	}
162
163	for (i=0; i < NSCENAR; i++)
164	{
165		if (scenarii[i].detached == 0)
166		{
167			#if VERBOSE > 0
168			output("-----\n");
169			output("Starting test with scenario (%i): %s\n", i, scenarii[i].descr);
170			#endif
171
172			ctl=0;
173
174			ret = pthread_create(&child, &scenarii[i].ta, threaded, &ctl);
175			switch (scenarii[i].result)
176			{
177				case 0: /* Operation was expected to succeed */
178					if (ret != 0)  {  UNRESOLVED(ret, "Failed to create this thread");  }
179					break;
180
181				case 1: /* Operation was expected to fail */
182					if (ret == 0)  {  UNRESOLVED(-1, "An error was expected but the thread creation succeeded");  }
183					break;
184
185				case 2: /* We did not know the expected result */
186				default:
187					#if VERBOSE > 0
188					if (ret == 0)
189						{ output("Thread has been created successfully for this scenario\n"); }
190					else
191						{ output("Thread creation failed with the error: %s\n", strerror(ret)); }
192					#endif
193			}
194			if (ret == 0) /* The new thread is running */
195			{
196				ret = pthread_join(child, &rval);
197				if (ret != 0)  {  UNRESOLVED(ret, "Unable to join a thread");  }
198
199				if (rval != (NULL+1))
200				{
201					FAILED("pthread_join() did not retrieve the pthread_exit() param");
202				}
203
204				if (atctl != 0)  {  FAILED("The function registered with atexit() executed");  }
205
206				if (ctl != 3)  {  FAILED("The TLD destructors were not called");  }
207			}
208		}
209	}
210
211	for (j=0; j<3; j++)
212	{
213		ret = pthread_key_delete(tld[j]);
214		if (ret != 0)  {  UNRESOLVED(ret, "Failed to delete a TLD key");  }
215	}
216
217	scenar_fini();
218	#if VERBOSE > 0
219	output("-----\n");
220	output("All test data destroyed\n");
221	output("Test PASSED\n");
222	#endif
223
224	PASSED;
225}
226
227