2 * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
32 * $FreeBSD: src/lib/libc_r/test/mutex_d.c,v 1.1.2.2 2003/01/05 19:59:39 semenu Exp $
37 #include <sys/ioctl.h>
49 #include <pthread_np.h>
53 #define NELEMENTS(arr) (sizeof (arr) / sizeof (arr[0]))
57 #define NUM_THREADS 10
60 #define MAX_THREAD_CMDS 10
62 static void log_error(const char *, ...) __printflike(1, 2);
63 static void log_trace (const char *, ...) __printflike(1, 2);
64 static void log (const char *, ...) __printflike(1, 2);
66 /*------------------------------------------------------------
68 *----------------------------------------------------------*/
71 STAT_INITIAL, /* initial state */
72 STAT_WAITCONDVAR, /* waiting for condition variable signal */
73 STAT_WAITMUTEX /* waiting for mutex lock */
77 FLAGS_REPORT_WAITCONDMUTEX = 0x01,
78 FLAGS_REPORT_WAITCONDVAR = 0x02,
79 FLAGS_REPORT_WAITMUTEX = 0x04,
80 FLAGS_REPORT_BUSY_LOOP = 0x08,
96 thread_cmd_id_t cmd_id;
97 pthread_mutex_t *mutex;
102 pthread_cond_t cond_var;
103 thread_status_t status;
121 /*------------------------------------------------------------
123 *----------------------------------------------------------*/
125 const char *protocol_strs[] = {
127 "PTHREAD_PRIO_INHERIT",
128 "PTHREAD_PRIO_PROTECT"
131 const int protocols[] = {
133 PTHREAD_PRIO_INHERIT,
137 const 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"
145 const int mutex_types[] = {
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 */
154 /*------------------------------------------------------------
156 *----------------------------------------------------------*/
159 static int trace_enabled = 0;
160 static int use_global_condvar = 0;
161 static thread_state_t states[NUM_THREADS];
162 static int pipefd[2];
164 static pthread_mutex_t waiter_mutex;
165 static pthread_mutex_t cond_mutex;
166 static pthread_cond_t cond_var;
168 static FILE *logfile;
169 static int error_count = 0, pass_count = 0, total = 0;
172 /*------------------------------------------------------------
174 *----------------------------------------------------------*/
175 extern char *strtok_r(char *str, const char *sep, char **last);
178 /*------------------------------------------------------------
180 *----------------------------------------------------------*/
184 kern_switch (pthread_t pthread_out, pthread_t pthread_in)
186 if (pthread_out != NULL)
187 printf ("Swapping out thread 0x%x, ", (int) pthread_out);
189 printf ("Swapping out kernel thread, ");
191 if (pthread_in != NULL)
192 printf ("swapping in thread 0x%x\n", (int) pthread_in);
194 printf ("swapping in kernel thread.\n");
200 log_error (const char *fmt, ...)
205 fprintf (logfile, "FAIL: ");
206 vfprintf (logfile, fmt, ap);
207 error_count = error_count + 1;
215 fprintf (logfile, "PASS\n");
216 pass_count = pass_count + 1;
222 log_trace (const char *fmt, ...)
228 vfprintf (logfile, fmt, ap);
234 log (const char *fmt, ...)
239 vfprintf (logfile, fmt, ap);
244 check_result (int expected, int actual)
246 if (expected != actual)
247 log_error ("expected %d, returned %d\n", expected, actual);
254 * Check to see that the threads ran in the specified order.
257 check_run_order (char *order)
259 const char *sep = ":,";
260 char *tok, *last, *idstr, *endptr;
261 int expected_id, bytes, count = 0, errors = 0;
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);
269 for (idstr = strtok_r (tok, sep, &last);
270 (idstr != NULL) && (count < bytes);
271 idstr = strtok_r (NULL, sep, &last)) {
273 /* Get the expected id: */
274 expected_id = (int) strtol (idstr, &endptr, 10);
275 assert ((endptr != NULL) && (*endptr == '\0'));
277 /* Read the actual id from the pipe: */
278 assert (read (pipefd[0], &id, sizeof (id)) == sizeof (id));
279 count = count + sizeof (id);
281 if (id != expected_id) {
282 log_trace ("Thread %d ran out of order.\n", id);
286 log_trace ("Thread %d at priority %d reporting.\n",
287 (int) id, states[id].priority);
292 /* Clear the pipe: */
293 while (count < bytes) {
294 read (pipefd[0], &id, sizeof (id));
299 else if (bytes < count)
300 errors = errors + count - bytes;
305 log_error ("%d threads ran out of order", errors);
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];
316 struct timeval tv1, tv2;
318 int i, mutex_count = 0;
320 statep->status = STAT_INITIAL;
322 /* Block all signals except for interrupt.*/
324 sigdelset (&mask, SIGINT);
325 sigprocmask (SIG_BLOCK, &mask, NULL);
328 /* Wait for signal from the main thread to continue. */
329 statep->status = STAT_WAITMUTEX;
330 log_trace ("Thread %d: locking cond_mutex.\n",
332 pthread_mutex_lock (&cond_mutex);
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",
340 /* Wait for a command. */
341 statep->status = STAT_WAITCONDVAR;
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).
349 if (use_global_condvar != 0)
350 pthread_cond_wait (&cond_var, &cond_mutex);
352 pthread_cond_wait (&statep->cond_var, &cond_mutex);
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",
360 log_trace ("Thread %d: received cond_var signal.\n",
363 /* Get a copy of the command before releasing the mutex. */
366 /* Clear the command after copying it. */
367 statep->cmd.cmd_id = CMD_NONE;
369 /* Unlock the condition variable mutex. */
370 assert (pthread_mutex_unlock (&cond_mutex) == 0);
372 /* Peform the command.*/
373 switch (cmd.cmd_id) {
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;
383 held_mutex_owned[mutex_count] = 0;
384 log_trace ("Thread id %d unable to lock mutex, "
385 "error = %d\n", (int) statep->id,
390 case CMD_RELEASE_MUTEX:
391 assert ((mutex_count <= sizeof (held_mutex)) &&
394 if (held_mutex_owned[mutex_count] != 0)
395 assert (pthread_mutex_unlock
396 (held_mutex[mutex_count]) == 0);
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);
406 log_trace ("Thread %d: Entering busy loop.\n",
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);
416 statep->flags &= ~FLAGS_IS_BUSY;
417 statep->flags |= FLAGS_WAS_BUSY;
419 /* Do we report our status? */
420 if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
421 write (pipefd[1], &statep->id,
422 sizeof (statep->id));
424 log_trace ("Thread %d: Leaving busy loop.\n",
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));
436 assert (pthread_mutex_unlock (cmd.mutex) == 0);
439 case CMD_RELEASE_ALL:
440 assert ((mutex_count <= sizeof (held_mutex)) &&
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);
455 /* Wait for the big giant waiter lock. */
456 statep->status = STAT_WAITMUTEX;
457 log_trace ("Thread %d: waiting for big giant lock.\n",
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",
464 statep->status = STAT_INITIAL;
465 pthread_mutex_unlock (&waiter_mutex);
468 log_trace ("Thread %d: Exiting thread 0x%x\n", (int) statep->id,
469 (int) pthread_self());
476 lock_twice (void *arg)
478 thread_state_t *statep = (thread_state_t *) arg;
481 statep->status = STAT_INITIAL;
483 /* Block all signals except for interrupt.*/
485 sigdelset (&mask, SIGINT);
486 sigprocmask (SIG_BLOCK, &mask, NULL);
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);
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);
496 log_trace ("Thread %d: received cond_var signal.\n", (int) statep->id);
498 /* Unlock the condition variable mutex. */
499 assert (pthread_mutex_unlock (&cond_mutex) == 0);
501 statep->status = STAT_WAITMUTEX;
502 /* Lock the mutex once. */
503 assert (pthread_mutex_lock (statep->cmd.mutex) == 0);
505 /* Lock it again and capture the error. */
506 statep->ret = pthread_mutex_lock (statep->cmd.mutex);
509 assert (pthread_mutex_unlock (statep->cmd.mutex) == 0);
511 /* Unlock it again if it is locked recursively. */
512 if (statep->ret == 0)
513 pthread_mutex_unlock (statep->cmd.mutex);
515 log_trace ("Thread %d: Exiting thread 0x%x\n", (int) statep->id,
516 (int) pthread_self());
523 sighandler (int signo)
525 log ("Signal handler caught signal %d, thread id 0x%x\n",
526 signo, (int) pthread_self());
534 send_cmd (int id, thread_cmd_id_t cmd)
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);
549 send_mutex_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m)
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);
564 send_mutex_cv_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m,
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);
580 mutex_init_test (void)
582 pthread_mutexattr_t mattr;
583 pthread_mutex_t mutex;
588 * Initialize a mutex attribute.
590 * pthread_mutexattr_init not tested for: ENOMEM
592 assert (pthread_mutexattr_init (&mattr) == 0);
595 * Initialize a mutex.
597 * pthread_mutex_init not tested for: EAGAIN ENOMEM EPERM EBUSY
599 log ("Testing pthread_mutex_init\n");
600 log ("--------------------------\n");
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);
610 * Ensure that the first mutex type is a POSIX
613 if (mkind != M_POSIX) {
614 assert (pthread_mutexattr_settype (&mattr,
615 mutex_types[mkind]) == 0);
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);
625 * Destroy a mutex attribute.
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
632 * pthread_mutexattr_destroy not tested for: EINVAL
634 assert (pthread_mutexattr_destroy (&mattr) == 0);
641 mutex_destroy_test (void)
643 pthread_mutexattr_t mattr;
644 pthread_mutex_t mutex;
645 pthread_condattr_t cattr;
647 pthread_attr_t pattr;
650 thread_state_t state;
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.
659 * pthread_mutex_destroy not tested for:
661 log ("Testing pthread_mutex_destroy\n");
662 log ("-----------------------------\n");
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. */
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);
677 * Ensure that the first mutex type is a POSIX
680 if (mkind != M_POSIX) {
681 assert (pthread_mutexattr_settype (&mattr,
682 mutex_types[mkind]) == 0);
685 /* Create the mutex. */
686 assert (pthread_mutex_init (&mutex, &mattr) == 0);
688 log (" Protocol %s, Type %s\n",
689 protocol_strs[mproto], mutextype_strs[mkind]);
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);
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);
704 log (" Destruction of mutex locked by another "
706 assert (pthread_mutex_init (&mutex, &mattr) == 0);
707 send_mutex_cmd (0, CMD_TAKE_MUTEX, &mutex);
709 ret = pthread_mutex_destroy (&mutex);
710 check_result (/* expected */ EBUSY, ret);
711 send_cmd (0, CMD_RELEASE_ALL);
713 assert (pthread_mutex_destroy (&mutex) == 0);
715 log (" Destruction of mutex while being used in "
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);
722 ret = pthread_mutex_destroy (&mutex);
723 check_result (/* expected */ EBUSY, ret);
724 pthread_cond_signal (&cv);
726 assert (pthread_mutex_destroy (&mutex) == 0);
733 mutex_lock_test (void)
735 pthread_mutexattr_t mattr;
736 pthread_mutex_t mutex;
737 pthread_attr_t pattr;
740 thread_state_t state;
745 * pthread_lock not tested for:
747 log ("Testing pthread_mutex_lock\n");
748 log ("--------------------------\n");
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. */
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);
763 * Ensure that the first mutex type is a POSIX
766 if (mkind != M_POSIX) {
767 assert (pthread_mutexattr_settype (&mattr,
768 mutex_types[mkind]) == 0);
771 /* Create the mutex. */
772 assert (pthread_mutex_init (&mutex, &mattr) == 0);
774 log (" Protocol %s, Type %s\n",
775 protocol_strs[mproto], mutextype_strs[mkind]);
777 log (" Lock on unlocked mutex - ");
778 ret = pthread_mutex_lock (&mutex);
779 check_result (/* expected */ 0, ret);
780 pthread_mutex_unlock (&mutex);
782 log (" Lock on invalid mutex - ");
783 ret = pthread_mutex_lock (NULL);
784 check_result (/* expected */ EINVAL, ret);
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. */
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. */
801 check_result (/* expected */ EDEADLK,
805 check_result (/* expected */ EDEADLK,
808 case M_SS2_ERRORCHECK:
809 check_result (/* expected */ EDEADLK,
813 check_result (/* expected */ 0xdeadbeef,
816 case M_SS2_RECURSIVE:
817 check_result (/* expected */ 0, state.ret);
820 pthread_mutex_destroy (&mutex);
821 pthread_mutexattr_destroy (&mattr);
828 mutex_unlock_test (void)
830 const int test_thread_id = 0; /* ID of test thread */
831 pthread_mutexattr_t mattr;
832 pthread_mutex_t mutex;
839 * pthread_unlock not tested for:
841 log ("Testing pthread_mutex_unlock\n");
842 log ("----------------------------\n");
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);
852 * Ensure that the first mutex type is a POSIX
855 if (mkind != M_POSIX) {
856 assert (pthread_mutexattr_settype (&mattr,
857 mutex_types[mkind]) == 0);
860 /* Create the mutex. */
861 assert (pthread_mutex_init (&mutex, &mattr) == 0);
863 log (" Protocol %s, Type %s\n",
864 protocol_strs[mproto], mutextype_strs[mkind]);
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);
871 log (" Unlock on invalid mutex - ");
872 ret = pthread_mutex_unlock (NULL);
873 check_result (/* expected */ EINVAL, ret);
875 log (" Unlock on mutex locked by another thread - ");
876 send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &mutex);
878 ret = pthread_mutex_unlock (&mutex);
881 check_result (/* expected */ EPERM, ret);
884 check_result (/* expected */ EPERM, ret);
886 case M_SS2_ERRORCHECK:
887 check_result (/* expected */ EPERM, ret);
890 check_result (/* expected */ EPERM, ret);
892 case M_SS2_RECURSIVE:
893 check_result (/* expected */ EPERM, ret);
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.
902 pthread_mutex_lock (&mutex);
904 send_cmd (test_thread_id, CMD_RELEASE_ALL);
907 pthread_mutex_destroy (&mutex);
908 pthread_mutexattr_destroy (&mattr);
915 queueing_order_test (void)
919 log ("Testing queueing order\n");
920 log ("----------------------\n");
921 assert (pthread_mutex_lock (&waiter_mutex) == 0);
923 * Tell the threads to report when they take the waiters mutex.
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);
930 assert (pthread_mutex_unlock (&cond_mutex) == 0);
932 /* Signal the threads to continue. */
935 /* Use the global condition variable next time. */
936 use_global_condvar = 1;
938 /* Release the waiting threads and allow them to run again. */
939 assert (pthread_mutex_unlock (&waiter_mutex) == 0);
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;
950 * Prevent the threads from continuing their loop after we
953 assert (pthread_mutex_lock (&waiter_mutex) == 0);
956 log (" Queueing order on a condition variable - ");
958 * Signal one thread to run and see that the highest priority
961 assert (pthread_mutex_lock (&cond_mutex) == 0);
962 assert (pthread_cond_signal (&cond_var) == 0);
963 assert (pthread_mutex_unlock (&cond_mutex) == 0);
965 if (states[NUM_THREADS - 1].status != STAT_WAITMUTEX)
966 log_error ("highest priority thread does not run.\n");
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);
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. */
980 /* Use the thread unique condition variable next time. */
981 use_global_condvar = 0;
983 /* Allow the threads to continue their loop. */
984 assert (pthread_mutex_unlock (&waiter_mutex) == 0);
990 mutex_prioceiling_test (void)
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];
997 int i, ret, policy, my_prio, old_ceiling;
999 log ("Testing priority ceilings\n");
1000 log ("-------------------------\n");
1001 for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
1003 log (" Protype PTHREAD_PRIO_PROTECT, Type %s\n",
1004 mutextype_strs[mkind]);
1007 * Initialize and create a mutex.
1009 assert (pthread_mutexattr_init (&mattr) == 0);
1011 /* Get this threads current priority. */
1012 assert (pthread_getschedparam (pthread_self(), &policy,
1014 my_prio = param.sched_priority; /* save for later use */
1015 log_trace ("Current scheduling policy %d, priority %d\n",
1019 * Initialize and create 3 priority protection mutexes with
1020 * default (max priority) ceilings.
1022 assert (pthread_mutexattr_setprotocol(&mattr,
1023 PTHREAD_PRIO_PROTECT) == 0);
1026 * Ensure that the first mutex type is a POSIX
1029 if (mkind != M_POSIX) {
1030 assert (pthread_mutexattr_settype (&mattr,
1031 mutex_types[mkind]) == 0);
1034 for (i = 0; i < 3; i++)
1035 assert (pthread_mutex_init (&m[i], &mattr) == 0);
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.
1042 for (i = 0; i < 3; i++)
1043 assert (pthread_mutex_setprioceiling (&m[i],
1044 my_prio - 5 + 5*i, &old_ceiling) == 0);
1047 * Check that if we attempt to take a mutex whose priority
1048 * ceiling is lower than our priority, we get an error.
1050 log (" Lock with ceiling priority < thread priority - ");
1051 ret = pthread_mutex_lock (&m[0]);
1052 check_result (/* expected */ EINVAL, ret);
1054 pthread_mutex_unlock (&m[0]);
1057 * Check that we can take a mutex whose priority ceiling
1058 * is equal to our priority.
1060 log (" Lock with ceiling priority = thread priority - ");
1061 ret = pthread_mutex_lock (&m[1]);
1062 check_result (/* expected */ 0, ret);
1064 pthread_mutex_unlock (&m[1]);
1067 * Check that we can take a mutex whose priority ceiling
1068 * is higher than our priority.
1070 log (" Lock with ceiling priority > thread priority - ");
1071 ret = pthread_mutex_lock (&m[2]);
1072 check_result (/* expected */ 0, ret);
1074 pthread_mutex_unlock (&m[2]);
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).
1082 log (" Preemption with ceiling priority < thread "
1084 /* Have the test thread take mutex 0. */
1085 send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[0]);
1088 log_trace ("Sending busy command.\n");
1089 send_cmd (test_thread_id, CMD_BUSY_LOOP);
1090 log_trace ("Busy sent, yielding\n");
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");
1097 /* Let the thread finish its busy loop. */
1099 if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
1100 log_error ("test thread never finished.\n");
1104 states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
1106 /* Have the test thread release mutex 0. */
1107 send_cmd (test_thread_id, CMD_RELEASE_ALL);
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
1118 log (" Preemption with ceiling priority = thread "
1121 /* Have the test thread take mutex 1. */
1122 send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
1125 log_trace ("Sending busy\n");
1126 send_cmd (test_thread_id, CMD_BUSY_LOOP);
1127 log_trace ("Busy sent, yielding\n");
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");
1135 /* Let the thread finish its busy loop. */
1137 if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
1138 log_error ("test thread never finished.\n");
1142 states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
1144 /* Have the test thread release mutex 1. */
1145 send_cmd (test_thread_id, CMD_RELEASE_ALL);
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
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);
1162 /* Have the test thread take mutex 1. */
1163 send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
1166 log_trace ("Sending busy\n");
1167 send_cmd (test_thread_id, CMD_BUSY_LOOP);
1168 log_trace ("Busy sent, yielding\n");
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. */
1178 states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
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);
1185 /* Have the test thread release mutex 1. */
1186 send_cmd (test_thread_id, CMD_RELEASE_ALL);
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
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]);
1203 log_trace ("Sending busy\n");
1204 send_cmd (test_thread_id, CMD_BUSY_LOOP);
1205 log_trace ("Busy sent, yielding\n");
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. */
1213 else if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
1214 log_error ("test thread never finished.\n");
1217 states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
1219 /* Have the test thread release mutex 2. */
1220 send_cmd (test_thread_id, CMD_RELEASE_ALL);
1223 /* Destroy the mutexes. */
1224 for (i = 0; i < 3; i++)
1225 assert (pthread_mutex_destroy (&m[i]) == 0);
1231 mutex_prioinherit_test (void)
1233 pthread_mutexattr_t mattr;
1234 struct sched_param param;
1235 pthread_mutex_t m[3];
1237 int i, policy, my_prio;
1239 /* Get this threads current priority. */
1240 assert (pthread_getschedparam (pthread_self(), &policy,
1242 my_prio = param.sched_priority; /* save for later use */
1243 log_trace ("Current scheduling policy %d, priority %d\n",
1246 log ("Testing priority inheritence\n");
1247 log ("----------------------------\n");
1248 for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
1250 log (" Protype PTHREAD_PRIO_INHERIT, Type %s\n",
1251 mutextype_strs[mkind]);
1254 * Initialize and create a mutex.
1256 assert (pthread_mutexattr_init (&mattr) == 0);
1259 * Initialize and create 3 priority inheritence mutexes with
1260 * default (max priority) ceilings.
1262 assert (pthread_mutexattr_setprotocol(&mattr,
1263 PTHREAD_PRIO_INHERIT) == 0);
1266 * Ensure that the first mutex type is a POSIX
1269 if (mkind != M_POSIX) {
1270 assert (pthread_mutexattr_settype (&mattr,
1271 mutex_types[mkind]) == 0);
1274 for (i = 0; i < 3; i++)
1275 assert (pthread_mutex_init (&m[i], &mattr) == 0);
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.
1288 * Threads complete in order 4, 6, 5, 3, 2
1290 log (" Simple inheritence test - ");
1293 * Command thread 4 to take mutexes 0 and 1.
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]);
1301 * Tell the threads to report themselves when they are
1302 * at the bottom of their loop (waiting on wait_mutex).
1304 for (i = 0; i < NUM_THREADS; i++)
1305 states[i].flags |= FLAGS_REPORT_WAITMUTEX;
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.
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]);
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.
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);
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]);
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);
1340 check_run_order ("4,6,5,3,2");
1345 for (i = 0; i < NUM_THREADS; i++)
1346 states[i].flags = 0;
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
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).
1366 log (" Inheritence test with change of priority - ");
1369 * Change threads 2 and 4 scheduling policies to be
1372 param.sched_priority = states[2].priority;
1373 assert (pthread_setschedparam (states[2].tid, SCHED_FIFO,
1375 param.sched_priority = states[4].priority;
1376 assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
1380 * Command thread 4 to take mutex 0.
1382 send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
1386 * Command thread 2 to enter busy loop.
1388 send_cmd (2, CMD_BUSY_LOOP);
1389 sleep (1); /* Allow command to be received. */
1392 * Command thread 4 to enter busy loop.
1394 send_cmd (4, CMD_BUSY_LOOP);
1395 sleep (1); /* Allow command to be received. */
1397 /* Have threads 2 and 4 report themselves. */
1398 states[2].flags = FLAGS_REPORT_WAITMUTEX;
1399 states[4].flags = FLAGS_REPORT_WAITMUTEX;
1401 /* Change the priority of thread 4. */
1402 param.sched_priority = states[2].priority;
1403 assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
1406 check_run_order ("4,2");
1408 /* Clear the flags */
1409 states[2].flags = 0;
1410 states[4].flags = 0;
1412 /* Reset the policies. */
1413 param.sched_priority = states[2].priority;
1414 assert (pthread_setschedparam (states[2].tid, SCHED_RR,
1416 param.sched_priority = states[4].priority;
1417 assert (pthread_setschedparam (states[4].tid, SCHED_RR,
1420 send_cmd (4, CMD_RELEASE_MUTEX);
1423 /* Destroy the mutexes. */
1424 for (i = 0; i < 3; i++)
1425 assert (pthread_mutex_destroy (&m[i]) == 0);
1430 int main (int argc, char *argv[])
1432 pthread_mutexattr_t mattr;
1433 pthread_condattr_t cattr;
1434 pthread_attr_t pattr;
1435 int i, policy, main_prio;
1438 struct sigaction act;
1439 struct sched_param param;
1443 assert (pthread_getschedparam (pthread_self (), &policy, ¶m) == 0);
1444 main_prio = param.sched_priority;
1446 /* Setupt our signal mask. */
1448 sigdelset (&mask, SIGINT);
1449 sigprocmask (SIG_SETMASK, &mask, NULL);
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);
1459 * Initialize the thread attribute.
1461 assert (pthread_attr_init (&pattr) == 0);
1462 assert (pthread_attr_setdetachstate (&pattr,
1463 PTHREAD_CREATE_JOINABLE) == 0);
1466 * Initialize and create the waiter and condvar mutexes.
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);
1473 * Initialize and create a condition variable.
1475 assert (pthread_condattr_init (&cattr) == 0);
1476 assert (pthread_cond_init (&cond_var, &cattr) == 0);
1478 /* Create a pipe to catch the results of thread wakeups. */
1479 assert (pipe (pipefd) == 0);
1482 assert (pthread_switch_add_np (kern_switch) == 0);
1486 * Create the waiting threads.
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,
1500 #if defined(_LIBC_R_)
1504 snprintf (buf, sizeof(buf), "waiter_%d", i);
1505 pthread_set_name_np (states[i].tid, buf);
1510 /* Allow the threads to start. */
1512 log_trace ("Done creating threads.\n");
1517 mutex_destroy_test ();
1521 mutex_unlock_test ();
1523 queueing_order_test ();
1525 mutex_prioinherit_test ();
1527 mutex_prioceiling_test ();
1530 log ("Total tests %d, passed %d, failed %d\n",
1531 total, pass_count, error_count);
1533 /* Set the done flag and signal the threads to exit. */
1534 log_trace ("Setting done flag.\n");
1538 * Wait for the threads to finish.
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);
1546 /* Clean up after ourselves. */
1550 if (error_count != 0)
1551 exit (EX_OSERR); /* any better ideas??? */