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 * This sample test aims to check the following assertion:
19 *
20 * This sample test aims to check the following assertion:
21 * The function does not return an error code of EINTR
22
23
24 * The steps are:
25 *
26 * -> Create a thread which wait in a condition for a small time.
27 * -> Another thread will signal this condition from time to time.
28 * -> Another thread which loops on sending a signal to the first thread.
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 <stdarg.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <unistd.h>
44
45 #include <semaphore.h>
46 #include <errno.h>
47 #include <signal.h>
48 #include <time.h>
49
50 /********************************************************************************************/
51 /****************************** Test framework *****************************************/
52 /********************************************************************************************/
53 #include "testfrmw.h"
54 #include "testfrmw.c"
55 /* This header is responsible for defining the following macros:
56 * UNRESOLVED(ret, descr);
57 * where descr is a description of the error and ret is an int (error code for example)
58 * FAILED(descr);
59 * where descr is a short text saying why the test has failed.
60 * PASSED();
61 * No parameter.
62 *
63 * Both three macros shall terminate the calling process.
64 * The testcase shall not terminate in any other maneer.
65 *
66 * The other file defines the functions
67 * void output_init()
68 * void output(char * string, ...)
69 *
70 * Those may be used to output information.
71 */
72
73 /********************************************************************************************/
74 /********************************** Configuration ******************************************/
75 /********************************************************************************************/
76 #define WITH_SYNCHRO
77 #ifndef VERBOSE
78 #define VERBOSE 2
79 #endif
80
81 #define TIMEOUT (1000) /* ns, timeout parameter for pthread_cond_timedwait */
82 #define INTERVAL (700) /* ns, frequency (actually, period) for the condition signaling */
83
84 /********************************************************************************************/
85 /*********************************** Test case *****************************************/
86 /********************************************************************************************/
87
88 char do_it=1;
89 unsigned long count_cnd_sig=0, count_cnd_wup=0;
90 #ifdef WITH_SYNCHRO
91 sem_t semsig1;
92 sem_t semsig2;
93 unsigned long count_sig=0;
94 #endif
95
96 sigset_t usersigs;
97
98 typedef struct
99 {
100 int sig;
101 #ifdef WITH_SYNCHRO
102 sem_t *sem;
103 #endif
104 } thestruct;
105
106 struct
107 {
108 pthread_mutex_t mtx;
109 pthread_cond_t cnd;
110 } data;
111
112 /* the following function keeps on sending the signal to the process */
sendsig(void * arg)113 void * sendsig (void * arg)
114 {
115 thestruct *thearg = (thestruct *) arg;
116 int ret;
117 pid_t process;
118
119 process=getpid();
120
121 /* We block the signals SIGUSR1 and SIGUSR2 for this THREAD */
122 ret = pthread_sigmask(SIG_BLOCK, &usersigs, NULL);
123 if (ret != 0) { UNRESOLVED(ret, "Unable to block SIGUSR1 and SIGUSR2 in signal thread"); }
124
125 while (do_it)
126 {
127 #ifdef WITH_SYNCHRO
128 if ((ret = sem_wait(thearg->sem)))
129 { UNRESOLVED(errno, "Sem_wait in sendsig"); }
130 count_sig++;
131 #endif
132
133 ret = kill(process, thearg->sig);
134 if (ret != 0) { UNRESOLVED(errno, "Kill in sendsig"); }
135
136 }
137
138 return NULL;
139 }
140
141 /* Next are the signal handlers. */
142 /* This one is registered for signal SIGUSR1 */
sighdl1(int sig)143 void sighdl1(int sig)
144 {
145 #ifdef WITH_SYNCHRO
146 if (sem_post(&semsig1))
147 { UNRESOLVED(errno, "Sem_post in signal handler 1"); }
148 #endif
149 }
150 /* This one is registered for signal SIGUSR2 */
sighdl2(int sig)151 void sighdl2(int sig)
152 {
153 #ifdef WITH_SYNCHRO
154 if (sem_post(&semsig2))
155 { UNRESOLVED(errno, "Sem_post in signal handler 2"); }
156 #endif
157 }
158
159 /* The following function will timedwait on the cond
160 * it does check that no error code of EINTR is returned */
waiter(void * arg)161 void * waiter(void * arg)
162 {
163 int ret;
164 struct timespec ts;
165
166 /* We don't block the signals SIGUSR1 and SIGUSR2 for this THREAD */
167 ret = pthread_sigmask(SIG_UNBLOCK, &usersigs, NULL);
168 if (ret != 0) { UNRESOLVED(ret, "Unable to unblock SIGUSR1 and SIGUSR2 in worker thread"); }
169
170 ret = pthread_mutex_lock(&(data.mtx));
171 if (ret != 0) { UNRESOLVED(ret, "Unable to lock mutex in waiter thread"); }
172
173 while (do_it)
174 {
175 ret = clock_gettime(CLOCK_REALTIME, &ts);
176 if (ret != 0) { UNRESOLVED(ret, "Unable to get system time"); }
177
178 ts.tv_nsec += TIMEOUT;
179 while (ts.tv_nsec >= 1000000000)
180 {
181 ts.tv_nsec -= 1000000000;
182 ts.tv_sec += 1;
183 }
184
185 do
186 {
187 ret = pthread_cond_timedwait(&(data.cnd),&(data.mtx),&ts);
188 count_cnd_wup++;
189 } while (ret == 0);
190
191 if (ret == EINTR)
192 {
193 FAILED("pthread_cond_timedwait returned EINTR");
194 }
195
196 if (ret != ETIMEDOUT)
197 {
198 UNRESOLVED(ret, "pthread_cond_timedwait returned an unexpected error");
199 }
200 }
201
202 ret = pthread_mutex_unlock(&(data.mtx));
203 if (ret != 0) { UNRESOLVED(ret, "Unable to unlock mutex in waiter thread"); }
204
205 return NULL;
206 }
207
208
209 /* The next function will signal the condition at periodic interval */
worker(void * arg)210 void * worker (void * arg)
211 {
212 int ret=0;
213
214 struct timespec ts, tsrem;
215
216 /* We block the signals SIGUSR1 and SIGUSR2 for this THREAD */
217 ret = pthread_sigmask(SIG_BLOCK, &usersigs, NULL);
218 if (ret != 0) { UNRESOLVED(ret, "Unable to block SIGUSR1 and SIGUSR2 in signal thread"); }
219
220 ts.tv_sec=0;
221 ts.tv_nsec= INTERVAL;
222 while (ts.tv_nsec >= 1000000000)
223 {
224 ts.tv_nsec -= 1000000000;
225 ts.tv_sec +=1;
226 }
227
228 while (do_it)
229 {
230 tsrem.tv_sec = ts.tv_sec;
231 tsrem.tv_nsec = ts.tv_nsec;
232
233 do { ret = nanosleep(&tsrem, &tsrem); }
234 while ((ret != 0) && (errno == EINTR));
235
236 ret = pthread_cond_signal(&(data.cnd));
237 if (ret != 0) { UNRESOLVED(ret, "Failed to signal the condition"); }
238 count_cnd_sig++;
239 }
240
241 return NULL;
242 }
243
244 /* Main function */
main(int argc,char * argv[])245 int main (int argc, char * argv[])
246 {
247 int ret;
248 pthread_t th_waiter, th_worker, th_sig1, th_sig2;
249 thestruct arg1, arg2;
250 struct sigaction sa;
251
252 output_init();
253
254 /* We need to register the signal handlers for the PROCESS */
255 sigemptyset (&sa.sa_mask);
256 sa.sa_flags = 0;
257 sa.sa_handler = sighdl1;
258 if ((ret = sigaction (SIGUSR1, &sa, NULL)))
259 { UNRESOLVED(ret, "Unable to register signal handler1"); }
260 sa.sa_handler = sighdl2;
261 if ((ret = sigaction (SIGUSR2, &sa, NULL)))
262 { UNRESOLVED(ret, "Unable to register signal handler2"); }
263
264 /* We prepare a signal set which includes SIGUSR1 and SIGUSR2 */
265 sigemptyset(&usersigs);
266 ret = sigaddset(&usersigs, SIGUSR1);
267 ret |= sigaddset(&usersigs, SIGUSR2);
268 if (ret != 0) { UNRESOLVED(ret, "Unable to add SIGUSR1 or 2 to a signal set"); }
269
270 /* We now block the signals SIGUSR1 and SIGUSR2 for this THREAD */
271 ret = pthread_sigmask(SIG_BLOCK, &usersigs, NULL);
272 if (ret != 0) { UNRESOLVED(ret, "Unable to block SIGUSR1 and SIGUSR2 in main thread"); }
273
274
275
276 #ifdef WITH_SYNCHRO
277 if (sem_init(&semsig1, 0, 1))
278 { UNRESOLVED(errno, "Semsig1 init"); }
279 if (sem_init(&semsig2, 0, 1))
280 { UNRESOLVED(errno, "Semsig2 init"); }
281 #endif
282
283 if ((ret = pthread_create(&th_waiter, NULL, waiter, NULL)))
284 { UNRESOLVED(ret, "Waiter thread creation failed"); }
285
286 if ((ret = pthread_create(&th_worker, NULL, worker, NULL)))
287 { UNRESOLVED(ret, "Worker thread creation failed"); }
288
289 arg1.sig = SIGUSR1;
290 arg2.sig = SIGUSR2;
291 #ifdef WITH_SYNCHRO
292 arg1.sem = &semsig1;
293 arg2.sem = &semsig2;
294 #endif
295
296 if ((ret = pthread_create(&th_sig1, NULL, sendsig, (void *)&arg1)))
297 { UNRESOLVED(ret, "Signal 1 sender thread creation failed"); }
298 if ((ret = pthread_create(&th_sig2, NULL, sendsig, (void *)&arg2)))
299 { UNRESOLVED(ret, "Signal 2 sender thread creation failed"); }
300
301 /* Let's wait for a while now */
302 sleep(1);
303
304 /* Now stop the threads and join them */
305 do { do_it=0; }
306 while (do_it);
307
308 if ((ret = pthread_join(th_sig1, NULL)))
309 { UNRESOLVED(ret, "Signal 1 sender thread join failed"); }
310 if ((ret = pthread_join(th_sig2, NULL)))
311 { UNRESOLVED(ret, "Signal 2 sender thread join failed"); }
312 if ((ret = pthread_join(th_worker, NULL)))
313 { UNRESOLVED(ret, "Worker thread join failed"); }
314 if ((ret = pthread_join(th_waiter, NULL)))
315 { UNRESOLVED(ret, "Waiter thread join failed"); }
316
317 #if VERBOSE > 0
318 output("Test executed successfully.\n");
319 output(" Condition was signaled %d times.\n", count_cnd_sig);
320 output(" pthread_timed_wait exited %d times.\n", count_cnd_wup);
321 #ifdef WITH_SYNCHRO
322 output(" %d signals were sent meanwhile.\n", count_sig);
323 #endif
324 #endif
325 PASSED;
326 }
327