1/*
2* Copyright (c) 2005, 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 function does not return EINTR
21
22* The steps are:
23* -> kill a thread which calls pthread_join
24* -> check that EINTR is never returned
25
26*/
27
28
29/* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
30#define _POSIX_C_SOURCE 200112L
31
32/********************************************************************************************/
33/****************************** standard includes *****************************************/
34/********************************************************************************************/
35#include <pthread.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41
42#include <semaphore.h>
43 #include <errno.h>
44 #include <signal.h>
45
46/********************************************************************************************/
47/******************************   Test framework   *****************************************/
48/********************************************************************************************/
49#include "testfrmw.h"
50 #include "testfrmw.c"
51/* This header is responsible for defining the following macros:
52 * UNRESOLVED(ret, descr);
53 *    where descr is a description of the error and ret is an int (error code for example)
54 * FAILED(descr);
55 *    where descr is a short text saying why the test has failed.
56 * PASSED();
57 *    No parameter.
58 *
59 * Both three macros shall terminate the calling process.
60 * The testcase shall not terminate in any other maneer.
61 *
62 * The other file defines the functions
63 * void output_init()
64 * void output(char * string, ...)
65 *
66 * Those may be used to output information.
67 */
68
69/********************************************************************************************/
70/********************************** Configuration ******************************************/
71/********************************************************************************************/
72#ifndef VERBOSE
73#define VERBOSE 1
74#endif
75
76#define WITH_SYNCHRO
77
78
79/********************************************************************************************/
80/***********************************     Helper     *****************************************/
81/********************************************************************************************/
82#include "threads_scenarii.c"
83/* this file defines:
84* scenarii: array of struct __scenario type.
85* NSCENAR : macro giving the total # of scenarii
86* scenar_init(): function to call before use the scenarii array.
87* scenar_fini(): function to call after end of use of the scenarii array.
88*/
89
90/********************************************************************************************/
91/***********************************    Test cases  *****************************************/
92/********************************************************************************************/
93
94char do_it = 1;
95unsigned long count_ope = 0;
96#ifdef WITH_SYNCHRO
97sem_t semsig1;
98sem_t semsig2;
99unsigned long count_sig = 0;
100#endif
101
102sigset_t usersigs;
103
104typedef struct
105{
106	int sig;
107#ifdef WITH_SYNCHRO
108	sem_t *sem;
109#endif
110}
111
112thestruct;
113
114/* the following function keeps on sending the signal to the process */
115void * sendsig ( void * arg )
116{
117	thestruct * thearg = ( thestruct * ) arg;
118	int ret;
119	pid_t process;
120
121	process = getpid();
122
123	/* We block the signals SIGUSR1 and SIGUSR2 for this THREAD */
124	ret = pthread_sigmask( SIG_BLOCK, &usersigs, NULL );
125
126	if ( ret != 0 )
127	{
128		UNRESOLVED( ret, "Unable to block SIGUSR1 and SIGUSR2 in signal thread" );
129	}
130
131	while ( do_it )
132	{
133#ifdef WITH_SYNCHRO
134
135		if ( ( ret = sem_wait( thearg->sem ) ) )
136		{
137			UNRESOLVED( errno, "Sem_wait in sendsig" );
138		}
139
140		count_sig++;
141#endif
142
143		ret = kill( process, thearg->sig );
144
145		if ( ret != 0 )
146		{
147			UNRESOLVED( errno, "Kill in sendsig" );
148		}
149
150	}
151
152	return NULL;
153}
154
155/* Next are the signal handlers. */
156/* This one is registered for signal SIGUSR1 */
157void sighdl1( int sig )
158{
159#ifdef WITH_SYNCHRO
160
161	if ( sem_post( &semsig1 ) )
162	{
163		UNRESOLVED( errno, "Sem_post in signal handler 1" );
164	}
165
166#endif
167}
168
169/* This one is registered for signal SIGUSR2 */
170void sighdl2( int sig )
171{
172#ifdef WITH_SYNCHRO
173
174	if ( sem_post( &semsig2 ) )
175	{
176		UNRESOLVED( errno, "Sem_post in signal handler 2" );
177	}
178
179#endif
180}
181
182/* thread function */
183void *threaded( void* arg )
184{
185	/* do nothing */
186	sched_yield();
187
188	return NULL;
189}
190
191
192/* Test function -- calls pthread_join() and checks that EINTR is never returned. */
193void * test( void * arg )
194{
195	int ret = 0;
196	pthread_t child;
197
198	/* We don't block the signals SIGUSR1 and SIGUSR2 for this THREAD */
199	ret = pthread_sigmask( SIG_UNBLOCK, &usersigs, NULL );
200
201	if ( ret != 0 )
202	{
203		UNRESOLVED( ret, "Unable to unblock SIGUSR1 and SIGUSR2 in worker thread" );
204	}
205
206
207	while ( do_it )
208	{
209		for ( sc = 0; sc < NSCENAR; sc++ )
210		{
211			ret = pthread_create( &child, &scenarii[ sc ].ta, threaded, NULL );
212
213			if ( ( scenarii[ sc ].result == 0 ) && ( ret != 0 ) )
214			{
215				UNRESOLVED( ret, "Failed to create this thread" );
216			}
217
218			if ( ( scenarii[ sc ].result == 1 ) && ( ret == 0 ) )
219			{
220
221				UNRESOLVED( -1, "An error was expected but the thread creation succeeded" );
222			}
223
224
225			if ( ret == 0 )                    /* The new thread is running */
226			{
227				count_ope++;
228
229				ret = pthread_join( child, NULL );
230
231				if ( ret == EINTR )
232				{
233					FAILED( "pthread_join returned EINTR" );
234				}
235
236				if ( ret != 0 )
237				{
238					UNRESOLVED( ret, "Unable to join a thread" );
239				}
240
241			}
242		}
243	}
244
245	return NULL;
246}
247
248/* Main function */
249int main ( int argc, char * argv[] )
250{
251	int ret;
252	pthread_t th_work, th_sig1, th_sig2;
253	thestruct arg1, arg2;
254
255	struct sigaction sa;
256
257	/* Initialize output routine */
258	output_init();
259
260	/* We need to register the signal handlers for the PROCESS */
261	sigemptyset ( &sa.sa_mask );
262	sa.sa_flags = 0;
263	sa.sa_handler = sighdl1;
264
265	if ( ( ret = sigaction ( SIGUSR1, &sa, NULL ) ) )
266	{
267		UNRESOLVED( ret, "Unable to register signal handler1" );
268	}
269
270	sa.sa_handler = sighdl2;
271
272	if ( ( ret = sigaction ( SIGUSR2, &sa, NULL ) ) )
273	{
274		UNRESOLVED( ret, "Unable to register signal handler2" );
275	}
276
277	/* We prepare a signal set which includes SIGUSR1 and SIGUSR2 */
278	sigemptyset( &usersigs );
279
280	ret = sigaddset( &usersigs, SIGUSR1 );
281
282	ret |= sigaddset( &usersigs, SIGUSR2 );
283
284	if ( ret != 0 )
285	{
286		UNRESOLVED( ret, "Unable to add SIGUSR1 or 2 to a signal set" );
287	}
288
289	/* We now block the signals SIGUSR1 and SIGUSR2 for this THREAD */
290	ret = pthread_sigmask( SIG_BLOCK, &usersigs, NULL );
291
292	if ( ret != 0 )
293	{
294		UNRESOLVED( ret, "Unable to block SIGUSR1 and SIGUSR2 in main thread" );
295	}
296
297#ifdef WITH_SYNCHRO
298	if ( sem_init( &semsig1, 0, 1 ) )
299	{
300		UNRESOLVED( errno, "Semsig1  init" );
301	}
302
303	if ( sem_init( &semsig2, 0, 1 ) )
304	{
305		UNRESOLVED( errno, "Semsig2  init" );
306	}
307
308#endif
309
310	/* Initialize thread attribute objects */
311	scenar_init();
312
313
314	if ( ( ret = pthread_create( &th_work, NULL, test, NULL ) ) )
315	{
316		UNRESOLVED( ret, "Worker thread creation failed" );
317	}
318
319	arg1.sig = SIGUSR1;
320	arg2.sig = SIGUSR2;
321#ifdef WITH_SYNCHRO
322	arg1.sem = &semsig1;
323	arg2.sem = &semsig2;
324#endif
325
326
327
328	if ( ( ret = pthread_create( &th_sig1, NULL, sendsig, ( void * ) & arg1 ) ) )
329	{
330		UNRESOLVED( ret, "Signal 1 sender thread creation failed" );
331	}
332
333	if ( ( ret = pthread_create( &th_sig2, NULL, sendsig, ( void * ) & arg2 ) ) )
334	{
335		UNRESOLVED( ret, "Signal 2 sender thread creation failed" );
336	}
337
338
339
340	/* Let's wait for a while now */
341	sleep( 10 );
342
343
344	/* Now stop the threads and join them */
345	do
346	{
347		do_it = 0;
348	}
349	while ( do_it );
350
351
352	if ( ( ret = pthread_join( th_sig1, NULL ) ) )
353	{
354		UNRESOLVED( ret, "Signal 1 sender thread join failed" );
355	}
356
357	if ( ( ret = pthread_join( th_sig2, NULL ) ) )
358	{
359		UNRESOLVED( ret, "Signal 2 sender thread join failed" );
360	}
361
362
363	if ( ( ret = pthread_join( th_work, NULL ) ) )
364	{
365		UNRESOLVED( ret, "Worker thread join failed" );
366	}
367
368	scenar_fini();
369
370#if VERBOSE > 0
371	output( "Test executed successfully.\n" );
372
373	output( "  %d pthread_join calls.\n", count_ope );
374
375#ifdef WITH_SYNCHRO
376	output( "  %d signals were sent meanwhile.\n", count_sig );
377
378#endif
379 #endif
380	PASSED;
381}
382