1 /* 2 * Copyright (C) Bull S.A. 2001 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /******************************************************************************/ 21 /* */ 22 /* Dec-03-2001 Created: Jacky Malcles & Jean Noel Cordenner */ 23 /* These tests are adapted from AIX float PVT tests. */ 24 /* */ 25 /******************************************************************************/ 26 #include "tfloat.h" 27 28 #include "test.h" 29 30 #define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } } 31 /* LTP status reporting */ 32 char *TCID; /* Test program identifier. */ 33 int TST_TOTAL = 1; /* Total number of test cases. */ 34 35 /* To avoid extensive modifications to the code, use this bodge */ 36 #define exit(x) myexit(x) 37 38 void myexit(int x) 39 { 40 if (x) 41 tst_resm(TFAIL, "Test failed"); 42 else 43 tst_resm(TPASS, "Test passed"); 44 tst_exit(); 45 } 46 47 TH_DATA *pcom; 48 TH_DATA **tabcom; 49 TH_DATA **tabcour; 50 #ifndef PATH_MAX 51 #define PATH_MAX 1024 52 #endif 53 char datadir[PATH_MAX]; /* DATA directory */ 54 55 #ifndef PTHREAD_THREADS_MAX 56 #define PTHREAD_THREADS_MAX 1024 57 #endif 58 #define DEFAULT_NUM_THREADS 20 59 int num_threads = DEFAULT_NUM_THREADS; 60 int num_loops = 500; 61 62 int sig_cancel = 0; /* flag set by handle_signals to tell initial thread 63 to stop creating new threads (signal caught) */ 64 65 int indice = 0; /* # of threads created, to be canceled by handle_signals 66 or waited for by initial thread */ 67 68 pthread_mutex_t sig_mutex; 69 pthread_t *threads; 70 71 int debug = 0; 72 int true = 1; 73 74 static void *handle_signals(void *); 75 76 static void sys_error(const char *, int); 77 78 const double EPS = 0.1e-300; 79 80 const int nb_func = NB_FUNC; 81 82 int generate(char *datadir, char *bin_path) 83 { 84 char *cmdline; 85 char *fmt = "cd %s; %s/%s %s"; 86 87 cmdline = malloc(2 * strlen(bin_path) + strlen(datadir) + strlen(GENERATOR) + strlen(fmt)); 88 if (cmdline == NULL) 89 return (1); 90 sprintf(cmdline, fmt, datadir, bin_path, GENERATOR, bin_path); 91 system(cmdline); 92 free(cmdline); 93 return (0); 94 } 95 96 static void cleanup(void) 97 { 98 tst_rmdir(); 99 } 100 101 int main(int argc, char *argv[]) 102 { 103 int opt = 0; 104 pid_t pid; 105 106 char *bin_path, *ltproot; 107 void *exit_value; 108 pthread_attr_t newattr; 109 pthread_t sig_hand; 110 size_t stacksize = 2093056; 111 int th_num; 112 int retvalend = 0; 113 int retval = 0; 114 int error = 0; 115 /*int time=1; */ 116 int i; 117 118 /* Generate test ID from invocation name */ 119 if ((TCID = strrchr(argv[0], '/')) != NULL) 120 TCID++; 121 else 122 TCID = argv[0]; 123 ltproot = getenv("LTPROOT"); 124 if (ltproot == NULL || strlen(ltproot) == 0) { 125 tst_brkm(TBROK, NULL, 126 "You must set $LTPROOT before executing this test"); 127 } 128 bin_path = malloc(strlen(ltproot) + 16); 129 if (bin_path == NULL) { 130 tst_brkm(TBROK | TERRNO, NULL, "malloc failed"); 131 } 132 sprintf(bin_path, "%s/testcases/bin", ltproot); 133 134 tst_tmpdir(); 135 136 setbuf(stdout, NULL); 137 setbuf(stderr, NULL); 138 datadir[0] = '.'; 139 datadir[1] = '\0'; 140 141 if (argc != 1) { 142 while ((opt = getopt(argc, argv, "vn:l:D:?")) != EOF) { 143 switch (opt) { 144 case 'D': 145 strncpy(datadir, optarg, PATH_MAX); 146 break; 147 case 'l': 148 num_loops = atoi(optarg); 149 break; 150 case 'n': 151 num_threads = atoi(optarg); 152 break; 153 case 'v': 154 ++debug; /* verbose mode */ 155 break; 156 default: 157 fprintf(stderr, 158 "usage: %s [-n number_of_threads] [-v]\n", 159 argv[0]); 160 fprintf(stderr, "[-l number_of_loops] "); 161 fprintf(stderr, "[-D DATAs absolute path]\n"); 162 exit(1); 163 } 164 } 165 } 166 switch (pid = fork()) { 167 case -1: 168 tst_brkm(TBROK | TERRNO, cleanup, "fork failed"); 169 case 0: 170 generate(datadir, bin_path); 171 exit(0); 172 default: 173 waitpid(pid, NULL, 0); 174 } 175 SAFE_FREE(bin_path); 176 177 if (debug) { 178 tst_resm(TINFO, 179 "%s: will run for %d loops; using %s as a data directory", 180 argv[0], num_loops, datadir); 181 } 182 if (num_threads <= 0) { 183 tst_resm(TWARN, 184 "num_threads undefined or incorrect, using \"1\""); 185 num_threads = 1; 186 } 187 188 if (nb_func * num_threads > PTHREAD_THREADS_MAX - 2) 189 while (nb_func * num_threads > PTHREAD_THREADS_MAX - 2) 190 num_threads--; 191 if (debug) 192 tst_resm(TINFO, 193 "%s: will run %d functions, %d threads per function", 194 argv[0], nb_func, num_threads); 195 196 retval = pthread_mutex_init(&sig_mutex, NULL); 197 if (retval != 0) 198 sys_error("main : mutex_init(&sig_mutex) FAILED", __LINE__); 199 200 retval = pthread_create(&sig_hand, NULL, handle_signals, NULL); 201 if (retval != 0) 202 sys_error("main : create(&sig_hand) FAILED", __LINE__); 203 204 /* 205 * Start all calculation threads... 206 */ 207 threads = malloc(nb_func * num_threads * sizeof(pthread_t)); 208 if (threads == NULL) 209 tst_brkm(TFAIL | TERRNO, cleanup, "malloc failed"); 210 211 tabcom = malloc((sizeof(TH_DATA *) * nb_func * num_threads)); 212 if (!tabcom) 213 tst_brkm(TFAIL | TERRNO, cleanup, "malloc failed"); 214 tabcour = tabcom; 215 216 retval = pthread_attr_init(&newattr); 217 if (retval != 0) 218 sys_error("main : attr_init(&newattr) FAILED", __LINE__); 219 220 if (pthread_attr_setstacksize(&newattr, stacksize)) 221 sys_error("main: pthread_attr_setstacksize failed", __LINE__); 222 223 retval = pthread_attr_setdetachstate(&newattr, PTHREAD_CREATE_JOINABLE); 224 if (retval != 0) 225 sys_error("main : attr_setdetachstate(&newattr) FAILED", 226 __LINE__); 227 228 /* run the nb_func functions on num_threads */ 229 230 indice = 0; 231 for (i = 0; i < nb_func; i++) { 232 233 for (th_num = 0; th_num < num_threads; th_num++) { 234 235 /* allocate struct of commucation with the thread */ 236 pcom = calloc(1, sizeof(TH_DATA)); 237 if (pcom == NULL) 238 tst_brkm(TFAIL | TERRNO, cleanup, 239 "calloc failed"); 240 *tabcour = (TH_DATA *) pcom; 241 tabcour++; 242 /* 243 * update structure of communication 244 */ 245 pcom->th_num = th_num; 246 pcom->th_func = th_func[i]; 247 248 pthread_mutex_lock(&sig_mutex); 249 250 if (sig_cancel) { /* stop processing right now! */ 251 pthread_mutex_unlock(&sig_mutex); 252 goto finished; 253 } 254 retval = pthread_create(&threads[indice], &newattr, 255 thread_code, (void *)pcom); 256 if (retval != 0) 257 sys_error("main : create FAILED", __LINE__); 258 indice++; 259 pthread_mutex_unlock(&sig_mutex); 260 261 } /* num_threads */ 262 } /* for i */ 263 264 /*alarm(60*time); *//* start all threads for TEST_time */ 265 266 /* 267 * Wait for the threads finish their task 268 * pthread_join () will block 269 */ 270 271 finished: 272 if (debug) { 273 tst_resm(TINFO, 274 "initial thread: Waiting for %d threads to finish", 275 indice); 276 } 277 tabcour = tabcom; 278 279 for (th_num = 0; th_num < indice; th_num++) { 280 retvalend = pthread_join(threads[th_num], &exit_value); 281 if (retvalend != 0) 282 sys_error("finish : join FAILED", __LINE__); 283 284 /* test the result in TH_DATA : communication buffer */ 285 pcom = *tabcour++; 286 if (pcom->th_result != 0) { 287 error++; 288 tst_resm(TFAIL, 289 "thread %d (%s) terminated unsuccessfully %d " 290 "errors/%d loops\n%s", 291 th_num, pcom->th_func.fident, pcom->th_nerror, 292 pcom->th_nloop, pcom->detail_data); 293 } else if (debug) { 294 tst_resm(TINFO, 295 "thread %d (%s) terminated successfully %d loops", 296 th_num, pcom->th_func.fident, 297 pcom->th_nloop - 1); 298 } 299 SAFE_FREE(pcom); 300 301 } 302 pthread_cancel(sig_hand); 303 pthread_join(sig_hand, NULL); 304 SAFE_FREE(tabcom); 305 SAFE_FREE(threads); 306 tst_rmdir(); 307 if (error) 308 exit(1); 309 else 310 exit(0); 311 return 0; 312 } 313 314 /*----------------------------------------------------------------------+ 315 | handle_signals () | 316 | ======================================================================| 317 | | 318 | Function: .... | 319 | If SIGALRM or SIGUSR1 or SIGINT : cancel threads | 320 | | 321 | Updates: .... | 322 | | 323 +-----------------------------------------------------------------------*/ 324 static void *handle_signals(void *arg) 325 { 326 sigset_t signals_set; 327 int thd; 328 int sig; 329 int retvalsig = 0; 330 331 if (debug) 332 tst_resm(TINFO, "signal handler %lu started", pthread_self()); 333 /* 334 * Set up the signals that we want to handle... 335 */ 336 sigemptyset(&signals_set); 337 sigaddset(&signals_set, SIGINT); 338 sigaddset(&signals_set, SIGQUIT); 339 sigaddset(&signals_set, SIGTERM); 340 sigaddset(&signals_set, SIGUSR1); 341 sigaddset(&signals_set, SIGALRM); 342 while (1) { 343 if (debug) 344 tst_resm(TINFO, "Signal handler starts waiting..."); 345 346 sigwait(&signals_set, &sig); 347 if (debug) 348 tst_resm(TINFO, "Signal handler caught signal %d", sig); 349 350 switch (sig) { 351 case SIGALRM: 352 case SIGUSR1: 353 case SIGINT: 354 if (sig_cancel) 355 tst_resm(TINFO, 356 "Signal handler: already finished; " 357 "ignoring signal"); 358 else { 359 /* 360 * Have to signal all non started threads... 361 */ 362 363 retvalsig = pthread_mutex_lock(&sig_mutex); 364 if (retvalsig != 0) 365 sys_error 366 ("handle_signal : mutex_lock(&sig_mutex) FAILED", 367 __LINE__); 368 369 sig_cancel = 1; 370 retvalsig = pthread_mutex_unlock(&sig_mutex); 371 if (retvalsig != 0) 372 sys_error 373 ("handle_signal : mutex_unlock(&sig_mutex) FAILED", 374 __LINE__); 375 376 /* 377 * ......... and all started 378 */ 379 for (thd = 0; thd < indice; thd++) { 380 if (debug) 381 tst_resm(TINFO, 382 "signal handler: " 383 "cancelling thread (%d of " 384 "%d)", thd, indice); 385 retvalsig = 386 pthread_cancel(threads[thd]); 387 if (retvalsig != 0) 388 sys_error 389 ("handle_signal : cancel FAILED", 390 __LINE__); 391 } 392 } 393 break; 394 case SIGQUIT: 395 tst_resm(TINFO, 396 "Signal handler: Caught SIGQUIT; doing nothing"); 397 break; 398 case SIGTERM: 399 tst_resm(TINFO, 400 "Signal handler: Caught SIGTERM; doing nothing"); 401 break; 402 default: 403 exit(1); 404 } 405 } 406 return NULL; 407 } 408 409 /*----------------------------------------------------------------------+ 410 | error () | 411 | =====================================================================| 412 | | 413 | Function: Prints out message and exits... | 414 | | 415 +----------------------------------------------------------------------*/ 416 static void error(const char *msg, int line) 417 { 418 tst_brkm(TFAIL, cleanup, "ERROR [line: %d] %s", line, msg); 419 } 420 421 /*----------------------------------------------------------------------+ 422 | sys_error () | 423 | =====================================================================| 424 | | 425 | Function: Creates system error message and calls error () | 426 | | 427 +----------------------------------------------------------------------*/ 428 /* 429 * XXX (garrcoop): the way that this is being called is just plain wrong. 430 * pthread(5) returns 0 or errnos, not necessarily sets errno to a sensible 431 * value. 432 */ 433 static void sys_error(const char *msg, int line) 434 { 435 char syserr_msg[256]; 436 437 sprintf(syserr_msg, "%s: %s", msg, strerror(errno)); 438 error(syserr_msg, line); 439 } 440