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