1 /* 2 * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by Daniel M. Eischen. 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS'' 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $FreeBSD: src/lib/libc_r/test/mutex_d.c,v 1.1.2.2 2003/01/05 19:59:39 semenu Exp $ 33 */ 34 #include <stdlib.h> 35 #include <unistd.h> 36 37 #include <sys/ioctl.h> 38 #include <assert.h> 39 #include <errno.h> 40 #include <pthread.h> 41 #include <pthread_np.h> 42 #include <sys/sched.h> 43 #include <signal.h> 44 #include <stdarg.h> 45 #include <stdio.h> 46 #include <string.h> 47 #include <sysexits.h> 48 #include <sys/time.h> 49 50 #ifndef NELEMENTS 51 #define NELEMENTS(arr) (sizeof (arr) / sizeof (arr[0])) 52 #endif 53 54 #ifndef NUM_THREADS 55 #define NUM_THREADS 10 56 #endif 57 58 #define MAX_THREAD_CMDS 10 59 60 static void log_error(const char *, ...) __printflike(1, 2); 61 static void log_trace (const char *, ...) __printflike(1, 2); 62 static void log_info (const char *, ...) __printflike(1, 2); 63 64 /*------------------------------------------------------------ 65 * Types 66 *----------------------------------------------------------*/ 67 68 typedef enum { 69 STAT_INITIAL, /* initial state */ 70 STAT_WAITCONDVAR, /* waiting for condition variable signal */ 71 STAT_WAITMUTEX /* waiting for mutex lock */ 72 } thread_status_t; 73 74 typedef enum { 75 FLAGS_REPORT_WAITCONDMUTEX = 0x01, 76 FLAGS_REPORT_WAITCONDVAR = 0x02, 77 FLAGS_REPORT_WAITMUTEX = 0x04, 78 FLAGS_REPORT_BUSY_LOOP = 0x08, 79 FLAGS_IS_BUSY = 0x10, 80 FLAGS_WAS_BUSY = 0x20 81 } thread_flags_t; 82 83 typedef enum { 84 CMD_NONE, 85 CMD_TAKE_MUTEX, 86 CMD_RELEASE_MUTEX, 87 CMD_WAIT_FOR_SIGNAL, 88 CMD_BUSY_LOOP, 89 CMD_PROTECTED_OP, 90 CMD_RELEASE_ALL 91 } thread_cmd_id_t; 92 93 typedef struct { 94 thread_cmd_id_t cmd_id; 95 pthread_mutex_t *mutex; 96 pthread_cond_t *cond; 97 } thread_cmd_t; 98 99 typedef struct { 100 pthread_cond_t cond_var; 101 thread_status_t status; 102 thread_cmd_t cmd; 103 int flags; 104 int priority; 105 int ret; 106 pthread_t tid; 107 u_int8_t id; 108 } thread_state_t; 109 110 typedef enum { 111 M_POSIX, 112 M_SS2_DEFAULT, 113 M_SS2_ERRORCHECK, 114 M_SS2_NORMAL, 115 M_SS2_RECURSIVE 116 } mutex_kind_t; 117 118 119 /*------------------------------------------------------------ 120 * Constants 121 *----------------------------------------------------------*/ 122 123 const char *protocol_strs[] = { 124 "PTHREAD_PRIO_NONE", 125 "PTHREAD_PRIO_INHERIT", 126 "PTHREAD_PRIO_PROTECT" 127 }; 128 129 const int protocols[] = { 130 PTHREAD_PRIO_NONE, 131 PTHREAD_PRIO_INHERIT, 132 PTHREAD_PRIO_PROTECT 133 }; 134 135 const char *mutextype_strs[] = { 136 "POSIX (type not specified)", 137 "SS2 PTHREAD_MUTEX_DEFAULT", 138 "SS2 PTHREAD_MUTEX_ERRORCHECK", 139 "SS2 PTHREAD_MUTEX_NORMAL", 140 "SS2 PTHREAD_MUTEX_RECURSIVE" 141 }; 142 143 const int mutex_types[] = { 144 0, /* M_POSIX */ 145 PTHREAD_MUTEX_DEFAULT, /* M_SS2_DEFAULT */ 146 PTHREAD_MUTEX_ERRORCHECK, /* M_SS2_ERRORCHECK */ 147 PTHREAD_MUTEX_NORMAL, /* M_SS2_NORMAL */ 148 PTHREAD_MUTEX_RECURSIVE /* M_SS2_RECURSIVE */ 149 }; 150 151 152 /*------------------------------------------------------------ 153 * Objects 154 *----------------------------------------------------------*/ 155 156 static int done = 0; 157 static int trace_enabled = 0; 158 static int use_global_condvar = 0; 159 static thread_state_t states[NUM_THREADS]; 160 static int pipefd[2]; 161 162 static pthread_mutex_t waiter_mutex; 163 static pthread_mutex_t cond_mutex; 164 static pthread_cond_t cond_var; 165 166 static FILE *logfile; 167 static int error_count = 0, pass_count = 0, total = 0; 168 169 170 /*------------------------------------------------------------ 171 * Prototypes 172 *----------------------------------------------------------*/ 173 extern char *strtok_r(char *str, const char *sep, char **last); 174 175 176 /*------------------------------------------------------------ 177 * Functions 178 *----------------------------------------------------------*/ 179 180 #ifdef DEBUG 181 static void 182 kern_switch (pthread_t pthread_out, pthread_t pthread_in) 183 { 184 if (pthread_out != NULL) 185 printf ("Swapping out thread 0x%x, ", (int) pthread_out); 186 else 187 printf ("Swapping out kernel thread, "); 188 189 if (pthread_in != NULL) 190 printf ("swapping in thread 0x%x\n", (int) pthread_in); 191 else 192 printf ("swapping in kernel thread.\n"); 193 } 194 #endif 195 196 197 static void 198 log_error (const char *fmt, ...) 199 { 200 va_list ap; 201 202 va_start (ap, fmt); 203 fprintf (logfile, "FAIL: "); 204 vfprintf (logfile, fmt, ap); 205 error_count = error_count + 1; 206 total = total + 1; 207 } 208 209 210 static void 211 log_pass (void) 212 { 213 fprintf (logfile, "PASS\n"); 214 pass_count = pass_count + 1; 215 total = total + 1; 216 } 217 218 219 static void 220 log_trace (const char *fmt, ...) 221 { 222 va_list ap; 223 224 if (trace_enabled) { 225 va_start (ap, fmt); 226 vfprintf (logfile, fmt, ap); 227 } 228 } 229 230 231 static void 232 log_info (const char *fmt, ...) 233 { 234 va_list ap; 235 236 va_start (ap, fmt); 237 vfprintf (logfile, fmt, ap); 238 } 239 240 241 static void 242 check_result (int expected, int actual) 243 { 244 if (expected != actual) 245 log_error ("expected %d, returned %d\n", expected, actual); 246 else 247 log_pass (); 248 } 249 250 251 /* 252 * Check to see that the threads ran in the specified order. 253 */ 254 static void 255 check_run_order (char *order) 256 { 257 const char *sep = ":,"; 258 char *tok, *last, *idstr, *endptr; 259 int expected_id, bytes, count = 0, errors = 0; 260 u_int8_t id; 261 262 assert ((tok = (char *) malloc (strlen(order) + 1)) != NULL); 263 strcpy (tok, order); /* tok has to be larger than order */ 264 assert (ioctl (pipefd[0], FIONREAD, &bytes) == 0); 265 log_trace ("%d bytes read from FIFO.\n", bytes); 266 267 for (idstr = strtok_r (tok, sep, &last); 268 (idstr != NULL) && (count < bytes); 269 idstr = strtok_r (NULL, sep, &last)) { 270 271 /* Get the expected id: */ 272 expected_id = (int) strtol (idstr, &endptr, 10); 273 assert ((endptr != NULL) && (*endptr == '\0')); 274 275 /* Read the actual id from the pipe: */ 276 assert (read (pipefd[0], &id, sizeof (id)) == sizeof (id)); 277 count = count + sizeof (id); 278 279 if (id != expected_id) { 280 log_trace ("Thread %d ran out of order.\n", id); 281 errors = errors + 1; 282 } 283 else { 284 log_trace ("Thread %d at priority %d reporting.\n", 285 (int) id, states[id].priority); 286 } 287 } 288 289 if (count < bytes) { 290 /* Clear the pipe: */ 291 while (count < bytes) { 292 read (pipefd[0], &id, sizeof (id)); 293 count = count + 1; 294 errors = errors + 1; 295 } 296 } 297 else if (bytes < count) 298 errors = errors + count - bytes; 299 300 if (errors == 0) 301 log_pass (); 302 else 303 log_error ("%d threads ran out of order\n", errors); 304 } 305 306 307 static void * 308 waiter (void *arg) 309 { 310 thread_state_t *statep = (thread_state_t *) arg; 311 pthread_mutex_t *held_mutex[MAX_THREAD_CMDS]; 312 int held_mutex_owned[MAX_THREAD_CMDS]; 313 sigset_t mask; 314 struct timeval tv1, tv2; 315 thread_cmd_t cmd; 316 int i, mutex_count = 0; 317 318 statep->status = STAT_INITIAL; 319 320 /* Block all signals except for interrupt.*/ 321 sigfillset (&mask); 322 sigdelset (&mask, SIGINT); 323 sigprocmask (SIG_BLOCK, &mask, NULL); 324 325 while (done == 0) { 326 /* Wait for signal from the main thread to continue. */ 327 statep->status = STAT_WAITMUTEX; 328 log_trace ("Thread %d: locking cond_mutex.\n", 329 (int) statep->id); 330 pthread_mutex_lock (&cond_mutex); 331 332 /* Do we report our status. */ 333 if (statep->flags & FLAGS_REPORT_WAITCONDMUTEX) 334 write (pipefd[1], &statep->id, sizeof (statep->id)); 335 log_trace ("Thread %d: waiting for cond_var.\n", 336 (int) statep->id); 337 338 /* Wait for a command. */ 339 statep->status = STAT_WAITCONDVAR; 340 341 /* 342 * The threads are allowed commanded to wait either on 343 * their own unique condition variable (so they may be 344 * separately signaled) or on one global condition variable 345 * (so they may be signaled together). 346 */ 347 if (use_global_condvar != 0) 348 pthread_cond_wait (&cond_var, &cond_mutex); 349 else 350 pthread_cond_wait (&statep->cond_var, &cond_mutex); 351 352 /* Do we report our status? */ 353 if (statep->flags & FLAGS_REPORT_WAITCONDVAR) { 354 write (pipefd[1], &statep->id, sizeof (statep->id)); 355 log_trace ("Thread %d: wrote to pipe.\n", 356 (int) statep->id); 357 } 358 log_trace ("Thread %d: received cond_var signal.\n", 359 (int) statep->id); 360 361 /* Get a copy of the command before releasing the mutex. */ 362 cmd = statep->cmd; 363 364 /* Clear the command after copying it. */ 365 statep->cmd.cmd_id = CMD_NONE; 366 367 /* Unlock the condition variable mutex. */ 368 assert (pthread_mutex_unlock (&cond_mutex) == 0); 369 370 /* Peform the command.*/ 371 switch (cmd.cmd_id) { 372 case CMD_TAKE_MUTEX: 373 statep->ret = pthread_mutex_lock (cmd.mutex); 374 if (statep->ret == 0) { 375 assert (mutex_count < sizeof (held_mutex)); 376 held_mutex[mutex_count] = cmd.mutex; 377 held_mutex_owned[mutex_count] = 1; 378 mutex_count++; 379 } 380 else { 381 held_mutex_owned[mutex_count] = 0; 382 log_trace ("Thread id %d unable to lock mutex, " 383 "error = %d\n", (int) statep->id, 384 statep->ret); 385 } 386 break; 387 388 case CMD_RELEASE_MUTEX: 389 assert ((mutex_count <= sizeof (held_mutex)) && 390 (mutex_count > 0)); 391 mutex_count--; 392 if (held_mutex_owned[mutex_count] != 0) 393 assert (pthread_mutex_unlock 394 (held_mutex[mutex_count]) == 0); 395 break; 396 397 case CMD_WAIT_FOR_SIGNAL: 398 assert (pthread_mutex_lock (cmd.mutex) == 0); 399 assert (pthread_cond_wait (cmd.cond, cmd.mutex) == 0); 400 assert (pthread_mutex_unlock (cmd.mutex) == 0); 401 break; 402 403 case CMD_BUSY_LOOP: 404 log_trace ("Thread %d: Entering busy loop.\n", 405 (int) statep->id); 406 /* Spin for 15 seconds. */ 407 assert (gettimeofday (&tv2, NULL) == 0); 408 tv1.tv_sec = tv2.tv_sec + 5; 409 tv1.tv_usec = tv2.tv_usec; 410 statep->flags |= FLAGS_IS_BUSY; 411 while (timercmp (&tv2, &tv1,<)) { 412 assert (gettimeofday (&tv2, NULL) == 0); 413 } 414 statep->flags &= ~FLAGS_IS_BUSY; 415 statep->flags |= FLAGS_WAS_BUSY; 416 417 /* Do we report our status? */ 418 if (statep->flags & FLAGS_REPORT_BUSY_LOOP) 419 write (pipefd[1], &statep->id, 420 sizeof (statep->id)); 421 422 log_trace ("Thread %d: Leaving busy loop.\n", 423 (int) statep->id); 424 break; 425 426 case CMD_PROTECTED_OP: 427 assert (pthread_mutex_lock (cmd.mutex) == 0); 428 statep->flags |= FLAGS_WAS_BUSY; 429 /* Do we report our status? */ 430 if (statep->flags & FLAGS_REPORT_BUSY_LOOP) 431 write (pipefd[1], &statep->id, 432 sizeof (statep->id)); 433 434 assert (pthread_mutex_unlock (cmd.mutex) == 0); 435 break; 436 437 case CMD_RELEASE_ALL: 438 assert ((mutex_count <= sizeof (held_mutex)) && 439 (mutex_count > 0)); 440 for (i = mutex_count - 1; i >= 0; i--) { 441 if (held_mutex_owned[i] != 0) 442 assert (pthread_mutex_unlock 443 (held_mutex[i]) == 0); 444 } 445 mutex_count = 0; 446 break; 447 448 case CMD_NONE: 449 default: 450 break; 451 } 452 453 /* Wait for the big giant waiter lock. */ 454 statep->status = STAT_WAITMUTEX; 455 log_trace ("Thread %d: waiting for big giant lock.\n", 456 (int) statep->id); 457 pthread_mutex_lock (&waiter_mutex); 458 if (statep->flags & FLAGS_REPORT_WAITMUTEX) 459 write (pipefd[1], &statep->id, sizeof (statep->id)); 460 log_trace ("Thread %d: got big giant lock.\n", 461 (int) statep->id); 462 statep->status = STAT_INITIAL; 463 pthread_mutex_unlock (&waiter_mutex); 464 } 465 466 log_trace ("Thread %d: Exiting thread 0x%p\n", (int) statep->id, 467 pthread_self()); 468 pthread_exit (arg); 469 return (NULL); 470 } 471 472 473 static void * 474 lock_twice (void *arg) 475 { 476 thread_state_t *statep = (thread_state_t *) arg; 477 sigset_t mask; 478 479 statep->status = STAT_INITIAL; 480 481 /* Block all signals except for interrupt.*/ 482 sigfillset (&mask); 483 sigdelset (&mask, SIGINT); 484 sigprocmask (SIG_BLOCK, &mask, NULL); 485 486 /* Wait for a signal to continue. */ 487 log_trace ("Thread %d: locking cond_mutex.\n", (int) statep->id); 488 pthread_mutex_lock (&cond_mutex); 489 490 log_trace ("Thread %d: waiting for cond_var.\n", (int) statep->id); 491 statep->status = STAT_WAITCONDVAR; 492 pthread_cond_wait (&cond_var, &cond_mutex); 493 494 log_trace ("Thread %d: received cond_var signal.\n", (int) statep->id); 495 496 /* Unlock the condition variable mutex. */ 497 assert (pthread_mutex_unlock (&cond_mutex) == 0); 498 499 statep->status = STAT_WAITMUTEX; 500 /* Lock the mutex once. */ 501 assert (pthread_mutex_lock (statep->cmd.mutex) == 0); 502 503 /* Lock it again and capture the error. */ 504 statep->ret = pthread_mutex_lock (statep->cmd.mutex); 505 statep->status = 0; 506 507 assert (pthread_mutex_unlock (statep->cmd.mutex) == 0); 508 509 /* Unlock it again if it is locked recursively. */ 510 if (statep->ret == 0) 511 pthread_mutex_unlock (statep->cmd.mutex); 512 513 log_trace ("Thread %d: Exiting thread 0x%p\n", (int) statep->id, 514 pthread_self()); 515 pthread_exit (arg); 516 return (NULL); 517 } 518 519 520 static void 521 sighandler (int signo) 522 { 523 log_info ("Signal handler caught signal %d, thread id 0x%p\n", 524 signo, pthread_self()); 525 526 if (signo == SIGINT) 527 done = 1; 528 } 529 530 531 static void 532 send_cmd (int id, thread_cmd_id_t cmd) 533 { 534 assert (pthread_mutex_lock (&cond_mutex) == 0); 535 assert (states[id].status == STAT_WAITCONDVAR); 536 states[id].cmd.cmd_id = cmd; 537 states[id].cmd.mutex = NULL; 538 states[id].cmd.cond = NULL; 539 /* Clear the busy flags. */ 540 states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY); 541 assert (pthread_cond_signal (&states[id].cond_var) == 0); 542 assert (pthread_mutex_unlock (&cond_mutex) == 0); 543 } 544 545 546 static void 547 send_mutex_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m) 548 { 549 assert (pthread_mutex_lock (&cond_mutex) == 0); 550 assert (states[id].status == STAT_WAITCONDVAR); 551 states[id].cmd.cmd_id = cmd; 552 states[id].cmd.mutex = m; 553 states[id].cmd.cond = NULL; 554 /* Clear the busy flags. */ 555 states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY); 556 assert (pthread_cond_signal (&states[id].cond_var) == 0); 557 assert (pthread_mutex_unlock (&cond_mutex) == 0); 558 } 559 560 561 static void 562 send_mutex_cv_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m, 563 pthread_cond_t *cv) 564 { 565 assert (pthread_mutex_lock (&cond_mutex) == 0); 566 assert (states[id].status == STAT_WAITCONDVAR); 567 states[id].cmd.cmd_id = cmd; 568 states[id].cmd.mutex = m; 569 states[id].cmd.cond = cv; 570 /* Clear the busy flags. */ 571 states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY); 572 assert (pthread_cond_signal (&states[id].cond_var) == 0); 573 assert (pthread_mutex_unlock (&cond_mutex) == 0); 574 } 575 576 577 static void 578 mutex_init_test (void) 579 { 580 pthread_mutexattr_t mattr; 581 pthread_mutex_t mutex; 582 mutex_kind_t mkind; 583 int mproto, ret; 584 585 /* 586 * Initialize a mutex attribute. 587 * 588 * pthread_mutexattr_init not tested for: ENOMEM 589 */ 590 assert (pthread_mutexattr_init (&mattr) == 0); 591 592 /* 593 * Initialize a mutex. 594 * 595 * pthread_mutex_init not tested for: EAGAIN ENOMEM EPERM EBUSY 596 */ 597 log_info ("Testing pthread_mutex_init\n"); 598 log_info ("--------------------------\n"); 599 600 for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) { 601 for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { 602 /* Initialize the mutex attribute. */ 603 assert (pthread_mutexattr_init (&mattr) == 0); 604 assert (pthread_mutexattr_setprotocol (&mattr, 605 protocols[mproto]) == 0); 606 607 /* 608 * Ensure that the first mutex type is a POSIX 609 * compliant mutex. 610 */ 611 if (mkind != M_POSIX) { 612 assert (pthread_mutexattr_settype (&mattr, 613 mutex_types[mkind]) == 0); 614 } 615 616 log_info (" Protocol %s, Type %s - ", 617 protocol_strs[mproto], mutextype_strs[mkind]); 618 ret = pthread_mutex_init (&mutex, &mattr); 619 check_result (/* expected */ 0, ret); 620 assert (pthread_mutex_destroy (&mutex) == 0); 621 622 /* 623 * Destroy a mutex attribute. 624 * 625 * XXX - There should probably be a magic number 626 * associated with a mutex attribute so that 627 * destroy can be reasonably sure the attribute 628 * is valid. 629 * 630 * pthread_mutexattr_destroy not tested for: EINVAL 631 */ 632 assert (pthread_mutexattr_destroy (&mattr) == 0); 633 } 634 } 635 } 636 637 638 static void 639 mutex_destroy_test (void) 640 { 641 pthread_mutexattr_t mattr; 642 pthread_mutex_t mutex; 643 pthread_condattr_t cattr; 644 pthread_cond_t cv; 645 pthread_attr_t pattr; 646 int mproto, ret; 647 mutex_kind_t mkind; 648 #if 0 649 thread_state_t state; 650 #endif 651 652 /* 653 * Destroy a mutex. 654 * 655 * XXX - There should probably be a magic number associated 656 * with a mutex so that destroy can be reasonably sure 657 * the mutex is valid. 658 * 659 * pthread_mutex_destroy not tested for: 660 */ 661 log_info ("Testing pthread_mutex_destroy\n"); 662 log_info ("-----------------------------\n"); 663 664 assert (pthread_attr_init (&pattr) == 0); 665 assert (pthread_attr_setdetachstate (&pattr, 666 PTHREAD_CREATE_DETACHED) == 0); 667 #if 0 668 state.flags = 0; /* No flags yet. */ 669 #endif 670 671 for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) { 672 for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { 673 /* Initialize the mutex attribute. */ 674 assert (pthread_mutexattr_init (&mattr) == 0); 675 assert (pthread_mutexattr_setprotocol (&mattr, 676 protocols[mproto]) == 0); 677 678 /* 679 * Ensure that the first mutex type is a POSIX 680 * compliant mutex. 681 */ 682 if (mkind != M_POSIX) { 683 assert (pthread_mutexattr_settype (&mattr, 684 mutex_types[mkind]) == 0); 685 } 686 687 /* Create the mutex. */ 688 assert (pthread_mutex_init (&mutex, &mattr) == 0); 689 690 log_info (" Protocol %s, Type %s\n", 691 protocol_strs[mproto], mutextype_strs[mkind]); 692 693 log_info (" Destruction of unused mutex - "); 694 assert (pthread_mutex_init (&mutex, &mattr) == 0); 695 ret = pthread_mutex_destroy (&mutex); 696 check_result (/* expected */ 0, ret); 697 698 log_info (" Destruction of mutex locked by self - "); 699 assert (pthread_mutex_init (&mutex, &mattr) == 0); 700 assert (pthread_mutex_lock (&mutex) == 0); 701 ret = pthread_mutex_destroy (&mutex); 702 check_result (/* expected */ EBUSY, ret); 703 assert (pthread_mutex_unlock (&mutex) == 0); 704 assert (pthread_mutex_destroy (&mutex) == 0); 705 706 log_info (" Destruction of mutex locked by another " 707 "thread - "); 708 assert (pthread_mutex_init (&mutex, &mattr) == 0); 709 send_mutex_cmd (0, CMD_TAKE_MUTEX, &mutex); 710 sleep (1); 711 ret = pthread_mutex_destroy (&mutex); 712 check_result (/* expected */ EBUSY, ret); 713 send_cmd (0, CMD_RELEASE_ALL); 714 sleep (1); 715 assert (pthread_mutex_destroy (&mutex) == 0); 716 717 log_info (" Destruction of mutex while being used in " 718 "cond_wait - "); 719 assert (pthread_mutex_init (&mutex, &mattr) == 0); 720 assert (pthread_condattr_init (&cattr) == 0); 721 assert (pthread_cond_init (&cv, &cattr) == 0); 722 send_mutex_cv_cmd (0, CMD_WAIT_FOR_SIGNAL, &mutex, &cv); 723 sleep (1); 724 ret = pthread_mutex_destroy (&mutex); 725 check_result (/* expected */ EBUSY, ret); 726 pthread_cond_signal (&cv); 727 sleep (1); 728 assert (pthread_mutex_destroy (&mutex) == 0); 729 } 730 } 731 } 732 733 734 static void 735 mutex_lock_test (void) 736 { 737 pthread_mutexattr_t mattr; 738 pthread_mutex_t mutex; 739 pthread_attr_t pattr; 740 int mproto, ret; 741 mutex_kind_t mkind; 742 thread_state_t state; 743 744 /* 745 * Lock a mutex. 746 * 747 * pthread_lock not tested for: 748 */ 749 log_info ("Testing pthread_mutex_lock\n"); 750 log_info ("--------------------------\n"); 751 752 assert (pthread_attr_init (&pattr) == 0); 753 assert (pthread_attr_setdetachstate (&pattr, 754 PTHREAD_CREATE_DETACHED) == 0); 755 state.flags = 0; /* No flags yet. */ 756 757 for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) { 758 for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { 759 /* Initialize the mutex attribute. */ 760 assert (pthread_mutexattr_init (&mattr) == 0); 761 assert (pthread_mutexattr_setprotocol (&mattr, 762 protocols[mproto]) == 0); 763 764 /* 765 * Ensure that the first mutex type is a POSIX 766 * compliant mutex. 767 */ 768 if (mkind != M_POSIX) { 769 assert (pthread_mutexattr_settype (&mattr, 770 mutex_types[mkind]) == 0); 771 } 772 773 /* Create the mutex. */ 774 assert (pthread_mutex_init (&mutex, &mattr) == 0); 775 776 log_info (" Protocol %s, Type %s\n", 777 protocol_strs[mproto], mutextype_strs[mkind]); 778 779 log_info (" Lock on unlocked mutex - "); 780 ret = pthread_mutex_lock (&mutex); 781 check_result (/* expected */ 0, ret); 782 pthread_mutex_unlock (&mutex); 783 784 log_info (" Lock on invalid mutex - "); 785 ret = pthread_mutex_lock (NULL); 786 check_result (/* expected */ EINVAL, ret); 787 788 log_info (" Lock on mutex held by self - "); 789 assert (pthread_create (&state.tid, &pattr, lock_twice, 790 (void *) &state) == 0); 791 /* Let the thread start. */ 792 sleep (1); 793 state.cmd.mutex = &mutex; 794 state.ret = 0xdeadbeef; 795 assert (pthread_mutex_lock (&cond_mutex) == 0); 796 assert (pthread_cond_signal (&cond_var) == 0); 797 assert (pthread_mutex_unlock (&cond_mutex) == 0); 798 /* Let the thread receive and process the command. */ 799 sleep (1); 800 801 switch (mkind) { 802 case M_POSIX: 803 check_result (/* expected */ EDEADLK, 804 state.ret); 805 break; 806 case M_SS2_DEFAULT: 807 check_result (/* expected */ EDEADLK, 808 state.ret); 809 break; 810 case M_SS2_ERRORCHECK: 811 check_result (/* expected */ EDEADLK, 812 state.ret); 813 break; 814 case M_SS2_NORMAL: 815 check_result (/* expected */ 0xdeadbeef, 816 state.ret); 817 break; 818 case M_SS2_RECURSIVE: 819 check_result (/* expected */ 0, state.ret); 820 break; 821 } 822 pthread_mutex_destroy (&mutex); 823 pthread_mutexattr_destroy (&mattr); 824 } 825 } 826 } 827 828 829 static void 830 mutex_unlock_test (void) 831 { 832 const int test_thread_id = 0; /* ID of test thread */ 833 pthread_mutexattr_t mattr; 834 pthread_mutex_t mutex; 835 int mproto, ret; 836 mutex_kind_t mkind; 837 838 /* 839 * Unlock a mutex. 840 * 841 * pthread_unlock not tested for: 842 */ 843 log_info ("Testing pthread_mutex_unlock\n"); 844 log_info ("----------------------------\n"); 845 846 for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) { 847 for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { 848 /* Initialize the mutex attribute. */ 849 assert (pthread_mutexattr_init (&mattr) == 0); 850 assert (pthread_mutexattr_setprotocol (&mattr, 851 protocols[mproto]) == 0); 852 853 /* 854 * Ensure that the first mutex type is a POSIX 855 * compliant mutex. 856 */ 857 if (mkind != M_POSIX) { 858 assert (pthread_mutexattr_settype (&mattr, 859 mutex_types[mkind]) == 0); 860 } 861 862 /* Create the mutex. */ 863 assert (pthread_mutex_init (&mutex, &mattr) == 0); 864 865 log_info (" Protocol %s, Type %s\n", 866 protocol_strs[mproto], mutextype_strs[mkind]); 867 868 log_info (" Unlock on mutex held by self - "); 869 assert (pthread_mutex_lock (&mutex) == 0); 870 ret = pthread_mutex_unlock (&mutex); 871 check_result (/* expected */ 0, ret); 872 873 log_info (" Unlock on invalid mutex - "); 874 ret = pthread_mutex_unlock (NULL); 875 check_result (/* expected */ EINVAL, ret); 876 877 log_info (" Unlock on mutex locked by another thread - "); 878 send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &mutex); 879 sleep (1); 880 ret = pthread_mutex_unlock (&mutex); 881 switch (mkind) { 882 case M_POSIX: 883 check_result (/* expected */ EPERM, ret); 884 break; 885 case M_SS2_DEFAULT: 886 check_result (/* expected */ EPERM, ret); 887 break; 888 case M_SS2_ERRORCHECK: 889 check_result (/* expected */ EPERM, ret); 890 break; 891 case M_SS2_NORMAL: 892 check_result (/* expected */ EPERM, ret); 893 break; 894 case M_SS2_RECURSIVE: 895 check_result (/* expected */ EPERM, ret); 896 break; 897 } 898 if (ret == 0) { 899 /* 900 * If for some reason we were able to unlock 901 * the mutex, relock it so that the test 902 * thread has no problems releasing the mutex. 903 */ 904 pthread_mutex_lock (&mutex); 905 } 906 send_cmd (test_thread_id, CMD_RELEASE_ALL); 907 sleep (1); 908 909 pthread_mutex_destroy (&mutex); 910 pthread_mutexattr_destroy (&mattr); 911 } 912 } 913 } 914 915 916 static void 917 queueing_order_test (void) 918 { 919 int i; 920 921 log_info ("Testing queueing order\n"); 922 log_info ("----------------------\n"); 923 assert (pthread_mutex_lock (&waiter_mutex) == 0); 924 /* 925 * Tell the threads to report when they take the waiters mutex. 926 */ 927 assert (pthread_mutex_lock (&cond_mutex) == 0); 928 for (i = 0; i < NUM_THREADS; i++) { 929 states[i].flags = FLAGS_REPORT_WAITMUTEX; 930 assert (pthread_cond_signal (&states[i].cond_var) == 0); 931 } 932 assert (pthread_mutex_unlock (&cond_mutex) == 0); 933 934 /* Signal the threads to continue. */ 935 sleep (1); 936 937 /* Use the global condition variable next time. */ 938 use_global_condvar = 1; 939 940 /* Release the waiting threads and allow them to run again. */ 941 assert (pthread_mutex_unlock (&waiter_mutex) == 0); 942 sleep (1); 943 944 log_info (" Queueing order on a mutex - "); 945 check_run_order ("9,8,7,6,5,4,3,2,1,0"); 946 for (i = 0; i < NUM_THREADS; i = i + 1) { 947 /* Tell the threads to report when they've been signaled. */ 948 states[i].flags = FLAGS_REPORT_WAITCONDVAR; 949 } 950 951 /* 952 * Prevent the threads from continuing their loop after we 953 * signal them. 954 */ 955 assert (pthread_mutex_lock (&waiter_mutex) == 0); 956 957 958 log_info (" Queueing order on a condition variable - "); 959 /* 960 * Signal one thread to run and see that the highest priority 961 * thread executes. 962 */ 963 assert (pthread_mutex_lock (&cond_mutex) == 0); 964 assert (pthread_cond_signal (&cond_var) == 0); 965 assert (pthread_mutex_unlock (&cond_mutex) == 0); 966 sleep (1); 967 if (states[NUM_THREADS - 1].status != STAT_WAITMUTEX) 968 log_error ("highest priority thread does not run.\n"); 969 970 /* Signal the remaining threads. */ 971 assert (pthread_mutex_lock (&cond_mutex) == 0); 972 assert (pthread_cond_broadcast (&cond_var) == 0); 973 assert (pthread_mutex_unlock (&cond_mutex) == 0); 974 sleep (1); 975 976 check_run_order ("9,8,7,6,5,4,3,2,1,0"); 977 for (i = 0; i < NUM_THREADS; i = i + 1) { 978 /* Tell the threads not to report anything. */ 979 states[i].flags = 0; 980 } 981 982 /* Use the thread unique condition variable next time. */ 983 use_global_condvar = 0; 984 985 /* Allow the threads to continue their loop. */ 986 assert (pthread_mutex_unlock (&waiter_mutex) == 0); 987 sleep (1); 988 } 989 990 991 static void 992 mutex_prioceiling_test (void) 993 { 994 const int test_thread_id = 0; /* ID of test thread */ 995 pthread_mutexattr_t mattr; 996 struct sched_param param; 997 pthread_mutex_t m[3]; 998 mutex_kind_t mkind; 999 int i, ret, policy, my_prio, old_ceiling; 1000 1001 log_info ("Testing priority ceilings\n"); 1002 log_info ("-------------------------\n"); 1003 for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { 1004 1005 log_info (" Protype PTHREAD_PRIO_PROTECT, Type %s\n", 1006 mutextype_strs[mkind]); 1007 1008 /* 1009 * Initialize and create a mutex. 1010 */ 1011 assert (pthread_mutexattr_init (&mattr) == 0); 1012 1013 /* Get this threads current priority. */ 1014 assert (pthread_getschedparam (pthread_self(), &policy, 1015 ¶m) == 0); 1016 my_prio = param.sched_priority; /* save for later use */ 1017 log_trace ("Current scheduling policy %d, priority %d\n", 1018 policy, my_prio); 1019 1020 /* 1021 * Initialize and create 3 priority protection mutexes with 1022 * default (max priority) ceilings. 1023 */ 1024 assert (pthread_mutexattr_setprotocol(&mattr, 1025 PTHREAD_PRIO_PROTECT) == 0); 1026 1027 /* 1028 * Ensure that the first mutex type is a POSIX 1029 * compliant mutex. 1030 */ 1031 if (mkind != M_POSIX) { 1032 assert (pthread_mutexattr_settype (&mattr, 1033 mutex_types[mkind]) == 0); 1034 } 1035 1036 for (i = 0; i < 3; i++) 1037 assert (pthread_mutex_init (&m[i], &mattr) == 0); 1038 1039 /* 1040 * Set the ceiling priorities for the 3 priority protection 1041 * mutexes to, 5 less than, equal to, and 5 greater than, 1042 * this threads current priority. 1043 */ 1044 for (i = 0; i < 3; i++) 1045 assert (pthread_mutex_setprioceiling (&m[i], 1046 my_prio - 5 + 5*i, &old_ceiling) == 0); 1047 1048 /* 1049 * Check that if we attempt to take a mutex whose priority 1050 * ceiling is lower than our priority, we get an error. 1051 */ 1052 log_info (" Lock with ceiling priority < thread priority - "); 1053 ret = pthread_mutex_lock (&m[0]); 1054 check_result (/* expected */ EINVAL, ret); 1055 if (ret == 0) 1056 pthread_mutex_unlock (&m[0]); 1057 1058 /* 1059 * Check that we can take a mutex whose priority ceiling 1060 * is equal to our priority. 1061 */ 1062 log_info (" Lock with ceiling priority = thread priority - "); 1063 ret = pthread_mutex_lock (&m[1]); 1064 check_result (/* expected */ 0, ret); 1065 if (ret == 0) 1066 pthread_mutex_unlock (&m[1]); 1067 1068 /* 1069 * Check that we can take a mutex whose priority ceiling 1070 * is higher than our priority. 1071 */ 1072 log_info (" Lock with ceiling priority > thread priority - "); 1073 ret = pthread_mutex_lock (&m[2]); 1074 check_result (/* expected */ 0, ret); 1075 if (ret == 0) 1076 pthread_mutex_unlock (&m[2]); 1077 1078 /* 1079 * Have the test thread go into a busy loop for 5 seconds 1080 * and see that it doesn't block this thread (since the 1081 * priority ceiling of mutex 0 and the priority of the test 1082 * thread are both less than the priority of this thread). 1083 */ 1084 log_info (" Preemption with ceiling priority < thread " 1085 "priority - "); 1086 /* Have the test thread take mutex 0. */ 1087 send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[0]); 1088 sleep (1); 1089 1090 log_trace ("Sending busy command.\n"); 1091 send_cmd (test_thread_id, CMD_BUSY_LOOP); 1092 log_trace ("Busy sent, yielding\n"); 1093 pthread_yield (); 1094 log_trace ("Returned from yield.\n"); 1095 if (states[test_thread_id].flags & 1096 (FLAGS_IS_BUSY | FLAGS_WAS_BUSY)) 1097 log_error ("test thread inproperly preempted us.\n"); 1098 else { 1099 /* Let the thread finish its busy loop. */ 1100 sleep (6); 1101 if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) 1102 log_error ("test thread never finished.\n"); 1103 else 1104 log_pass (); 1105 } 1106 states[test_thread_id].flags &= ~FLAGS_WAS_BUSY; 1107 1108 /* Have the test thread release mutex 0. */ 1109 send_cmd (test_thread_id, CMD_RELEASE_ALL); 1110 sleep (1); 1111 1112 /* 1113 * Have the test thread go into a busy loop for 5 seconds 1114 * and see that it preempts this thread (since the priority 1115 * ceiling of mutex 1 is the same as the priority of this 1116 * thread). The test thread should not run to completion 1117 * as its time quantum should expire before the 5 seconds 1118 * are up. 1119 */ 1120 log_info (" Preemption with ceiling priority = thread " 1121 "priority - "); 1122 1123 /* Have the test thread take mutex 1. */ 1124 send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]); 1125 sleep (1); 1126 1127 log_trace ("Sending busy\n"); 1128 send_cmd (test_thread_id, CMD_BUSY_LOOP); 1129 log_trace ("Busy sent, yielding\n"); 1130 pthread_yield (); 1131 log_trace ("Returned from yield.\n"); 1132 if ((states[test_thread_id].flags & FLAGS_IS_BUSY) == 0) 1133 log_error ("test thread did not switch in on yield.\n"); 1134 else if (states[test_thread_id].flags & FLAGS_WAS_BUSY) 1135 log_error ("test thread ran to completion.\n"); 1136 else { 1137 /* Let the thread finish its busy loop. */ 1138 sleep (6); 1139 if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) 1140 log_error ("test thread never finished.\n"); 1141 else 1142 log_pass (); 1143 } 1144 states[test_thread_id].flags &= ~FLAGS_WAS_BUSY; 1145 1146 /* Have the test thread release mutex 1. */ 1147 send_cmd (test_thread_id, CMD_RELEASE_ALL); 1148 sleep (1); 1149 1150 /* 1151 * Set the scheduling policy of the test thread to SCHED_FIFO 1152 * and have it go into a busy loop for 5 seconds. This 1153 * thread is SCHED_RR, and since the priority ceiling of 1154 * mutex 1 is the same as the priority of this thread, the 1155 * test thread should run to completion once it is switched 1156 * in. 1157 */ 1158 log_info (" SCHED_FIFO scheduling and ceiling priority = " 1159 "thread priority - "); 1160 param.sched_priority = states[test_thread_id].priority; 1161 assert (pthread_setschedparam (states[test_thread_id].tid, 1162 SCHED_FIFO, ¶m) == 0); 1163 1164 /* Have the test thread take mutex 1. */ 1165 send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]); 1166 sleep (1); 1167 1168 log_trace ("Sending busy\n"); 1169 send_cmd (test_thread_id, CMD_BUSY_LOOP); 1170 log_trace ("Busy sent, yielding\n"); 1171 pthread_yield (); 1172 log_trace ("Returned from yield.\n"); 1173 if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) { 1174 log_error ("test thread did not run to completion.\n"); 1175 /* Let the thread finish it's busy loop. */ 1176 sleep (6); 1177 } 1178 else 1179 log_pass (); 1180 states[test_thread_id].flags &= ~FLAGS_WAS_BUSY; 1181 1182 /* Restore the test thread scheduling parameters. */ 1183 param.sched_priority = states[test_thread_id].priority; 1184 assert (pthread_setschedparam (states[test_thread_id].tid, 1185 SCHED_RR, ¶m) == 0); 1186 1187 /* Have the test thread release mutex 1. */ 1188 send_cmd (test_thread_id, CMD_RELEASE_ALL); 1189 sleep (1); 1190 1191 /* 1192 * Have the test thread go into a busy loop for 5 seconds 1193 * and see that it preempts this thread (since the priority 1194 * ceiling of mutex 2 is the greater than the priority of 1195 * this thread). The test thread should run to completion 1196 * and block this thread because its active priority is 1197 * higher. 1198 */ 1199 log_info (" SCHED_FIFO scheduling and ceiling priority > " 1200 "thread priority - "); 1201 /* Have the test thread take mutex 2. */ 1202 send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[2]); 1203 sleep (1); 1204 1205 log_trace ("Sending busy\n"); 1206 send_cmd (test_thread_id, CMD_BUSY_LOOP); 1207 log_trace ("Busy sent, yielding\n"); 1208 pthread_yield (); 1209 log_trace ("Returned from yield.\n"); 1210 if ((states[test_thread_id].flags & FLAGS_IS_BUSY) != 0) { 1211 log_error ("test thread did not run to completion.\n"); 1212 /* Let the thread finish it's busy loop. */ 1213 sleep (6); 1214 } 1215 else if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) 1216 log_error ("test thread never finished.\n"); 1217 else 1218 log_pass (); 1219 states[test_thread_id].flags &= ~FLAGS_WAS_BUSY; 1220 1221 /* Have the test thread release mutex 2. */ 1222 send_cmd (test_thread_id, CMD_RELEASE_ALL); 1223 sleep (1); 1224 1225 /* Destroy the mutexes. */ 1226 for (i = 0; i < 3; i++) 1227 assert (pthread_mutex_destroy (&m[i]) == 0); 1228 } 1229 } 1230 1231 1232 static void 1233 mutex_prioinherit_test (void) 1234 { 1235 pthread_mutexattr_t mattr; 1236 struct sched_param param; 1237 pthread_mutex_t m[3]; 1238 mutex_kind_t mkind; 1239 int i, policy, my_prio; 1240 1241 /* Get this threads current priority. */ 1242 assert (pthread_getschedparam (pthread_self(), &policy, 1243 ¶m) == 0); 1244 my_prio = param.sched_priority; /* save for later use */ 1245 log_trace ("Current scheduling policy %d, priority %d\n", 1246 policy, my_prio); 1247 1248 log_info ("Testing priority inheritance\n"); 1249 log_info ("----------------------------\n"); 1250 for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) { 1251 1252 log_info (" Protype PTHREAD_PRIO_INHERIT, Type %s\n", 1253 mutextype_strs[mkind]); 1254 1255 /* 1256 * Initialize and create a mutex. 1257 */ 1258 assert (pthread_mutexattr_init (&mattr) == 0); 1259 1260 /* 1261 * Initialize and create 3 priority inheritance mutexes with 1262 * default (max priority) ceilings. 1263 */ 1264 assert (pthread_mutexattr_setprotocol(&mattr, 1265 PTHREAD_PRIO_INHERIT) == 0); 1266 1267 /* 1268 * Ensure that the first mutex type is a POSIX 1269 * compliant mutex. 1270 */ 1271 if (mkind != M_POSIX) { 1272 assert (pthread_mutexattr_settype (&mattr, 1273 mutex_types[mkind]) == 0); 1274 } 1275 1276 for (i = 0; i < 3; i++) 1277 assert (pthread_mutex_init (&m[i], &mattr) == 0); 1278 1279 /* 1280 * Test setup: 1281 * Thread 4 - take mutex 0, 1 1282 * Thread 2 - enter protected busy loop with mutex 0 1283 * Thread 3 - enter protected busy loop with mutex 1 1284 * Thread 4 - enter protected busy loop with mutex 2 1285 * Thread 5 - enter busy loop 1286 * Thread 6 - enter protected busy loop with mutex 0 1287 * Thread 4 - releases mutexes 1 and 0. 1288 * 1289 * Expected results: 1290 * Threads complete in order 4, 6, 5, 3, 2 1291 */ 1292 log_info (" Simple inheritance test - "); 1293 1294 /* 1295 * Command thread 4 to take mutexes 0 and 1. 1296 */ 1297 send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]); 1298 sleep (1); /* Allow command to be received. */ 1299 send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[1]); 1300 sleep (1); 1301 1302 /* 1303 * Tell the threads to report themselves when they are 1304 * at the bottom of their loop (waiting on wait_mutex). 1305 */ 1306 for (i = 0; i < NUM_THREADS; i++) 1307 states[i].flags |= FLAGS_REPORT_WAITMUTEX; 1308 1309 /* 1310 * Command thread 2 to take mutex 0 and thread 3 to take 1311 * mutex 1, both via a protected operation command. Since 1312 * thread 4 owns mutexes 0 and 1, both threads 2 and 3 1313 * will block until the mutexes are released by thread 4. 1314 */ 1315 log_trace ("Commanding protected operation to thread 2.\n"); 1316 send_mutex_cmd (2, CMD_PROTECTED_OP, &m[0]); 1317 log_trace ("Commanding protected operation to thread 3.\n"); 1318 send_mutex_cmd (3, CMD_PROTECTED_OP, &m[1]); 1319 sleep (1); 1320 1321 /* 1322 * Command thread 4 to take mutex 2 via a protected operation 1323 * and thread 5 to enter a busy loop for 5 seconds. Since 1324 * thread 5 has higher priority than thread 4, thread 5 will 1325 * enter the busy loop before thread 4 is activated. 1326 */ 1327 log_trace ("Commanding protected operation to thread 4.\n"); 1328 send_mutex_cmd (4, CMD_PROTECTED_OP, &m[2]); 1329 log_trace ("Commanding busy loop to thread 5.\n"); 1330 send_cmd (5, CMD_BUSY_LOOP); 1331 sleep (1); 1332 if ((states[5].flags & FLAGS_IS_BUSY) == 0) 1333 log_error ("thread 5 is not running.\n"); 1334 log_trace ("Commanding protected operation thread 6.\n"); 1335 send_mutex_cmd (6, CMD_PROTECTED_OP, &m[0]); 1336 sleep (1); 1337 if ((states[4].flags & FLAGS_WAS_BUSY) == 0) 1338 log_error ("thread 4 failed to inherit priority.\n"); 1339 states[4].flags = 0; 1340 send_cmd (4, CMD_RELEASE_ALL); 1341 sleep (5); 1342 check_run_order ("4,6,5,3,2"); 1343 1344 /* 1345 * Clear the flags. 1346 */ 1347 for (i = 0; i < NUM_THREADS; i++) 1348 states[i].flags = 0; 1349 1350 /* 1351 * Test setup: 1352 * Thread 2 - enter busy loop (SCHED_FIFO) 1353 * Thread 4 - take mutex 0 1354 * Thread 4 - priority change to same priority as thread 2 1355 * Thread 4 - release mutex 0 1356 * 1357 * Expected results: 1358 * Since thread 4 owns a priority mutex, it should be 1359 * placed at the front of the run queue (for its new 1360 * priority slot) when its priority is lowered to the 1361 * same priority as thread 2. If thread 4 did not own 1362 * a priority mutex, then it would have been added to 1363 * the end of the run queue and thread 2 would have 1364 * executed until it blocked (because it's scheduling 1365 * policy is SCHED_FIFO). 1366 * 1367 */ 1368 log_info (" Inheritance test with change of priority - "); 1369 1370 /* 1371 * Change threads 2 and 4 scheduling policies to be 1372 * SCHED_FIFO. 1373 */ 1374 param.sched_priority = states[2].priority; 1375 assert (pthread_setschedparam (states[2].tid, SCHED_FIFO, 1376 ¶m) == 0); 1377 param.sched_priority = states[4].priority; 1378 assert (pthread_setschedparam (states[4].tid, SCHED_FIFO, 1379 ¶m) == 0); 1380 1381 /* 1382 * Command thread 4 to take mutex 0. 1383 */ 1384 send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]); 1385 sleep (1); 1386 1387 /* 1388 * Command thread 2 to enter busy loop. 1389 */ 1390 send_cmd (2, CMD_BUSY_LOOP); 1391 sleep (1); /* Allow command to be received. */ 1392 1393 /* 1394 * Command thread 4 to enter busy loop. 1395 */ 1396 send_cmd (4, CMD_BUSY_LOOP); 1397 sleep (1); /* Allow command to be received. */ 1398 1399 /* Have threads 2 and 4 report themselves. */ 1400 states[2].flags = FLAGS_REPORT_WAITMUTEX; 1401 states[4].flags = FLAGS_REPORT_WAITMUTEX; 1402 1403 /* Change the priority of thread 4. */ 1404 param.sched_priority = states[2].priority; 1405 assert (pthread_setschedparam (states[4].tid, SCHED_FIFO, 1406 ¶m) == 0); 1407 sleep (5); 1408 check_run_order ("4,2"); 1409 1410 /* Clear the flags */ 1411 states[2].flags = 0; 1412 states[4].flags = 0; 1413 1414 /* Reset the policies. */ 1415 param.sched_priority = states[2].priority; 1416 assert (pthread_setschedparam (states[2].tid, SCHED_RR, 1417 ¶m) == 0); 1418 param.sched_priority = states[4].priority; 1419 assert (pthread_setschedparam (states[4].tid, SCHED_RR, 1420 ¶m) == 0); 1421 1422 send_cmd (4, CMD_RELEASE_MUTEX); 1423 sleep (1); 1424 1425 /* Destroy the mutexes. */ 1426 for (i = 0; i < 3; i++) 1427 assert (pthread_mutex_destroy (&m[i]) == 0); 1428 } 1429 } 1430 1431 1432 int main (int argc, char *argv[]) 1433 { 1434 pthread_mutexattr_t mattr; 1435 pthread_condattr_t cattr; 1436 pthread_attr_t pattr; 1437 int i, policy, main_prio; 1438 void * exit_status; 1439 sigset_t mask; 1440 struct sigaction act; 1441 struct sched_param param; 1442 char buf[30]; 1443 1444 logfile = stdout; 1445 1446 assert (pthread_getschedparam (pthread_self (), &policy, ¶m) == 0); 1447 main_prio = param.sched_priority; 1448 1449 /* Setupt our signal mask. */ 1450 sigfillset (&mask); 1451 sigdelset (&mask, SIGINT); 1452 sigprocmask (SIG_SETMASK, &mask, NULL); 1453 1454 /* Install a signal handler for SIGINT */ 1455 sigemptyset (&act.sa_mask); 1456 sigaddset (&act.sa_mask, SIGINT); 1457 act.sa_handler = sighandler; 1458 act.sa_flags = SA_RESTART; 1459 sigaction (SIGINT, &act, NULL); 1460 1461 /* 1462 * Initialize the thread attribute. 1463 */ 1464 assert (pthread_attr_init (&pattr) == 0); 1465 assert (pthread_attr_setdetachstate (&pattr, 1466 PTHREAD_CREATE_JOINABLE) == 0); 1467 1468 /* 1469 * Initialize and create the waiter and condvar mutexes. 1470 */ 1471 assert (pthread_mutexattr_init (&mattr) == 0); 1472 assert (pthread_mutex_init (&waiter_mutex, &mattr) == 0); 1473 assert (pthread_mutex_init (&cond_mutex, &mattr) == 0); 1474 1475 /* 1476 * Initialize and create a condition variable. 1477 */ 1478 assert (pthread_condattr_init (&cattr) == 0); 1479 assert (pthread_cond_init (&cond_var, &cattr) == 0); 1480 1481 /* Create a pipe to catch the results of thread wakeups. */ 1482 assert (pipe (pipefd) == 0); 1483 1484 #ifdef DEBUG 1485 assert (pthread_switch_add_np (kern_switch) == 0); 1486 #endif 1487 1488 /* 1489 * Create the waiting threads. 1490 */ 1491 for (i = 0; i < NUM_THREADS; i++) { 1492 assert (pthread_cond_init (&states[i].cond_var, &cattr) == 0); 1493 states[i].id = (u_int8_t) i; /* NUM_THREADS must be <= 256 */ 1494 states[i].status = 0; 1495 states[i].cmd.cmd_id = CMD_NONE; 1496 states[i].flags = 0; /* No flags yet. */ 1497 assert (pthread_create (&states[i].tid, &pattr, waiter, 1498 (void *) &states[i]) == 0); 1499 param.sched_priority = main_prio - 10 + i; 1500 states[i].priority = param.sched_priority; 1501 assert (pthread_setschedparam (states[i].tid, SCHED_OTHER, 1502 ¶m) == 0); 1503 snprintf (buf, sizeof(buf), "waiter_%d", i); 1504 pthread_set_name_np (states[i].tid, buf); 1505 } 1506 1507 /* Allow the threads to start. */ 1508 sleep (1); 1509 log_trace ("Done creating threads.\n"); 1510 1511 log_info ("\n"); 1512 mutex_init_test (); 1513 log_info ("\n"); 1514 mutex_destroy_test (); 1515 log_info ("\n"); 1516 mutex_lock_test (); 1517 log_info ("\n"); 1518 mutex_unlock_test (); 1519 log_info ("\n"); 1520 queueing_order_test (); 1521 log_info ("\n"); 1522 mutex_prioinherit_test (); 1523 log_info ("\n"); 1524 mutex_prioceiling_test (); 1525 log_info ("\n"); 1526 1527 log_info ("Total tests %d, passed %d, failed %d\n", 1528 total, pass_count, error_count); 1529 1530 /* Set the done flag and signal the threads to exit. */ 1531 log_trace ("Setting done flag.\n"); 1532 done = 1; 1533 1534 /* 1535 * Wait for the threads to finish. 1536 */ 1537 log_trace ("Trying to join threads.\n"); 1538 for (i = 0; i < NUM_THREADS; i++) { 1539 send_cmd (i, CMD_NONE); 1540 assert (pthread_join (states[i].tid, &exit_status) == 0); 1541 } 1542 1543 /* Clean up after ourselves. */ 1544 close (pipefd[0]); 1545 close (pipefd[1]); 1546 1547 if (error_count != 0) 1548 exit (EX_OSERR); /* any better ideas??? */ 1549 else 1550 exit (EX_OK); 1551 } 1552