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 /********************************************************************************************/
82 char do_it=1;
83 unsigned long count_ope=0;
84 pthread_mutex_t count_protect = PTHREAD_MUTEX_INITIALIZER;
85 #ifdef WITH_SYNCHRO
86 sem_t semsig1;
87 sem_t semsig2;
88 unsigned long count_sig=0;
89 #endif
90 sem_t semsync;
91 
92 typedef 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 */
sendsig(void * arg)103 void * 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. */
sighdl1(int sig)124 void 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 }
sighdl2(int sig)131 void 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 
threaded(void * arg)142 void * 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 */
main(int argc,char * argv[])235 int 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