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