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