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 83char do_it=1; 84char woken=0; 85unsigned long count_cnd_sig=0, count_cnd_wup=0; 86#ifdef WITH_SYNCHRO 87sem_t semsig1; 88sem_t semsig2; 89unsigned long count_sig=0; 90#endif 91 92sigset_t usersigs; 93 94typedef struct 95{ 96 int sig; 97#ifdef WITH_SYNCHRO 98 sem_t *sem; 99#endif 100} thestruct; 101 102struct 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 */ 109void * 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 */ 139void 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 */ 147void 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 */ 157void * 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 */ 187void * 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 */ 207int 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