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