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
19 * This sample test aims to check the following assertion:
20 * The function does not return an error code of EINTR
21
22
23 * The steps are:
24 *
25 * -> Create a thread which loops on pthread_mutex_lock and pthread_mutex_unlock
26 *      operations.
27 * -> Create another thread which loops on sending a signal to the first thread.
28 *
29 *
30 */
31
32 /*
33  * - adam.li@intel.com 2004-05-13
34  *   Add to PTS. Please refer to http://nptl.bullopensource.org/phpBB/
35  *   for general information
36  */
37
38 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
39 #define _POSIX_C_SOURCE 200112L
40
41 /* We enable the following line to have mutex attributes defined */
42#ifndef WITHOUT_XOPEN
43 #define _XOPEN_SOURCE	600
44#endif
45
46/********************************************************************************************/
47/****************************** standard includes *****************************************/
48/********************************************************************************************/
49 #include <pthread.h>
50 #include <semaphore.h>
51 #include <errno.h>
52 #include <signal.h>
53 #include <unistd.h>
54 #include <stdlib.h>
55 #include <stdio.h>
56 #include <stdarg.h>
57
58/********************************************************************************************/
59/******************************   Test framework   *****************************************/
60/********************************************************************************************/
61 #include "testfrmw.h"
62 #include "testfrmw.c"
63 /* This header is responsible for defining the following macros:
64  * UNRESOLVED(ret, descr);
65  *    where descr is a description of the error and ret is an int (error code for example)
66  * FAILED(descr);
67  *    where descr is a short text saying why the test has failed.
68  * PASSED();
69  *    No parameter.
70  *
71  * Both three macros shall terminate the calling process.
72  * The testcase shall not terminate in any other maneer.
73  *
74  * The other file defines the functions
75  * void output_init()
76  * void output(char * string, ...)
77  *
78  * Those may be used to output information.
79  */
80
81/********************************************************************************************/
82/********************************** Configuration ******************************************/
83/********************************************************************************************/
84#define WITH_SYNCHRO
85#ifndef VERBOSE
86#define VERBOSE 1
87#endif
88
89/********************************************************************************************/
90/***********************************    Test case   *****************************************/
91/********************************************************************************************/
92char do_it=1;
93unsigned long count_ope=0;
94pthread_mutex_t count_protect = PTHREAD_MUTEX_INITIALIZER;
95#ifdef WITH_SYNCHRO
96sem_t semsig1;
97sem_t semsig2;
98unsigned long count_sig=0;
99#endif
100sem_t semsync;
101
102typedef struct
103{
104	pthread_t   	*thr;
105	int	sig;
106#ifdef WITH_SYNCHRO
107	sem_t	*sem;
108#endif
109} thestruct;
110
111/* the following function keeps on sending the signal to the thread pointed by arg
112 *  If WITH_SYNCHRO is defined, the target thread has a handler for the signal */
113void * sendsig (void * arg)
114{
115	thestruct *thearg = (thestruct *) arg;
116	int ret;
117	while (do_it)
118	{
119		#ifdef WITH_SYNCHRO
120		if ((ret = sem_wait(thearg->sem)))
121		{ UNRESOLVED(errno, "Sem_wait in sendsig"); }
122		count_sig++;
123		#endif
124
125		if ((ret = pthread_kill (*(thearg->thr), thearg->sig)))
126		{ UNRESOLVED(ret, "Pthread_kill in sendsig"); }
127
128	}
129
130	return NULL;
131}
132
133/* Next are the signal handlers. */
134void sighdl1(int sig)
135{
136#ifdef WITH_SYNCHRO
137	if ((sem_post(&semsig1)))
138	{ UNRESOLVED(errno, "Sem_post in signal handler 1"); }
139#endif
140}
141void sighdl2(int sig)
142{
143#ifdef WITH_SYNCHRO
144	if ((sem_post(&semsig2)))
145	{ UNRESOLVED(errno, "Sem_post in signal handler 2"); }
146#endif
147}
148
149/* The following function loops on init/destroy some mutex (with different attributes)
150 * it does check that no error code of EINTR is returned */
151
152void * threaded(void * arg)
153{
154	pthread_mutexattr_t ma[4], *pma[5];
155	pthread_mutex_t m[5];
156	int i;
157	int ret;
158
159	/* We need to register the signal handlers */
160	struct sigaction sa;
161	sigemptyset (&sa.sa_mask);
162	sa.sa_flags = 0;
163	sa.sa_handler = sighdl1;
164	if ((ret = sigaction (SIGUSR1, &sa, NULL)))
165	{ UNRESOLVED(ret, "Unable to register signal handler1"); }
166	sa.sa_handler = sighdl2;
167	if ((ret = sigaction (SIGUSR2, &sa, NULL)))
168	{ UNRESOLVED(ret, "Unable to register signal handler2"); }
169
170	/* Initialize the different mutex */
171	pma[4]=NULL;
172
173	for (i=0; i<4; i++)
174	{
175		pma[i]=&ma[i];
176		if ((ret = pthread_mutexattr_init(pma[i])))
177		{ UNRESOLVED(ret, "pthread_mutexattr_init"); }
178	}
179
180	#ifndef WITHOUT_XOPEN
181		if ((ret = pthread_mutexattr_settype(pma[0], PTHREAD_MUTEX_NORMAL)))
182		{ UNRESOLVED(ret, "pthread_mutexattr_settype (normal)"); }
183		if ((ret = pthread_mutexattr_settype(pma[1], PTHREAD_MUTEX_ERRORCHECK)))
184		{ UNRESOLVED(ret, "pthread_mutexattr_settype (errorcheck)"); }
185		if ((ret = pthread_mutexattr_settype(pma[2], PTHREAD_MUTEX_RECURSIVE)))
186		{ UNRESOLVED(ret, "pthread_mutexattr_settype (recursive)"); }
187		if ((ret = pthread_mutexattr_settype(pma[3], PTHREAD_MUTEX_DEFAULT)))
188		{ UNRESOLVED(ret, "pthread_mutexattr_settype (default)"); }
189		#if VERBOSE >1
190		output("Mutex attributes NORMAL,ERRORCHECK,RECURSIVE,DEFAULT initialized\n");
191		#endif
192	#else
193		#if VERBOSE > 0
194		output("Mutex attributes NORMAL,ERRORCHECK,RECURSIVE,DEFAULT unavailable\n");
195		#endif
196	#endif
197
198	for (i=0; i<5; i++)
199	{
200		ret = pthread_mutex_init(&m[i], pma[i]);
201		if (ret == EINTR)
202		{
203			FAILED("pthread_mutex_init returned EINTR");
204		}
205		if (ret != 0)
206		{
207			UNRESOLVED(ret, "pthread_mutex_init failed");
208		}
209	}
210	/* The mutex are ready, we will loop on lock/unlock now */
211
212	while (do_it)
213	{
214		for (i=0; i<5; i++)
215		{
216			ret = pthread_mutex_lock(&m[i]);
217			if (ret == EINTR)
218			{
219				FAILED("pthread_mutex_lock returned EINTR");
220			}
221			if (ret != 0)
222			{
223				UNRESOLVED(ret, "pthread_mutex_lock failed");
224			}
225			ret = pthread_mutex_unlock(&m[i]);
226			if (ret == EINTR)
227			{
228				FAILED("pthread_mutex_unlock returned EINTR");
229			}
230			if (ret != 0)
231			{
232				UNRESOLVED(ret, "pthread_mutex_unlock failed");
233			}
234		}
235		ret = pthread_mutex_lock(&count_protect);
236		if (ret == EINTR)
237		{
238			FAILED("pthread_mutex_lock returned EINTR");
239		}
240		if (ret != 0)
241		{
242			UNRESOLVED(ret, "pthread_mutex_lock failed");
243		}
244		count_ope++;
245		pthread_mutex_unlock(&count_protect);
246		if (ret == EINTR)
247		{
248			FAILED("pthread_mutex_unlock returned EINTR");
249		}
250		if (ret != 0)
251		{
252			UNRESOLVED(ret, "pthread_mutex_unlock failed");
253		}
254	}
255
256	/* Now we can destroy the mutex objects */
257	for (i=0; i<4; i++)
258	{
259		if ((ret = pthread_mutexattr_destroy(pma[i])))
260		{ UNRESOLVED(ret, "pthread_mutexattr_init"); }
261	}
262	for (i=0; i<5; i++)
263	{
264		ret = pthread_mutex_destroy(&m[i]);
265		if (ret == EINTR)
266		{
267			FAILED("pthread_mutex_destroy returned EINTR");
268		}
269		if (ret != 0)
270		{
271			UNRESOLVED(ret, "pthread_mutex_destroy failed");
272		}
273	}
274
275	do {
276		ret = sem_wait(&semsync);
277	} while (ret && (errno ==  EINTR));
278	if (ret)
279	{ UNRESOLVED(errno, "Could not wait for sig senders termination"); }
280
281	return NULL;
282}
283
284/* At last (but not least) we need a main */
285int main (int argc, char * argv[])
286{
287	int ret;
288	pthread_t th_work, th_sig1, th_sig2;
289	thestruct arg1, arg2;
290
291	output_init();
292
293	#ifdef WITH_SYNCHRO
294	#if VERBOSE >1
295	output("Running in synchronized mode\n");
296	#endif
297	if ((sem_init(&semsig1, 0, 1)))
298	{ UNRESOLVED(errno, "Semsig1  init"); }
299	if ((sem_init(&semsig2, 0, 1)))
300	{ UNRESOLVED(errno, "Semsig2  init"); }
301	#endif
302
303	if ((sem_init(&semsync, 0, 0)))
304	{ UNRESOLVED(errno, "semsync init"); }
305
306	#if VERBOSE >1
307	output("Starting the worker thread\n");
308	#endif
309	if ((ret = pthread_create(&th_work, NULL, threaded, NULL)))
310	{ UNRESOLVED(ret, "Worker thread creation failed"); }
311
312	arg1.thr = &th_work;
313	arg2.thr = &th_work;
314	arg1.sig = SIGUSR1;
315	arg2.sig = SIGUSR2;
316#ifdef WITH_SYNCHRO
317	arg1.sem = &semsig1;
318	arg2.sem = &semsig2;
319#endif
320
321	#if VERBOSE >1
322	output("Starting the signal sources\n");
323	#endif
324	if ((ret = pthread_create(&th_sig1, NULL, sendsig, (void *)&arg1)))
325	{ UNRESOLVED(ret, "Signal 1 sender thread creation failed"); }
326	if ((ret = pthread_create(&th_sig2, NULL, sendsig, (void *)&arg2)))
327	{ UNRESOLVED(ret, "Signal 2 sender thread creation failed"); }
328
329	/* Let's wait for a while now */
330	#if VERBOSE >1
331	output("Let the worker be killed for a second\n");
332	#endif
333	sleep(1);
334
335	/* Now stop the threads and join them */
336	#if VERBOSE >1
337	output("Stop everybody\n");
338	#endif
339	do { do_it=0; }
340	while (do_it);
341
342	if ((ret = pthread_join(th_sig1, NULL)))
343	{ UNRESOLVED(ret, "Signal 1 sender thread join failed"); }
344	if ((ret = pthread_join(th_sig2, NULL)))
345	{ UNRESOLVED(ret, "Signal 2 sender thread join failed"); }
346
347	#if VERBOSE >1
348	output("Signal sources are stopped, we can stop the worker\n");
349	#endif
350	if ((sem_post(&semsync)))
351	{ UNRESOLVED(errno, "could not post semsync"); }
352
353	if ((ret = pthread_join(th_work, NULL)))
354	{ UNRESOLVED(ret, "Worker thread join failed"); }
355
356	#if VERBOSE > 0
357	output("Test executed successfully.\n");
358	output("  %d mutex lock and unlock were done.\n", count_ope);
359	#ifdef WITH_SYNCHRO
360	output("  %d signals were sent meanwhile.\n", count_sig);
361	#endif
362	#endif
363	PASSED;
364}
365