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