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 $
33 * $DragonFly: src/lib/libc_r/test/mutex_d.c,v 1.3 2007/06/26 23:30:05 josepht Exp $
38 #include <sys/ioctl.h>
42 #include <sys/sched.h>
50 #include <pthread_np.h>
54 #define NELEMENTS(arr) (sizeof (arr) / sizeof (arr[0]))
58 #define NUM_THREADS 10
61 #define MAX_THREAD_CMDS 10
63 static void log_error(const char *, ...) __printflike(1, 2);
64 static void log_trace (const char *, ...) __printflike(1, 2);
65 static void log (const char *, ...) __printflike(1, 2);
67 /*------------------------------------------------------------
69 *----------------------------------------------------------*/
72 STAT_INITIAL
, /* initial state */
73 STAT_WAITCONDVAR
, /* waiting for condition variable signal */
74 STAT_WAITMUTEX
/* waiting for mutex lock */
78 FLAGS_REPORT_WAITCONDMUTEX
= 0x01,
79 FLAGS_REPORT_WAITCONDVAR
= 0x02,
80 FLAGS_REPORT_WAITMUTEX
= 0x04,
81 FLAGS_REPORT_BUSY_LOOP
= 0x08,
97 thread_cmd_id_t cmd_id
;
98 pthread_mutex_t
*mutex
;
103 pthread_cond_t cond_var
;
104 thread_status_t status
;
122 /*------------------------------------------------------------
124 *----------------------------------------------------------*/
126 const char *protocol_strs
[] = {
128 "PTHREAD_PRIO_INHERIT",
129 "PTHREAD_PRIO_PROTECT"
132 const int protocols
[] = {
134 PTHREAD_PRIO_INHERIT
,
138 const 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"
146 const int mutex_types
[] = {
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 */
155 /*------------------------------------------------------------
157 *----------------------------------------------------------*/
160 static int trace_enabled
= 0;
161 static int use_global_condvar
= 0;
162 static thread_state_t states
[NUM_THREADS
];
163 static int pipefd
[2];
165 static pthread_mutex_t waiter_mutex
;
166 static pthread_mutex_t cond_mutex
;
167 static pthread_cond_t cond_var
;
169 static FILE *logfile
;
170 static int error_count
= 0, pass_count
= 0, total
= 0;
173 /*------------------------------------------------------------
175 *----------------------------------------------------------*/
176 extern char *strtok_r(char *str
, const char *sep
, char **last
);
179 /*------------------------------------------------------------
181 *----------------------------------------------------------*/
185 kern_switch (pthread_t pthread_out
, pthread_t pthread_in
)
187 if (pthread_out
!= NULL
)
188 printf ("Swapping out thread 0x%x, ", (int) pthread_out
);
190 printf ("Swapping out kernel thread, ");
192 if (pthread_in
!= NULL
)
193 printf ("swapping in thread 0x%x\n", (int) pthread_in
);
195 printf ("swapping in kernel thread.\n");
201 log_error (const char *fmt
, ...)
206 fprintf (logfile
, "FAIL: ");
207 vfprintf (logfile
, fmt
, ap
);
208 error_count
= error_count
+ 1;
216 fprintf (logfile
, "PASS\n");
217 pass_count
= pass_count
+ 1;
223 log_trace (const char *fmt
, ...)
229 vfprintf (logfile
, fmt
, ap
);
235 log (const char *fmt
, ...)
240 vfprintf (logfile
, fmt
, ap
);
245 check_result (int expected
, int actual
)
247 if (expected
!= actual
)
248 log_error ("expected %d, returned %d\n", expected
, actual
);
255 * Check to see that the threads ran in the specified order.
258 check_run_order (char *order
)
260 const char *sep
= ":,";
261 char *tok
, *last
, *idstr
, *endptr
;
262 int expected_id
, bytes
, count
= 0, errors
= 0;
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
);
270 for (idstr
= strtok_r (tok
, sep
, &last
);
271 (idstr
!= NULL
) && (count
< bytes
);
272 idstr
= strtok_r (NULL
, sep
, &last
)) {
274 /* Get the expected id: */
275 expected_id
= (int) strtol (idstr
, &endptr
, 10);
276 assert ((endptr
!= NULL
) && (*endptr
== '\0'));
278 /* Read the actual id from the pipe: */
279 assert (read (pipefd
[0], &id
, sizeof (id
)) == sizeof (id
));
280 count
= count
+ sizeof (id
);
282 if (id
!= expected_id
) {
283 log_trace ("Thread %d ran out of order.\n", id
);
287 log_trace ("Thread %d at priority %d reporting.\n",
288 (int) id
, states
[id
].priority
);
293 /* Clear the pipe: */
294 while (count
< bytes
) {
295 read (pipefd
[0], &id
, sizeof (id
));
300 else if (bytes
< count
)
301 errors
= errors
+ count
- bytes
;
306 log_error ("%d threads ran out of order", errors
);
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
];
317 struct timeval tv1
, tv2
;
319 int i
, mutex_count
= 0;
321 statep
->status
= STAT_INITIAL
;
323 /* Block all signals except for interrupt.*/
325 sigdelset (&mask
, SIGINT
);
326 sigprocmask (SIG_BLOCK
, &mask
, NULL
);
329 /* Wait for signal from the main thread to continue. */
330 statep
->status
= STAT_WAITMUTEX
;
331 log_trace ("Thread %d: locking cond_mutex.\n",
333 pthread_mutex_lock (&cond_mutex
);
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",
341 /* Wait for a command. */
342 statep
->status
= STAT_WAITCONDVAR
;
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).
350 if (use_global_condvar
!= 0)
351 pthread_cond_wait (&cond_var
, &cond_mutex
);
353 pthread_cond_wait (&statep
->cond_var
, &cond_mutex
);
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",
361 log_trace ("Thread %d: received cond_var signal.\n",
364 /* Get a copy of the command before releasing the mutex. */
367 /* Clear the command after copying it. */
368 statep
->cmd
.cmd_id
= CMD_NONE
;
370 /* Unlock the condition variable mutex. */
371 assert (pthread_mutex_unlock (&cond_mutex
) == 0);
373 /* Peform the command.*/
374 switch (cmd
.cmd_id
) {
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;
384 held_mutex_owned
[mutex_count
] = 0;
385 log_trace ("Thread id %d unable to lock mutex, "
386 "error = %d\n", (int) statep
->id
,
391 case CMD_RELEASE_MUTEX
:
392 assert ((mutex_count
<= sizeof (held_mutex
)) &&
395 if (held_mutex_owned
[mutex_count
] != 0)
396 assert (pthread_mutex_unlock
397 (held_mutex
[mutex_count
]) == 0);
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);
407 log_trace ("Thread %d: Entering busy loop.\n",
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);
417 statep
->flags
&= ~FLAGS_IS_BUSY
;
418 statep
->flags
|= FLAGS_WAS_BUSY
;
420 /* Do we report our status? */
421 if (statep
->flags
& FLAGS_REPORT_BUSY_LOOP
)
422 write (pipefd
[1], &statep
->id
,
423 sizeof (statep
->id
));
425 log_trace ("Thread %d: Leaving busy loop.\n",
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
));
437 assert (pthread_mutex_unlock (cmd
.mutex
) == 0);
440 case CMD_RELEASE_ALL
:
441 assert ((mutex_count
<= sizeof (held_mutex
)) &&
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);
456 /* Wait for the big giant waiter lock. */
457 statep
->status
= STAT_WAITMUTEX
;
458 log_trace ("Thread %d: waiting for big giant lock.\n",
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",
465 statep
->status
= STAT_INITIAL
;
466 pthread_mutex_unlock (&waiter_mutex
);
469 log_trace ("Thread %d: Exiting thread 0x%x\n", (int) statep
->id
,
470 (int) pthread_self());
477 lock_twice (void *arg
)
479 thread_state_t
*statep
= (thread_state_t
*) arg
;
482 statep
->status
= STAT_INITIAL
;
484 /* Block all signals except for interrupt.*/
486 sigdelset (&mask
, SIGINT
);
487 sigprocmask (SIG_BLOCK
, &mask
, NULL
);
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
);
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
);
497 log_trace ("Thread %d: received cond_var signal.\n", (int) statep
->id
);
499 /* Unlock the condition variable mutex. */
500 assert (pthread_mutex_unlock (&cond_mutex
) == 0);
502 statep
->status
= STAT_WAITMUTEX
;
503 /* Lock the mutex once. */
504 assert (pthread_mutex_lock (statep
->cmd
.mutex
) == 0);
506 /* Lock it again and capture the error. */
507 statep
->ret
= pthread_mutex_lock (statep
->cmd
.mutex
);
510 assert (pthread_mutex_unlock (statep
->cmd
.mutex
) == 0);
512 /* Unlock it again if it is locked recursively. */
513 if (statep
->ret
== 0)
514 pthread_mutex_unlock (statep
->cmd
.mutex
);
516 log_trace ("Thread %d: Exiting thread 0x%x\n", (int) statep
->id
,
517 (int) pthread_self());
524 sighandler (int signo
)
526 log ("Signal handler caught signal %d, thread id 0x%x\n",
527 signo
, (int) pthread_self());
535 send_cmd (int id
, thread_cmd_id_t cmd
)
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);
550 send_mutex_cmd (int id
, thread_cmd_id_t cmd
, pthread_mutex_t
*m
)
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);
565 send_mutex_cv_cmd (int id
, thread_cmd_id_t cmd
, pthread_mutex_t
*m
,
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);
581 mutex_init_test (void)
583 pthread_mutexattr_t mattr
;
584 pthread_mutex_t mutex
;
589 * Initialize a mutex attribute.
591 * pthread_mutexattr_init not tested for: ENOMEM
593 assert (pthread_mutexattr_init (&mattr
) == 0);
596 * Initialize a mutex.
598 * pthread_mutex_init not tested for: EAGAIN ENOMEM EPERM EBUSY
600 log ("Testing pthread_mutex_init\n");
601 log ("--------------------------\n");
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);
611 * Ensure that the first mutex type is a POSIX
614 if (mkind
!= M_POSIX
) {
615 assert (pthread_mutexattr_settype (&mattr
,
616 mutex_types
[mkind
]) == 0);
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);
626 * Destroy a mutex attribute.
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
633 * pthread_mutexattr_destroy not tested for: EINVAL
635 assert (pthread_mutexattr_destroy (&mattr
) == 0);
642 mutex_destroy_test (void)
644 pthread_mutexattr_t mattr
;
645 pthread_mutex_t mutex
;
646 pthread_condattr_t cattr
;
648 pthread_attr_t pattr
;
651 thread_state_t state
;
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.
660 * pthread_mutex_destroy not tested for:
662 log ("Testing pthread_mutex_destroy\n");
663 log ("-----------------------------\n");
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. */
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);
678 * Ensure that the first mutex type is a POSIX
681 if (mkind
!= M_POSIX
) {
682 assert (pthread_mutexattr_settype (&mattr
,
683 mutex_types
[mkind
]) == 0);
686 /* Create the mutex. */
687 assert (pthread_mutex_init (&mutex
, &mattr
) == 0);
689 log (" Protocol %s, Type %s\n",
690 protocol_strs
[mproto
], mutextype_strs
[mkind
]);
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
);
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);
705 log (" Destruction of mutex locked by another "
707 assert (pthread_mutex_init (&mutex
, &mattr
) == 0);
708 send_mutex_cmd (0, CMD_TAKE_MUTEX
, &mutex
);
710 ret
= pthread_mutex_destroy (&mutex
);
711 check_result (/* expected */ EBUSY
, ret
);
712 send_cmd (0, CMD_RELEASE_ALL
);
714 assert (pthread_mutex_destroy (&mutex
) == 0);
716 log (" Destruction of mutex while being used in "
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
);
723 ret
= pthread_mutex_destroy (&mutex
);
724 check_result (/* expected */ EBUSY
, ret
);
725 pthread_cond_signal (&cv
);
727 assert (pthread_mutex_destroy (&mutex
) == 0);
734 mutex_lock_test (void)
736 pthread_mutexattr_t mattr
;
737 pthread_mutex_t mutex
;
738 pthread_attr_t pattr
;
741 thread_state_t state
;
746 * pthread_lock not tested for:
748 log ("Testing pthread_mutex_lock\n");
749 log ("--------------------------\n");
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. */
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);
764 * Ensure that the first mutex type is a POSIX
767 if (mkind
!= M_POSIX
) {
768 assert (pthread_mutexattr_settype (&mattr
,
769 mutex_types
[mkind
]) == 0);
772 /* Create the mutex. */
773 assert (pthread_mutex_init (&mutex
, &mattr
) == 0);
775 log (" Protocol %s, Type %s\n",
776 protocol_strs
[mproto
], mutextype_strs
[mkind
]);
778 log (" Lock on unlocked mutex - ");
779 ret
= pthread_mutex_lock (&mutex
);
780 check_result (/* expected */ 0, ret
);
781 pthread_mutex_unlock (&mutex
);
783 log (" Lock on invalid mutex - ");
784 ret
= pthread_mutex_lock (NULL
);
785 check_result (/* expected */ EINVAL
, ret
);
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. */
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. */
802 check_result (/* expected */ EDEADLK
,
806 check_result (/* expected */ EDEADLK
,
809 case M_SS2_ERRORCHECK
:
810 check_result (/* expected */ EDEADLK
,
814 check_result (/* expected */ 0xdeadbeef,
817 case M_SS2_RECURSIVE
:
818 check_result (/* expected */ 0, state
.ret
);
821 pthread_mutex_destroy (&mutex
);
822 pthread_mutexattr_destroy (&mattr
);
829 mutex_unlock_test (void)
831 const int test_thread_id
= 0; /* ID of test thread */
832 pthread_mutexattr_t mattr
;
833 pthread_mutex_t mutex
;
840 * pthread_unlock not tested for:
842 log ("Testing pthread_mutex_unlock\n");
843 log ("----------------------------\n");
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);
853 * Ensure that the first mutex type is a POSIX
856 if (mkind
!= M_POSIX
) {
857 assert (pthread_mutexattr_settype (&mattr
,
858 mutex_types
[mkind
]) == 0);
861 /* Create the mutex. */
862 assert (pthread_mutex_init (&mutex
, &mattr
) == 0);
864 log (" Protocol %s, Type %s\n",
865 protocol_strs
[mproto
], mutextype_strs
[mkind
]);
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
);
872 log (" Unlock on invalid mutex - ");
873 ret
= pthread_mutex_unlock (NULL
);
874 check_result (/* expected */ EINVAL
, ret
);
876 log (" Unlock on mutex locked by another thread - ");
877 send_mutex_cmd (test_thread_id
, CMD_TAKE_MUTEX
, &mutex
);
879 ret
= pthread_mutex_unlock (&mutex
);
882 check_result (/* expected */ EPERM
, ret
);
885 check_result (/* expected */ EPERM
, ret
);
887 case M_SS2_ERRORCHECK
:
888 check_result (/* expected */ EPERM
, ret
);
891 check_result (/* expected */ EPERM
, ret
);
893 case M_SS2_RECURSIVE
:
894 check_result (/* expected */ EPERM
, ret
);
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.
903 pthread_mutex_lock (&mutex
);
905 send_cmd (test_thread_id
, CMD_RELEASE_ALL
);
908 pthread_mutex_destroy (&mutex
);
909 pthread_mutexattr_destroy (&mattr
);
916 queueing_order_test (void)
920 log ("Testing queueing order\n");
921 log ("----------------------\n");
922 assert (pthread_mutex_lock (&waiter_mutex
) == 0);
924 * Tell the threads to report when they take the waiters mutex.
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);
931 assert (pthread_mutex_unlock (&cond_mutex
) == 0);
933 /* Signal the threads to continue. */
936 /* Use the global condition variable next time. */
937 use_global_condvar
= 1;
939 /* Release the waiting threads and allow them to run again. */
940 assert (pthread_mutex_unlock (&waiter_mutex
) == 0);
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
;
951 * Prevent the threads from continuing their loop after we
954 assert (pthread_mutex_lock (&waiter_mutex
) == 0);
957 log (" Queueing order on a condition variable - ");
959 * Signal one thread to run and see that the highest priority
962 assert (pthread_mutex_lock (&cond_mutex
) == 0);
963 assert (pthread_cond_signal (&cond_var
) == 0);
964 assert (pthread_mutex_unlock (&cond_mutex
) == 0);
966 if (states
[NUM_THREADS
- 1].status
!= STAT_WAITMUTEX
)
967 log_error ("highest priority thread does not run.\n");
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);
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. */
981 /* Use the thread unique condition variable next time. */
982 use_global_condvar
= 0;
984 /* Allow the threads to continue their loop. */
985 assert (pthread_mutex_unlock (&waiter_mutex
) == 0);
991 mutex_prioceiling_test (void)
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];
998 int i
, ret
, policy
, my_prio
, old_ceiling
;
1000 log ("Testing priority ceilings\n");
1001 log ("-------------------------\n");
1002 for (mkind
= M_POSIX
; mkind
<= M_SS2_RECURSIVE
; mkind
++) {
1004 log (" Protype PTHREAD_PRIO_PROTECT, Type %s\n",
1005 mutextype_strs
[mkind
]);
1008 * Initialize and create a mutex.
1010 assert (pthread_mutexattr_init (&mattr
) == 0);
1012 /* Get this threads current priority. */
1013 assert (pthread_getschedparam (pthread_self(), &policy
,
1015 my_prio
= param
.sched_priority
; /* save for later use */
1016 log_trace ("Current scheduling policy %d, priority %d\n",
1020 * Initialize and create 3 priority protection mutexes with
1021 * default (max priority) ceilings.
1023 assert (pthread_mutexattr_setprotocol(&mattr
,
1024 PTHREAD_PRIO_PROTECT
) == 0);
1027 * Ensure that the first mutex type is a POSIX
1030 if (mkind
!= M_POSIX
) {
1031 assert (pthread_mutexattr_settype (&mattr
,
1032 mutex_types
[mkind
]) == 0);
1035 for (i
= 0; i
< 3; i
++)
1036 assert (pthread_mutex_init (&m
[i
], &mattr
) == 0);
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.
1043 for (i
= 0; i
< 3; i
++)
1044 assert (pthread_mutex_setprioceiling (&m
[i
],
1045 my_prio
- 5 + 5*i
, &old_ceiling
) == 0);
1048 * Check that if we attempt to take a mutex whose priority
1049 * ceiling is lower than our priority, we get an error.
1051 log (" Lock with ceiling priority < thread priority - ");
1052 ret
= pthread_mutex_lock (&m
[0]);
1053 check_result (/* expected */ EINVAL
, ret
);
1055 pthread_mutex_unlock (&m
[0]);
1058 * Check that we can take a mutex whose priority ceiling
1059 * is equal to our priority.
1061 log (" Lock with ceiling priority = thread priority - ");
1062 ret
= pthread_mutex_lock (&m
[1]);
1063 check_result (/* expected */ 0, ret
);
1065 pthread_mutex_unlock (&m
[1]);
1068 * Check that we can take a mutex whose priority ceiling
1069 * is higher than our priority.
1071 log (" Lock with ceiling priority > thread priority - ");
1072 ret
= pthread_mutex_lock (&m
[2]);
1073 check_result (/* expected */ 0, ret
);
1075 pthread_mutex_unlock (&m
[2]);
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).
1083 log (" Preemption with ceiling priority < thread "
1085 /* Have the test thread take mutex 0. */
1086 send_mutex_cmd (test_thread_id
, CMD_TAKE_MUTEX
, &m
[0]);
1089 log_trace ("Sending busy command.\n");
1090 send_cmd (test_thread_id
, CMD_BUSY_LOOP
);
1091 log_trace ("Busy sent, yielding\n");
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");
1098 /* Let the thread finish its busy loop. */
1100 if ((states
[test_thread_id
].flags
& FLAGS_WAS_BUSY
) == 0)
1101 log_error ("test thread never finished.\n");
1105 states
[test_thread_id
].flags
&= ~FLAGS_WAS_BUSY
;
1107 /* Have the test thread release mutex 0. */
1108 send_cmd (test_thread_id
, CMD_RELEASE_ALL
);
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
1119 log (" Preemption with ceiling priority = thread "
1122 /* Have the test thread take mutex 1. */
1123 send_mutex_cmd (test_thread_id
, CMD_TAKE_MUTEX
, &m
[1]);
1126 log_trace ("Sending busy\n");
1127 send_cmd (test_thread_id
, CMD_BUSY_LOOP
);
1128 log_trace ("Busy sent, yielding\n");
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");
1136 /* Let the thread finish its busy loop. */
1138 if ((states
[test_thread_id
].flags
& FLAGS_WAS_BUSY
) == 0)
1139 log_error ("test thread never finished.\n");
1143 states
[test_thread_id
].flags
&= ~FLAGS_WAS_BUSY
;
1145 /* Have the test thread release mutex 1. */
1146 send_cmd (test_thread_id
, CMD_RELEASE_ALL
);
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
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);
1163 /* Have the test thread take mutex 1. */
1164 send_mutex_cmd (test_thread_id
, CMD_TAKE_MUTEX
, &m
[1]);
1167 log_trace ("Sending busy\n");
1168 send_cmd (test_thread_id
, CMD_BUSY_LOOP
);
1169 log_trace ("Busy sent, yielding\n");
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. */
1179 states
[test_thread_id
].flags
&= ~FLAGS_WAS_BUSY
;
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);
1186 /* Have the test thread release mutex 1. */
1187 send_cmd (test_thread_id
, CMD_RELEASE_ALL
);
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
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]);
1204 log_trace ("Sending busy\n");
1205 send_cmd (test_thread_id
, CMD_BUSY_LOOP
);
1206 log_trace ("Busy sent, yielding\n");
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. */
1214 else if ((states
[test_thread_id
].flags
& FLAGS_WAS_BUSY
) == 0)
1215 log_error ("test thread never finished.\n");
1218 states
[test_thread_id
].flags
&= ~FLAGS_WAS_BUSY
;
1220 /* Have the test thread release mutex 2. */
1221 send_cmd (test_thread_id
, CMD_RELEASE_ALL
);
1224 /* Destroy the mutexes. */
1225 for (i
= 0; i
< 3; i
++)
1226 assert (pthread_mutex_destroy (&m
[i
]) == 0);
1232 mutex_prioinherit_test (void)
1234 pthread_mutexattr_t mattr
;
1235 struct sched_param param
;
1236 pthread_mutex_t m
[3];
1238 int i
, policy
, my_prio
;
1240 /* Get this threads current priority. */
1241 assert (pthread_getschedparam (pthread_self(), &policy
,
1243 my_prio
= param
.sched_priority
; /* save for later use */
1244 log_trace ("Current scheduling policy %d, priority %d\n",
1247 log ("Testing priority inheritence\n");
1248 log ("----------------------------\n");
1249 for (mkind
= M_POSIX
; mkind
<= M_SS2_RECURSIVE
; mkind
++) {
1251 log (" Protype PTHREAD_PRIO_INHERIT, Type %s\n",
1252 mutextype_strs
[mkind
]);
1255 * Initialize and create a mutex.
1257 assert (pthread_mutexattr_init (&mattr
) == 0);
1260 * Initialize and create 3 priority inheritence mutexes with
1261 * default (max priority) ceilings.
1263 assert (pthread_mutexattr_setprotocol(&mattr
,
1264 PTHREAD_PRIO_INHERIT
) == 0);
1267 * Ensure that the first mutex type is a POSIX
1270 if (mkind
!= M_POSIX
) {
1271 assert (pthread_mutexattr_settype (&mattr
,
1272 mutex_types
[mkind
]) == 0);
1275 for (i
= 0; i
< 3; i
++)
1276 assert (pthread_mutex_init (&m
[i
], &mattr
) == 0);
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.
1289 * Threads complete in order 4, 6, 5, 3, 2
1291 log (" Simple inheritence test - ");
1294 * Command thread 4 to take mutexes 0 and 1.
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]);
1302 * Tell the threads to report themselves when they are
1303 * at the bottom of their loop (waiting on wait_mutex).
1305 for (i
= 0; i
< NUM_THREADS
; i
++)
1306 states
[i
].flags
|= FLAGS_REPORT_WAITMUTEX
;
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.
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]);
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.
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
);
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]);
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
);
1341 check_run_order ("4,6,5,3,2");
1346 for (i
= 0; i
< NUM_THREADS
; i
++)
1347 states
[i
].flags
= 0;
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
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).
1367 log (" Inheritence test with change of priority - ");
1370 * Change threads 2 and 4 scheduling policies to be
1373 param
.sched_priority
= states
[2].priority
;
1374 assert (pthread_setschedparam (states
[2].tid
, SCHED_FIFO
,
1376 param
.sched_priority
= states
[4].priority
;
1377 assert (pthread_setschedparam (states
[4].tid
, SCHED_FIFO
,
1381 * Command thread 4 to take mutex 0.
1383 send_mutex_cmd (4, CMD_TAKE_MUTEX
, &m
[0]);
1387 * Command thread 2 to enter busy loop.
1389 send_cmd (2, CMD_BUSY_LOOP
);
1390 sleep (1); /* Allow command to be received. */
1393 * Command thread 4 to enter busy loop.
1395 send_cmd (4, CMD_BUSY_LOOP
);
1396 sleep (1); /* Allow command to be received. */
1398 /* Have threads 2 and 4 report themselves. */
1399 states
[2].flags
= FLAGS_REPORT_WAITMUTEX
;
1400 states
[4].flags
= FLAGS_REPORT_WAITMUTEX
;
1402 /* Change the priority of thread 4. */
1403 param
.sched_priority
= states
[2].priority
;
1404 assert (pthread_setschedparam (states
[4].tid
, SCHED_FIFO
,
1407 check_run_order ("4,2");
1409 /* Clear the flags */
1410 states
[2].flags
= 0;
1411 states
[4].flags
= 0;
1413 /* Reset the policies. */
1414 param
.sched_priority
= states
[2].priority
;
1415 assert (pthread_setschedparam (states
[2].tid
, SCHED_RR
,
1417 param
.sched_priority
= states
[4].priority
;
1418 assert (pthread_setschedparam (states
[4].tid
, SCHED_RR
,
1421 send_cmd (4, CMD_RELEASE_MUTEX
);
1424 /* Destroy the mutexes. */
1425 for (i
= 0; i
< 3; i
++)
1426 assert (pthread_mutex_destroy (&m
[i
]) == 0);
1431 int main (int argc
, char *argv
[])
1433 pthread_mutexattr_t mattr
;
1434 pthread_condattr_t cattr
;
1435 pthread_attr_t pattr
;
1436 int i
, policy
, main_prio
;
1439 struct sigaction act
;
1440 struct sched_param param
;
1444 assert (pthread_getschedparam (pthread_self (), &policy
, ¶m
) == 0);
1445 main_prio
= param
.sched_priority
;
1447 /* Setupt our signal mask. */
1449 sigdelset (&mask
, SIGINT
);
1450 sigprocmask (SIG_SETMASK
, &mask
, NULL
);
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
);
1460 * Initialize the thread attribute.
1462 assert (pthread_attr_init (&pattr
) == 0);
1463 assert (pthread_attr_setdetachstate (&pattr
,
1464 PTHREAD_CREATE_JOINABLE
) == 0);
1467 * Initialize and create the waiter and condvar mutexes.
1469 assert (pthread_mutexattr_init (&mattr
) == 0);
1470 assert (pthread_mutex_init (&waiter_mutex
, &mattr
) == 0);
1471 assert (pthread_mutex_init (&cond_mutex
, &mattr
) == 0);
1474 * Initialize and create a condition variable.
1476 assert (pthread_condattr_init (&cattr
) == 0);
1477 assert (pthread_cond_init (&cond_var
, &cattr
) == 0);
1479 /* Create a pipe to catch the results of thread wakeups. */
1480 assert (pipe (pipefd
) == 0);
1483 assert (pthread_switch_add_np (kern_switch
) == 0);
1487 * Create the waiting threads.
1489 for (i
= 0; i
< NUM_THREADS
; i
++) {
1490 assert (pthread_cond_init (&states
[i
].cond_var
, &cattr
) == 0);
1491 states
[i
].id
= (u_int8_t
) i
; /* NUM_THREADS must be <= 256 */
1492 states
[i
].status
= 0;
1493 states
[i
].cmd
.cmd_id
= CMD_NONE
;
1494 states
[i
].flags
= 0; /* No flags yet. */
1495 assert (pthread_create (&states
[i
].tid
, &pattr
, waiter
,
1496 (void *) &states
[i
]) == 0);
1497 param
.sched_priority
= main_prio
- 10 + i
;
1498 states
[i
].priority
= param
.sched_priority
;
1499 assert (pthread_setschedparam (states
[i
].tid
, SCHED_OTHER
,
1501 #if defined(_LIBC_R_)
1505 snprintf (buf
, sizeof(buf
), "waiter_%d", i
);
1506 pthread_set_name_np (states
[i
].tid
, buf
);
1511 /* Allow the threads to start. */
1513 log_trace ("Done creating threads.\n");
1518 mutex_destroy_test ();
1522 mutex_unlock_test ();
1524 queueing_order_test ();
1526 mutex_prioinherit_test ();
1528 mutex_prioceiling_test ();
1531 log ("Total tests %d, passed %d, failed %d\n",
1532 total
, pass_count
, error_count
);
1534 /* Set the done flag and signal the threads to exit. */
1535 log_trace ("Setting done flag.\n");
1539 * Wait for the threads to finish.
1541 log_trace ("Trying to join threads.\n");
1542 for (i
= 0; i
< NUM_THREADS
; i
++) {
1543 send_cmd (i
, CMD_NONE
);
1544 assert (pthread_join (states
[i
].tid
, &exit_status
) == 0);
1547 /* Clean up after ourselves. */
1551 if (error_count
!= 0)
1552 exit (EX_OSERR
); /* any better ideas??? */