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 * 19 * When the abstime parameter is invalid, 20 * the function must return EINVAL and 21 * the mutex state must not have changed during the call. 22 23 * The steps are: 24 * -> parent (for each mutex type and each condvar options, across threads or processes) 25 * -> locks the mutex m 26 * -> sets ctrl = 0 27 * -> creates a bunch of children, which: 28 * -> lock the mutex m 29 * -> if ctrl == 0, test has failed 30 * -> unlock the mutex then exit 31 * -> calls pthread_cond_timedwait with invalid values (nsec > 999999999) 32 * -> sets ctrl = non-zero value 33 * -> unlocks the mutex m 34 */ 35 36 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 37 #define _POSIX_C_SOURCE 200112L 38 39 /* We need the XSI extention for the mutex attributes 40 and the mkstemp() routine */ 41 #ifndef WITHOUT_XOPEN 42 #define _XOPEN_SOURCE 600 43 #endif 44 45 #include <pthread.h> 46 #include <stdarg.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <unistd.h> 50 51 #include <errno.h> 52 #include <sys/wait.h> 53 #include <sys/mman.h> 54 #include <string.h> 55 #include <time.h> 56 57 #include "../testfrmw/testfrmw.h" 58 #include "../testfrmw/testfrmw.c" 59 60 #ifndef VERBOSE 61 #define VERBOSE 1 62 #endif 63 64 #define NCHILDREN (20) 65 66 #ifndef WITHOUT_ALTCLK 67 #define USE_ALTCLK /* make tests with MONOTONIC CLOCK if supported */ 68 #endif 69 70 #ifndef WITHOUT_XOPEN 71 72 typedef struct { 73 pthread_mutex_t mtx; 74 int ctrl; /* Control value */ 75 int gotit; /* Thread locked the mutex while ctrl == 0 */ 76 int status; /* error code */ 77 } testdata_t; 78 79 struct _scenar { 80 int m_type; /* Mutex type to use */ 81 int mc_pshared; /* 0: mutex and cond are process-private (default) ~ !0: Both are process-shared, if supported */ 82 int c_clock; /* 0: cond uses the default clock. ~ !0: Cond uses monotonic clock, if supported. */ 83 int fork; /* 0: Test between threads. ~ !0: Test across processes, if supported (mmap) */ 84 char *descr; /* Case description */ 85 } scenarii[] = { 86 { 87 PTHREAD_MUTEX_DEFAULT, 0, 0, 0, "Default mutex"} 88 , { 89 PTHREAD_MUTEX_NORMAL, 0, 0, 0, "Normal mutex"} 90 , { 91 PTHREAD_MUTEX_ERRORCHECK, 0, 0, 0, "Errorcheck mutex"} 92 , { 93 PTHREAD_MUTEX_RECURSIVE, 0, 0, 0, "Recursive mutex"} 94 95 , { 96 PTHREAD_MUTEX_DEFAULT, 1, 0, 0, "PShared default mutex"} 97 , { 98 PTHREAD_MUTEX_NORMAL, 1, 0, 0, "Pshared normal mutex"} 99 , { 100 PTHREAD_MUTEX_ERRORCHECK, 1, 0, 0, "Pshared errorcheck mutex"} 101 , { 102 PTHREAD_MUTEX_RECURSIVE, 1, 0, 0, "Pshared recursive mutex"} 103 104 , { 105 PTHREAD_MUTEX_DEFAULT, 1, 0, 1, 106 "Pshared default mutex across processes"} 107 , { 108 PTHREAD_MUTEX_NORMAL, 1, 0, 1, 109 "Pshared normal mutex across processes"} 110 , { 111 PTHREAD_MUTEX_ERRORCHECK, 1, 0, 1, 112 "Pshared errorcheck mutex across processes"} 113 , { 114 PTHREAD_MUTEX_RECURSIVE, 1, 0, 1, 115 "Pshared recursive mutex across processes"} 116 117 #ifdef USE_ALTCLK 118 , { 119 PTHREAD_MUTEX_DEFAULT, 1, 1, 1, 120 "Pshared default mutex and alt clock condvar across processes"} 121 , { 122 PTHREAD_MUTEX_NORMAL, 1, 1, 1, 123 "Pshared normal mutex and alt clock condvar across processes"} 124 , { 125 PTHREAD_MUTEX_ERRORCHECK, 1, 1, 1, 126 "Pshared errorcheck mutex and alt clock condvar across processes"} 127 , { 128 PTHREAD_MUTEX_RECURSIVE, 1, 1, 1, 129 "Pshared recursive mutex and alt clock condvar across processes"} 130 131 , { 132 PTHREAD_MUTEX_DEFAULT, 0, 1, 0, 133 "Default mutex and alt clock condvar"} 134 , { 135 PTHREAD_MUTEX_NORMAL, 0, 1, 0, 136 "Normal mutex and alt clock condvar"} 137 , { 138 PTHREAD_MUTEX_ERRORCHECK, 0, 1, 0, 139 "Errorcheck mutex and alt clock condvar"} 140 , { 141 PTHREAD_MUTEX_RECURSIVE, 0, 1, 0, 142 "Recursive mutex and alt clock condvar"} 143 144 , { 145 PTHREAD_MUTEX_DEFAULT, 1, 1, 0, 146 "PShared default mutex and alt clock condvar"} 147 , { 148 PTHREAD_MUTEX_NORMAL, 1, 1, 0, 149 "Pshared normal mutex and alt clock condvar"} 150 , { 151 PTHREAD_MUTEX_ERRORCHECK, 1, 1, 0, 152 "Pshared errorcheck mutex and alt clock condvar"} 153 , { 154 PTHREAD_MUTEX_RECURSIVE, 1, 1, 0, 155 "Pshared recursive mutex and alt clock condvar"} 156 #endif 157 }; 158 159 struct { 160 long sec_val; /* Value for seconds */ 161 short sec_is_offset; /* Seconds value is added to current time or is absolute */ 162 long nsec_val; /* Value for nanoseconds */ 163 short nsec_is_offset; /* Nanoseconds value is added to current time or is absolute */ 164 } junks_ts[] = { 165 { 166 -2, 1, 1000000000, 1} 167 , { 168 -2, 1, -1, 0} 169 , { 170 -3, 1, 2000000000, 0} 171 }; 172 173 void *tf(void *arg) 174 { 175 int ret = 0; 176 177 testdata_t *td = (testdata_t *) arg; 178 179 /* Lock the mutex */ 180 ret = pthread_mutex_lock(&(td->mtx)); 181 if (ret != 0) { 182 td->status = ret; 183 UNRESOLVED(ret, "[child] Unable to lock the mutex"); 184 } 185 186 /* Checks whether the parent release the lock inside the timedwait function */ 187 if (td->ctrl == 0) 188 td->gotit += 1; 189 190 /* Unlock and exit */ 191 ret = pthread_mutex_unlock(&(td->mtx)); 192 if (ret != 0) { 193 td->status = ret; 194 UNRESOLVED(ret, "[child] Failed to unlock the mutex."); 195 } 196 return NULL; 197 } 198 199 int main(void) 200 { 201 int ret, k; 202 unsigned int i, j; 203 pthread_mutexattr_t ma; 204 pthread_condattr_t ca; 205 pthread_cond_t cnd; 206 clockid_t cid = CLOCK_REALTIME; 207 struct timespec ts, ts_junk; 208 209 testdata_t *td; 210 testdata_t alternativ; 211 212 int do_fork; 213 214 pid_t child_pr[NCHILDREN], chkpid; 215 int status; 216 pthread_t child_th[NCHILDREN]; 217 218 long pshared, monotonic, cs, mf; 219 220 output_init(); 221 pshared = sysconf(_SC_THREAD_PROCESS_SHARED); 222 cs = sysconf(_SC_CLOCK_SELECTION); 223 monotonic = sysconf(_SC_MONOTONIC_CLOCK); 224 mf = sysconf(_SC_MAPPED_FILES); 225 226 #if VERBOSE > 0 227 output("Test starting\n"); 228 output("System abilities:\n"); 229 output(" TPS : %li\n", pshared); 230 output(" CS : %li\n", cs); 231 output(" MON : %li\n", monotonic); 232 output(" MF : %li\n", mf); 233 if ((mf < 0) || (pshared < 0)) 234 output("Process-shared attributes won't be tested\n"); 235 if ((cs < 0) || (monotonic < 0)) 236 output("Alternative clock won't be tested\n"); 237 fflush(stdout); 238 #endif 239 240 /* We are not interested in testing the clock if we have no other clock available.. */ 241 if (monotonic < 0) 242 cs = -1; 243 244 #ifndef USE_ALTCLK 245 if (cs > 0) 246 output 247 ("Implementation supports the MONOTONIC CLOCK but option is disabled in test.\n"); 248 #endif 249 250 /********** 251 * Allocate space for the testdata structure 252 */ 253 if (mf < 0) { 254 /* Cannot mmap a file, we use an alternative method */ 255 td = &alternativ; 256 pshared = -1; /* We won't do this testing anyway */ 257 #if VERBOSE > 0 258 output("Testdata allocated in the process memory.\n"); 259 #endif 260 } else { 261 /* We will place the test data in a mmaped file */ 262 char filename[] = "/tmp/cond_timedwait_2-4-XXXXXX"; 263 size_t sz; 264 void *mmaped; 265 int fd; 266 char *tmp; 267 268 /* We now create the temp files */ 269 fd = mkstemp(filename); 270 if (fd == -1) { 271 UNRESOLVED(errno, 272 "Temporary file could not be created"); 273 } 274 275 /* and make sure the file will be deleted when closed */ 276 unlink(filename); 277 278 #if VERBOSE > 1 279 output("Temp file created (%s).\n", filename); 280 #endif 281 282 sz = (size_t) sysconf(_SC_PAGESIZE); 283 284 tmp = calloc(1, sz); 285 if (tmp == NULL) { 286 UNRESOLVED(errno, "Memory allocation failed"); 287 } 288 289 /* Write the data to the file. */ 290 if (write(fd, tmp, sz) != (ssize_t) sz) { 291 UNRESOLVED(sz, "Writting to the file failed"); 292 } 293 294 free(tmp); 295 296 /* Now we can map the file in memory */ 297 mmaped = 298 mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 299 if (mmaped == MAP_FAILED) { 300 UNRESOLVED(errno, "mmap failed"); 301 } 302 303 td = (testdata_t *) mmaped; 304 305 /* Our datatest structure is now in shared memory */ 306 #if VERBOSE > 1 307 output("Testdata allocated in shared memory.\n"); 308 #endif 309 } 310 311 /********** 312 * For each test scenario, initialize the attributes and other variables. 313 * Do the whole thing for each time to test. 314 */ 315 for (i = 0; i < (sizeof(scenarii) / sizeof(scenarii[0])); i++) { 316 for (j = 0; j < (sizeof(junks_ts) / sizeof(junks_ts[0])); j++) { 317 #if VERBOSE > 1 318 output("[parent] Preparing attributes for: %s\n", 319 scenarii[i].descr); 320 #endif 321 /* set / reset everything */ 322 do_fork = 0; 323 ret = pthread_mutexattr_init(&ma); 324 if (ret != 0) { 325 UNRESOLVED(ret, 326 "[parent] Unable to initialize the mutex attribute object"); 327 } 328 ret = pthread_condattr_init(&ca); 329 if (ret != 0) { 330 UNRESOLVED(ret, 331 "[parent] Unable to initialize the cond attribute object"); 332 } 333 334 /* Set the mutex type */ 335 ret = 336 pthread_mutexattr_settype(&ma, scenarii[i].m_type); 337 if (ret != 0) { 338 UNRESOLVED(ret, 339 "[parent] Unable to set mutex type"); 340 } 341 #if VERBOSE > 1 342 output("[parent] Mutex type : %i\n", 343 scenarii[i].m_type); 344 #endif 345 346 /* Set the pshared attributes, if supported */ 347 if ((pshared > 0) && (scenarii[i].mc_pshared != 0)) { 348 ret = 349 pthread_mutexattr_setpshared(&ma, 350 PTHREAD_PROCESS_SHARED); 351 if (ret != 0) { 352 UNRESOLVED(ret, 353 "[parent] Unable to set the mutex process-shared"); 354 } 355 ret = 356 pthread_condattr_setpshared(&ca, 357 PTHREAD_PROCESS_SHARED); 358 if (ret != 0) { 359 UNRESOLVED(ret, 360 "[parent] Unable to set the cond var process-shared"); 361 } 362 #if VERBOSE > 1 363 output 364 ("[parent] Mutex & cond are process-shared\n"); 365 #endif 366 } 367 #if VERBOSE > 1 368 else { 369 output 370 ("[parent] Mutex & cond are process-private\n"); 371 } 372 #endif 373 374 /* Set the alternative clock, if supported */ 375 #ifdef USE_ALTCLK 376 if ((cs > 0) && (scenarii[i].c_clock != 0)) { 377 ret = 378 pthread_condattr_setclock(&ca, 379 CLOCK_MONOTONIC); 380 if (ret != 0) { 381 UNRESOLVED(ret, 382 "[parent] Unable to set the monotonic clock for the cond"); 383 } 384 #if VERBOSE > 1 385 output 386 ("[parent] Cond uses the Monotonic clock\n"); 387 #endif 388 } 389 #if VERBOSE > 1 390 else { 391 output 392 ("[parent] Cond uses the default clock\n"); 393 } 394 #endif 395 ret = pthread_condattr_getclock(&ca, &cid); 396 if (ret != 0) { 397 UNRESOLVED(ret, 398 "Unable to get clock from cond attr"); 399 } 400 #endif 401 402 /* Tell whether the test will be across processes */ 403 if ((pshared > 0) && (scenarii[i].fork != 0)) { 404 do_fork = 1; 405 #if VERBOSE > 1 406 output 407 ("[parent] Child will be a new process\n"); 408 #endif 409 } 410 #if VERBOSE > 1 411 else { 412 output("[parent] Child will be a new thread\n"); 413 } 414 #endif 415 416 /* initialize the condvar */ 417 ret = pthread_cond_init(&cnd, &ca); 418 if (ret != 0) { 419 UNRESOLVED(ret, "[parent] Cond init failed"); 420 } 421 422 /********** 423 * Initialize the testdata_t structure with the previously defined attributes 424 */ 425 /* Initialize the mutex */ 426 ret = pthread_mutex_init(&(td->mtx), &ma); 427 if (ret != 0) { 428 UNRESOLVED(ret, "[parent] Mutex init failed"); 429 } 430 431 /* Initialize the other datas from the test structure */ 432 td->ctrl = 0; 433 td->gotit = 0; 434 td->status = 0; 435 436 /********** 437 * Proceed to the actual testing 438 */ 439 /* Lock the mutex before creating children */ 440 ret = pthread_mutex_lock(&(td->mtx)); 441 if (ret != 0) { 442 UNRESOLVED(ret, 443 "[parent] Unable to lock the mutex"); 444 } 445 446 /* Create the children */ 447 if (do_fork != 0) { 448 /* We are testing across processes */ 449 for (k = 0; k < NCHILDREN; k++) { 450 child_pr[k] = fork(); 451 if (child_pr[k] == -1) { 452 UNRESOLVED(errno, 453 "[parent] Fork failed"); 454 } 455 456 if (child_pr[k] == 0) { 457 #if VERBOSE > 3 458 output 459 ("[child] Child process %i starting...\n", 460 k); 461 #endif 462 463 if (tf((void *)td) != NULL) { 464 UNRESOLVED(-1, 465 "[child] Got an unexpected return value from test function"); 466 } else { 467 /* We cannot use the PASSED macro here since it would terminate the output */ 468 exit(0); 469 } 470 } 471 } 472 /* Only the parent process goes further */ 473 } else { /* do_fork == 0 */ 474 475 /* We are testing across two threads */ 476 for (k = 0; k < NCHILDREN; k++) { 477 ret = 478 pthread_create(&child_th[k], NULL, 479 tf, td); 480 if (ret != 0) { 481 UNRESOLVED(ret, 482 "[parent] Unable to create the child thread."); 483 } 484 } 485 } 486 487 /* Children are now running and trying to lock the mutex. */ 488 489 ret = clock_gettime(cid, &ts); 490 if (ret != 0) { 491 UNRESOLVED(ret, 492 "[parent] Unable to read clock"); 493 } 494 495 /* Do the junk timedwaits */ 496 ts_junk.tv_sec = 497 junks_ts[j].sec_val + 498 (junks_ts[j].sec_is_offset ? ts.tv_sec : 0); 499 ts_junk.tv_nsec = 500 junks_ts[j].nsec_val + 501 (junks_ts[j].nsec_is_offset ? ts.tv_nsec : 0); 502 503 #if VERBOSE > 2 504 output("TS: s = %s%li ; ns = %s%li\n", 505 junks_ts[j].sec_is_offset ? "n + " : " ", 506 junks_ts[j].sec_val, 507 junks_ts[j].nsec_is_offset ? "n + " : " ", 508 junks_ts[j].nsec_val); 509 output("Now is: %i.%09li\n", ts.tv_sec, ts.tv_nsec); 510 output("Junk is: %i.%09li\n", ts_junk.tv_sec, 511 ts_junk.tv_nsec); 512 #endif 513 514 do { 515 ret = 516 pthread_cond_timedwait(&cnd, &(td->mtx), 517 &ts_junk); 518 } while (ret == 0); 519 #if VERBOSE > 2 520 output("timedwait returns %d (%s) - gotit = %d\n", ret, 521 strerror(ret), td->gotit); 522 #endif 523 524 /* check that when EINVAL is returned, the mutex has not been released */ 525 if (ret == EINVAL) { 526 if (td->gotit != 0) { 527 FAILED 528 ("The mutex was released when an invalid timestamp was detected in the function"); 529 } 530 #if VERBOSE > 0 531 } else { 532 output 533 ("Warning, struct timespec with tv_sec = %i and tv_nsec = %li was not invalid\n", 534 ts_junk.tv_sec, ts_junk.tv_nsec); 535 } 536 #endif 537 538 /* Finally unlock the mutex */ 539 td->ctrl = 1; 540 ret = pthread_mutex_unlock(&(td->mtx)); 541 if (ret != 0) { 542 UNRESOLVED(ret, 543 "[parent] Unable to unlock the mutex"); 544 } 545 546 /* Wait for the child to terminate */ 547 if (do_fork != 0) { 548 /* We were testing across processes */ 549 ret = 0; 550 for (k = 0; k < NCHILDREN; k++) { 551 chkpid = 552 waitpid(child_pr[k], &status, 0); 553 if (chkpid != child_pr[k]) { 554 output 555 ("Expected pid: %i. Got %i\n", 556 (int)child_pr[k], 557 (int)chkpid); 558 UNRESOLVED(errno, 559 "Waitpid failed"); 560 } 561 if (WIFSIGNALED(status)) { 562 output 563 ("Child process killed with signal %d\n", 564 WTERMSIG(status)); 565 UNRESOLVED(-1, 566 "Child process was killed"); 567 } 568 569 if (WIFEXITED(status)) { 570 ret |= WEXITSTATUS(status); 571 } else { 572 UNRESOLVED(-1, 573 "Child process was neither killed nor exited"); 574 } 575 } 576 if (ret != 0) { 577 exit(ret); /* Output has already been closed in child */ 578 } 579 580 } else { /* child was a thread */ 581 582 for (k = 0; k < NCHILDREN; k++) { 583 ret = pthread_join(child_th[k], NULL); 584 if (ret != 0) { 585 UNRESOLVED(ret, 586 "[parent] Unable to join the thread"); 587 } 588 } 589 } 590 591 /********** 592 * Destroy the data 593 */ 594 ret = pthread_cond_destroy(&cnd); 595 if (ret != 0) { 596 UNRESOLVED(ret, 597 "Failed to destroy the cond var"); 598 } 599 600 ret = pthread_mutex_destroy(&(td->mtx)); 601 if (ret != 0) { 602 UNRESOLVED(ret, "Failed to destroy the mutex"); 603 } 604 605 ret = pthread_condattr_destroy(&ca); 606 if (ret != 0) { 607 UNRESOLVED(ret, 608 "Failed to destroy the cond var attribute object"); 609 } 610 611 ret = pthread_mutexattr_destroy(&ma); 612 if (ret != 0) { 613 UNRESOLVED(ret, 614 "Failed to destroy the mutex attribute object"); 615 } 616 617 } /* Proceed to the next junk timedwait value */ 618 } /* Proceed to the next scenario */ 619 620 #if VERBOSE > 0 621 output("Test passed\n"); 622 #endif 623 624 PASSED; 625 } 626 627 #else /* WITHOUT_XOPEN */ 628 int main(void) 629 { 630 output_init(); 631 UNTESTED("This test requires XSI features"); 632 } 633 #endif 634