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