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