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