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 * The TLD destructors (if any) are executed after the cancelation cleanup handlers,
21 * in unspecified order.
22
23 * The steps are:
24 *
25 *  -> Create threads with different attributes (but all must be joinable)
26 *  -> inside the thread,
27 *     -> register three cancelation handlers
28 *     -> call pthread_exit.
29 *  -> In the main thread, we join the thread and check the cleanups were executed in order.
30
31  */
32
33
34 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
35 #define _POSIX_C_SOURCE 200112L
36
37 /* Some routines are part of the XSI Extensions */
38#ifndef WITHOUT_XOPEN
39 #define _XOPEN_SOURCE	600
40#endif
41
42/********************************************************************************************/
43/****************************** standard includes *****************************************/
44/********************************************************************************************/
45 #include <pthread.h>
46 #include <stdarg.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <string.h>
50 #include <unistd.h>
51
52 #include <sched.h>
53 #include <semaphore.h>
54 #include <errno.h>
55 #include <assert.h>
56/********************************************************************************************/
57/******************************   Test framework   *****************************************/
58/********************************************************************************************/
59 #include "testfrmw.h"
60 #include "testfrmw.c"
61 /* This header is responsible for defining the following macros:
62  * UNRESOLVED(ret, descr);
63  *    where descr is a description of the error and ret is an int (error code for example)
64  * FAILED(descr);
65  *    where descr is a short text saying why the test has failed.
66  * PASSED();
67  *    No parameter.
68  *
69  * Both three macros shall terminate the calling process.
70  * The testcase shall not terminate in any other maneer.
71  *
72  * The other file defines the functions
73  * void output_init()
74  * void output(char * string, ...)
75  *
76  * Those may be used to output information.
77  */
78
79/********************************************************************************************/
80/********************************** Configuration ******************************************/
81/********************************************************************************************/
82#ifndef VERBOSE
83#define VERBOSE 1
84#endif
85
86/********************************************************************************************/
87/***********************************    Test cases  *****************************************/
88/********************************************************************************************/
89
90#include "threads_scenarii.c"
91
92/* This file will define the following objects:
93 * scenarii: array of struct __scenario type.
94 * NSCENAR : macro giving the total # of scenarii
95 * scenar_init(): function to call before use the scenarii array.
96 * scenar_fini(): function to call after end of use of the scenarii array.
97 */
98
99/********************************************************************************************/
100/***********************************    Real Test   *****************************************/
101/********************************************************************************************/
102
103int global=0;
104int tab[4];
105pthread_key_t tld[3];
106
107#define CLEANUP(n) void clnp##n(void * arg)\
108{\
109	tab[global]=n; \
110	global++; \
111}
112
113/* Cancelation cleanup handlers */
114CLEANUP(1)
115CLEANUP(2)
116CLEANUP(3)
117
118/* TLD destructor */
119void destructor(void * arg)
120{
121	*(int *) arg += global;
122}
123
124/* Thread routine */
125void * threaded (void * arg)
126{
127	int ret = 0;
128
129	ret = pthread_setspecific(tld[0], (void *)&tab[3]);
130	if (ret != 0)  {  UNRESOLVED(ret, "Failed to set TLD data");  }
131
132	pthread_cleanup_push(clnp3, NULL);
133	pthread_cleanup_push(clnp2, NULL);
134	ret = pthread_setspecific(tld[1], (void *)&tab[3]);
135	if (ret != 0)  {  UNRESOLVED(ret, "Failed to set TLD data");  }
136
137	pthread_cleanup_push(clnp1, NULL);
138	ret = pthread_setspecific(tld[2], (void *)&tab[3]);
139	if (ret != 0)  {  UNRESOLVED(ret, "Failed to set TLD data");  }
140
141	pthread_exit(NULL + 1);
142
143	pthread_cleanup_pop(0);
144	pthread_cleanup_pop(0);
145	pthread_cleanup_pop(0);
146
147	FAILED("pthread_exit() did not terminate the thread");
148	return NULL;
149}
150
151
152int main (int argc, char *argv[])
153{
154	int ret=0;
155	void * rval;
156	pthread_t child;
157	int i,j;
158
159	output_init();
160
161	scenar_init();
162
163	for (j=0; j<3; j++)
164	{
165		ret = pthread_key_create(&tld[j], destructor);
166		if (ret != 0)  {  UNRESOLVED(ret, "Failed to create a TLD key");  }
167	}
168
169	for (i=0; i < NSCENAR; i++)
170	{
171		if (scenarii[i].detached == 0)
172		{
173			#if VERBOSE > 0
174			output("-----\n");
175			output("Starting test with scenario (%i): %s\n", i, scenarii[i].descr);
176			#endif
177
178			for (j=0; j<4; j++)
179				tab[j]=0;
180			global=0;
181
182			ret = pthread_create(&child, &scenarii[i].ta, threaded, NULL);
183			switch (scenarii[i].result)
184			{
185				case 0: /* Operation was expected to succeed */
186					if (ret != 0)  {  UNRESOLVED(ret, "Failed to create this thread");  }
187					break;
188
189				case 1: /* Operation was expected to fail */
190					if (ret == 0)  {  UNRESOLVED(-1, "An error was expected but the thread creation succeeded");  }
191					break;
192
193				case 2: /* We did not know the expected result */
194				default:
195					#if VERBOSE > 0
196					if (ret == 0)
197						{ output("Thread has been created successfully for this scenario\n"); }
198					else
199						{ output("Thread creation failed with the error: %s\n", strerror(ret)); }
200					#endif
201			}
202			if (ret == 0) /* The new thread is running */
203			{
204				ret = pthread_join(child, &rval);
205				if (ret != 0)  {  UNRESOLVED(ret, "Unable to join a thread");  }
206
207				if (rval != (NULL+1))
208				{
209					FAILED("pthread_join() did not retrieve the pthread_exit() param");
210				}
211
212				for (j=0; j<3; j++)
213				{
214					if ((tab[j] != j+1) || (tab[3] != 9))
215					{
216						output("dump:\ntab[0]=%i\ntab[1]=%i\ntab[2]=%i\ntab[3]=%i\n", tab[0], tab[1], tab[2], tab[3]);
217						FAILED("The cleanup handlers were not called as expected");
218					}
219				}
220			}
221		}
222	}
223
224	for (j=0; j<3; j++)
225	{
226		ret = pthread_key_delete(tld[j]);
227		if (ret != 0)  {  UNRESOLVED(ret, "Failed to delete a TLD key");  }
228	}
229
230	scenar_fini();
231	#if VERBOSE > 0
232	output("-----\n");
233	output("All test data destroyed\n");
234	output("Test PASSED\n");
235	#endif
236
237	PASSED;
238}
239
240