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_cond_init and pthread_cond_destroy
26 *      operations.
27 * -> Create another thread which loops on sending a signal to the first thread.
28 *
29 *
30 */
31
32 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
33 #define _POSIX_C_SOURCE 200112L
34
35
36/********************************************************************************************/
37/****************************** standard includes *****************************************/
38/********************************************************************************************/
39 #include <pthread.h>
40 #include <semaphore.h>
41 #include <errno.h>
42 #include <signal.h>
43 #include <unistd.h>
44 #include <stdio.h>
45 #include <stdarg.h>
46 #include <stdlib.h>
47
48/********************************************************************************************/
49/******************************   Test framework   *****************************************/
50/********************************************************************************************/
51 #include "testfrmw.h"
52 #include "testfrmw.c"
53 /* This header is responsible for defining the following macros:
54  * UNRESOLVED(ret, descr);
55  *    where descr is a description of the error and ret is an int (error code for example)
56  * FAILED(descr);
57  *    where descr is a short text saying why the test has failed.
58  * PASSED();
59  *    No parameter.
60  *
61  * Both three macros shall terminate the calling process.
62  * The testcase shall not terminate in any other maneer.
63  *
64  * The other file defines the functions
65  * void output_init()
66  * void output(char * string, ...)
67  *
68  * Those may be used to output information.
69  */
70
71/********************************************************************************************/
72/********************************** Configuration ******************************************/
73/********************************************************************************************/
74#define WITH_SYNCHRO
75#ifndef VERBOSE
76#define VERBOSE 2
77#endif
78
79/********************************************************************************************/
80/***********************************    Test case   *****************************************/
81/********************************************************************************************/
82char do_it=1;
83unsigned long count_ope=0;
84pthread_mutex_t count_protect = PTHREAD_MUTEX_INITIALIZER;
85#ifdef WITH_SYNCHRO
86sem_t semsig1;
87sem_t semsig2;
88unsigned long count_sig=0;
89#endif
90sem_t semsync;
91
92typedef struct
93{
94	pthread_t   	*thr;
95	int	sig;
96#ifdef WITH_SYNCHRO
97	sem_t	*sem;
98#endif
99} thestruct;
100
101/* the following function keeps on sending the signal to the thread pointed by arg
102 *  If WITH_SYNCHRO is defined, the target thread has a handler for the signal */
103void * sendsig (void * arg)
104{
105	thestruct *thearg = (thestruct *) arg;
106	int ret;
107	while (do_it)
108	{
109		#ifdef WITH_SYNCHRO
110		if ((ret = sem_wait(thearg->sem)))
111		{ UNRESOLVED(errno, "Sem_wait in sendsig"); }
112		count_sig++;
113		#endif
114
115		if ((ret = pthread_kill (*(thearg->thr), thearg->sig)))
116		{ UNRESOLVED(ret, "Pthread_kill in sendsig"); }
117
118	}
119
120	return NULL;
121}
122
123/* Next are the signal handlers. */
124void sighdl1(int sig)
125{
126#ifdef WITH_SYNCHRO
127	if (sem_post(&semsig1))
128	{ UNRESOLVED(errno, "Sem_post in signal handler 1"); }
129#endif
130}
131void sighdl2(int sig)
132{
133#ifdef WITH_SYNCHRO
134	if (sem_post(&semsig2))
135	{ UNRESOLVED(errno, "Sem_post in signal handler 2"); }
136#endif
137}
138
139/* The following function loops on init/destroy some condvars (with different attributes)
140 * it does check that no error code of EINTR is returned */
141
142void * threaded(void * arg)
143{
144	pthread_condattr_t ca[4], *pca[5];
145	pthread_cond_t c[5];
146	int i;
147	int ret;
148
149	/* We need to register the signal handlers */
150	struct sigaction sa;
151	sigemptyset (&sa.sa_mask);
152	sa.sa_flags = 0;
153	sa.sa_handler = sighdl1;
154	if ((ret = sigaction (SIGUSR1, &sa, NULL)))
155	{ UNRESOLVED(ret, "Unable to register signal handler1"); }
156	sa.sa_handler = sighdl2;
157	if ((ret = sigaction (SIGUSR2, &sa, NULL)))
158	{ UNRESOLVED(ret, "Unable to register signal handler2"); }
159
160	/* Initialize the different cond attributes */
161	pca[4]=NULL;
162
163	for (i=0; i<4; i++)
164	{
165		pca[i]=&ca[i];
166		if ((ret = pthread_condattr_init(pca[i])))
167		{ UNRESOLVED(ret, "pthread_condattr_init"); }
168	}
169
170		ret = pthread_condattr_setpshared(pca[0], PTHREAD_PROCESS_SHARED);
171		if (ret != 0) {  UNRESOLVED(ret, "Cond attribute PSHARED failed");  }
172		ret = pthread_condattr_setpshared(pca[1], PTHREAD_PROCESS_SHARED);
173		if (ret != 0) {  UNRESOLVED(ret, "Cond attribute PSHARED failed");  }
174
175		#if VERBOSE >1
176		output("PShared condvar attributes initialized\n");
177		#endif
178		if (sysconf(_SC_MONOTONIC_CLOCK) > 0)
179		{
180			ret = pthread_condattr_setclock(pca[1], CLOCK_MONOTONIC);
181			if (ret != 0) {  UNRESOLVED(ret, "Cond set monotonic clock failed");  }
182			ret = pthread_condattr_setclock(pca[2], CLOCK_MONOTONIC);
183			if (ret != 0) {  UNRESOLVED(ret, "Cond set monotonic clock failed");  }
184			#if VERBOSE >1
185			output("Alternative clock condvar attributes initialized\n");
186			#endif
187		}
188
189	/*	We are ready to proceed */
190	while (do_it)
191	{
192		for (i=0; i<5; i++)
193		{
194			ret = pthread_cond_init(&c[i], pca[i]);
195			if (ret == EINTR)
196			{
197				FAILED("pthread_cond_init returned EINTR");
198			}
199			if (ret != 0)
200			{
201				UNRESOLVED(ret, "pthread_cond_init failed");
202			}
203			ret = pthread_cond_destroy(&c[i]);
204			if (ret == EINTR)
205			{
206				FAILED("pthread_cond_destroy returned EINTR");
207			}
208			if (ret != 0)
209			{
210				UNRESOLVED(ret, "pthread_cond_destroy failed");
211			}
212			pthread_mutex_lock(&count_protect);
213			count_ope++;
214			pthread_mutex_unlock(&count_protect);
215		}
216	}
217
218	/* Now we can destroy the mutex attributes objects */
219	for (i=0; i<4; i++)
220	{
221		if ((ret = pthread_condattr_destroy(pca[i])))
222		{ UNRESOLVED(ret, "pthread_condattr_init"); }
223	}
224
225	do {
226		ret = sem_wait(&semsync);
227	} while (ret && (errno ==  EINTR));
228	if (ret)
229	{ UNRESOLVED(errno, "Could not wait for sig senders termination"); }
230
231	return NULL;
232}
233
234/* Main function */
235int main (int argc, char * argv[])
236{
237	int ret;
238	pthread_t th_work, th_sig1, th_sig2;
239	thestruct arg1, arg2;
240
241	output_init();
242
243	#ifdef WITH_SYNCHRO
244	if (sem_init(&semsig1, 0, 1))
245	{ UNRESOLVED(errno, "Semsig1  init"); }
246	if (sem_init(&semsig2, 0, 1))
247	{ UNRESOLVED(errno, "Semsig2  init"); }
248	#endif
249
250	if (sem_init(&semsync, 0, 0))
251	{ UNRESOLVED(errno, "semsync init"); }
252
253	if ((ret = pthread_create(&th_work, NULL, threaded, NULL)))
254	{ UNRESOLVED(ret, "Worker thread creation failed"); }
255
256	arg1.thr = &th_work;
257	arg2.thr = &th_work;
258	arg1.sig = SIGUSR1;
259	arg2.sig = SIGUSR2;
260#ifdef WITH_SYNCHRO
261	arg1.sem = &semsig1;
262	arg2.sem = &semsig2;
263#endif
264
265	if ((ret = pthread_create(&th_sig1, NULL, sendsig, (void *)&arg1)))
266	{ UNRESOLVED(ret, "Signal 1 sender thread creation failed"); }
267	if ((ret = pthread_create(&th_sig2, NULL, sendsig, (void *)&arg2)))
268	{ UNRESOLVED(ret, "Signal 2 sender thread creation failed"); }
269
270	/* Let's wait for a while now */
271	sleep(1);
272
273	/* Now stop the threads and join them */
274	do { do_it=0; }
275	while (do_it);
276
277	if ((ret = pthread_join(th_sig1, NULL)))
278	{ UNRESOLVED(ret, "Signal 1 sender thread join failed"); }
279	if ((ret = pthread_join(th_sig2, NULL)))
280	{ UNRESOLVED(ret, "Signal 2 sender thread join failed"); }
281
282	if (sem_post(&semsync))
283	{ UNRESOLVED(errno, "could not post semsync"); }
284
285	if ((ret = pthread_join(th_work, NULL)))
286	{ UNRESOLVED(ret, "Worker thread join failed"); }
287
288	#if VERBOSE > 0
289	output("Test executed successfully.\n");
290	output("  %d condvars initialization and destruction were done.\n", count_ope);
291	#ifdef WITH_SYNCHRO
292	output("  %d signals were sent meanwhile.\n", count_sig);
293	#endif
294	#endif
295	PASSED;
296}
297