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 * The function does not return an error code of EINTR
20
21
22 * The steps are:
23 *
24 * -> Create some threads which wait for a condition.
25 * -> Create a worker thread which broadcasts this condition.
26 * -> Another thread loops on killing the worker thread.
27 *
28 */
29
30 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
31 #define _POSIX_C_SOURCE 200112L
32
33
34 /********************************************************************************************/
35 /****************************** standard includes *****************************************/
36 /********************************************************************************************/
37 #include <pthread.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42
43 #include <semaphore.h>
44 #include <errno.h>
45 #include <signal.h>
46 #include <time.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
83 char do_it=1;
84 char woken=0;
85 unsigned long count_cnd_sig=0, count_cnd_wup=0;
86 #ifdef WITH_SYNCHRO
87 sem_t semsig1;
88 sem_t semsig2;
89 unsigned long count_sig=0;
90 #endif
91
92 sigset_t usersigs;
93
94 typedef struct
95 {
96 int sig;
97 #ifdef WITH_SYNCHRO
98 sem_t *sem;
99 #endif
100 } thestruct;
101
102 struct
103 {
104 pthread_mutex_t mtx;
105 pthread_cond_t cnd;
106 } data;
107
108 /* the following function keeps on sending the signal to the process */
sendsig(void * arg)109 void * sendsig (void * arg)
110 {
111 thestruct *thearg = (thestruct *) arg;
112 int ret;
113 pid_t process;
114
115 process=getpid();
116
117 /* We block the signals SIGUSR1 and SIGUSR2 for this THREAD */
118 ret = pthread_sigmask(SIG_BLOCK, &usersigs, NULL);
119 if (ret != 0) { UNRESOLVED(ret, "Unable to block SIGUSR1 and SIGUSR2 in signal thread"); }
120
121 while (do_it)
122 {
123 #ifdef WITH_SYNCHRO
124 if ((ret = sem_wait(thearg->sem)))
125 { UNRESOLVED(errno, "Sem_wait in sendsig"); }
126 count_sig++;
127 #endif
128
129 ret = kill(process, thearg->sig);
130 if (ret != 0) { UNRESOLVED(errno, "Kill in sendsig"); }
131
132 }
133
134 return NULL;
135 }
136
137 /* Next are the signal handlers. */
138 /* This one is registered for signal SIGUSR1 */
sighdl1(int sig)139 void sighdl1(int sig)
140 {
141 #ifdef WITH_SYNCHRO
142 if (sem_post(&semsig1))
143 { UNRESOLVED(errno, "Sem_post in signal handler 1"); }
144 #endif
145 }
146 /* This one is registered for signal SIGUSR2 */
sighdl2(int sig)147 void sighdl2(int sig)
148 {
149 #ifdef WITH_SYNCHRO
150 if (sem_post(&semsig2))
151 { UNRESOLVED(errno, "Sem_post in signal handler 2"); }
152 #endif
153 }
154
155 /* The following function will wait on the cond
156 * it does check that no error code of EINTR is returned */
waiter(void * arg)157 void * waiter(void * arg)
158 {
159 int ret;
160
161 /* We block the signals SIGUSR1 and SIGUSR2 for this THREAD */
162 ret = pthread_sigmask(SIG_BLOCK, &usersigs, NULL);
163 if (ret != 0) { UNRESOLVED(ret, "Unable to block SIGUSR1 and SIGUSR2 in signal thread"); }
164
165 ret = pthread_mutex_lock(&(data.mtx));
166 if (ret != 0) { UNRESOLVED(ret, "Unable to lock mutex in waiter thread"); }
167
168 do
169 {
170 ret = pthread_cond_wait(&(data.cnd),&(data.mtx));
171 count_cnd_wup++;
172 } while ((ret == 0) && (do_it != 0));
173 if (ret != 0)
174 {
175 UNRESOLVED(ret, "pthread_cond_wait returned an unexpected error");
176 }
177 woken++;
178
179 ret = pthread_mutex_unlock(&(data.mtx));
180 if (ret != 0) { UNRESOLVED(ret, "Unable to unlock mutex in waiter thread"); }
181
182 return NULL;
183 }
184
185
186 /* The next function will signal the condition */
worker(void * arg)187 void * worker (void * arg)
188 {
189 int ret=0;
190
191 /* We don't block the signals SIGUSR1 and SIGUSR2 for this THREAD */
192 ret = pthread_sigmask(SIG_UNBLOCK, &usersigs, NULL);
193 if (ret != 0) { UNRESOLVED(ret, "Unable to unblock SIGUSR1 and SIGUSR2 in worker thread"); }
194
195 while (woken<5)
196 {
197 ret = pthread_cond_broadcast(&(data.cnd));
198 if (ret == EINTR) { FAILED("pthread_cond_signal returned EINTR"); }
199 if (ret != 0) { UNRESOLVED(ret, "Failed to signal the condition"); }
200 count_cnd_sig++;
201 }
202
203 return NULL;
204 }
205
206 /* Main function */
main(int argc,char * argv[])207 int main (int argc, char * argv[])
208 {
209 int ret,i;
210 pthread_t th_waiter[5], th_worker, th_sig1, th_sig2;
211 thestruct arg1, arg2;
212 struct sigaction sa;
213
214 output_init();
215
216 /* We need to register the signal handlers for the PROCESS */
217 sigemptyset (&sa.sa_mask);
218 sa.sa_flags = 0;
219 sa.sa_handler = sighdl1;
220 if ((ret = sigaction (SIGUSR1, &sa, NULL)))
221 { UNRESOLVED(ret, "Unable to register signal handler1"); }
222 sa.sa_handler = sighdl2;
223 if ((ret = sigaction (SIGUSR2, &sa, NULL)))
224 { UNRESOLVED(ret, "Unable to register signal handler2"); }
225
226 /* We prepare a signal set which includes SIGUSR1 and SIGUSR2 */
227 sigemptyset(&usersigs);
228 ret = sigaddset(&usersigs, SIGUSR1);
229 ret |= sigaddset(&usersigs, SIGUSR2);
230 if (ret != 0) { UNRESOLVED(ret, "Unable to add SIGUSR1 or 2 to a signal set"); }
231
232 /* We now block the signals SIGUSR1 and SIGUSR2 for this THREAD */
233 ret = pthread_sigmask(SIG_BLOCK, &usersigs, NULL);
234 if (ret != 0) { UNRESOLVED(ret, "Unable to block SIGUSR1 and SIGUSR2 in main thread"); }
235
236
237
238 #ifdef WITH_SYNCHRO
239 if (sem_init(&semsig1, 0, 1))
240 { UNRESOLVED(errno, "Semsig1 init"); }
241 if (sem_init(&semsig2, 0, 1))
242 { UNRESOLVED(errno, "Semsig2 init"); }
243 #endif
244
245 for (i=0; i<5; i++)
246 {
247 if ((ret = pthread_create(&th_waiter[i], NULL, waiter, NULL)))
248 { UNRESOLVED(ret, "Waiter thread creation failed"); }
249 }
250
251 if ((ret = pthread_create(&th_worker, NULL, worker, NULL)))
252 { UNRESOLVED(ret, "Worker thread creation failed"); }
253
254 arg1.sig = SIGUSR1;
255 arg2.sig = SIGUSR2;
256 #ifdef WITH_SYNCHRO
257 arg1.sem = &semsig1;
258 arg2.sem = &semsig2;
259 #endif
260
261 if ((ret = pthread_create(&th_sig1, NULL, sendsig, (void *)&arg1)))
262 { UNRESOLVED(ret, "Signal 1 sender thread creation failed"); }
263 if ((ret = pthread_create(&th_sig2, NULL, sendsig, (void *)&arg2)))
264 { UNRESOLVED(ret, "Signal 2 sender thread creation failed"); }
265
266 /* Let's wait for a while now */
267 sleep(1);
268
269 /* Now stop the threads and join them */
270 do { do_it=0; }
271 while (do_it);
272
273 if ((ret = pthread_join(th_sig1, NULL)))
274 { UNRESOLVED(ret, "Signal 1 sender thread join failed"); }
275 if ((ret = pthread_join(th_sig2, NULL)))
276 { UNRESOLVED(ret, "Signal 2 sender thread join failed"); }
277 for (i=0; i<5; i++)
278 {
279 if ((ret = pthread_join(th_waiter[i], NULL)))
280 { UNRESOLVED(ret, "Waiter thread join failed"); }
281 }
282 if ((ret = pthread_join(th_worker, NULL)))
283 { UNRESOLVED(ret, "Worker thread join failed"); }
284
285 #if VERBOSE > 0
286 output("Test executed successfully.\n");
287 output(" Condition was signaled %d times.\n", count_cnd_sig);
288 output(" pthread_cond_wait exited %d times.\n", count_cnd_wup);
289 #ifdef WITH_SYNCHRO
290 output(" %d signals were sent meanwhile.\n", count_sig);
291 #endif
292 #endif
293 PASSED;
294 }
295