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>
41 #include <pthread_np.h>
42 #include <sys/sched.h>
51 #define NELEMENTS(arr) (sizeof (arr) / sizeof (arr[0]))
55 #define NUM_THREADS 10
58 #define MAX_THREAD_CMDS 10
60 static void log_error(const char *, ...) __printflike(1, 2);
61 static void log_trace (const char *, ...) __printflike(1, 2);
62 static void log_info (const char *, ...) __printflike(1, 2);
64 /*------------------------------------------------------------
66 *----------------------------------------------------------*/
69 STAT_INITIAL
, /* initial state */
70 STAT_WAITCONDVAR
, /* waiting for condition variable signal */
71 STAT_WAITMUTEX
/* waiting for mutex lock */
75 FLAGS_REPORT_WAITCONDMUTEX
= 0x01,
76 FLAGS_REPORT_WAITCONDVAR
= 0x02,
77 FLAGS_REPORT_WAITMUTEX
= 0x04,
78 FLAGS_REPORT_BUSY_LOOP
= 0x08,
94 thread_cmd_id_t cmd_id
;
95 pthread_mutex_t
*mutex
;
100 pthread_cond_t cond_var
;
101 thread_status_t status
;
119 /*------------------------------------------------------------
121 *----------------------------------------------------------*/
123 const char *protocol_strs
[] = {
125 "PTHREAD_PRIO_INHERIT",
126 "PTHREAD_PRIO_PROTECT"
129 const int protocols
[] = {
131 PTHREAD_PRIO_INHERIT
,
135 const char *mutextype_strs
[] = {
136 "POSIX (type not specified)",
137 "SS2 PTHREAD_MUTEX_DEFAULT",
138 "SS2 PTHREAD_MUTEX_ERRORCHECK",
139 "SS2 PTHREAD_MUTEX_NORMAL",
140 "SS2 PTHREAD_MUTEX_RECURSIVE"
143 const int mutex_types
[] = {
145 PTHREAD_MUTEX_DEFAULT
, /* M_SS2_DEFAULT */
146 PTHREAD_MUTEX_ERRORCHECK
, /* M_SS2_ERRORCHECK */
147 PTHREAD_MUTEX_NORMAL
, /* M_SS2_NORMAL */
148 PTHREAD_MUTEX_RECURSIVE
/* M_SS2_RECURSIVE */
152 /*------------------------------------------------------------
154 *----------------------------------------------------------*/
157 static int trace_enabled
= 0;
158 static int use_global_condvar
= 0;
159 static thread_state_t states
[NUM_THREADS
];
160 static int pipefd
[2];
162 static pthread_mutex_t waiter_mutex
;
163 static pthread_mutex_t cond_mutex
;
164 static pthread_cond_t cond_var
;
166 static FILE *logfile
;
167 static int error_count
= 0, pass_count
= 0, total
= 0;
170 /*------------------------------------------------------------
172 *----------------------------------------------------------*/
173 extern char *strtok_r(char *str
, const char *sep
, char **last
);
176 /*------------------------------------------------------------
178 *----------------------------------------------------------*/
182 kern_switch (pthread_t pthread_out
, pthread_t pthread_in
)
184 if (pthread_out
!= NULL
)
185 printf ("Swapping out thread 0x%x, ", (int) pthread_out
);
187 printf ("Swapping out kernel thread, ");
189 if (pthread_in
!= NULL
)
190 printf ("swapping in thread 0x%x\n", (int) pthread_in
);
192 printf ("swapping in kernel thread.\n");
198 log_error (const char *fmt
, ...)
203 fprintf (logfile
, "FAIL: ");
204 vfprintf (logfile
, fmt
, ap
);
205 error_count
= error_count
+ 1;
213 fprintf (logfile
, "PASS\n");
214 pass_count
= pass_count
+ 1;
220 log_trace (const char *fmt
, ...)
226 vfprintf (logfile
, fmt
, ap
);
232 log_info (const char *fmt
, ...)
237 vfprintf (logfile
, fmt
, ap
);
242 check_result (int expected
, int actual
)
244 if (expected
!= actual
)
245 log_error ("expected %d, returned %d\n", expected
, actual
);
252 * Check to see that the threads ran in the specified order.
255 check_run_order (char *order
)
257 const char *sep
= ":,";
258 char *tok
, *last
, *idstr
, *endptr
;
259 int expected_id
, bytes
, count
= 0, errors
= 0;
262 assert ((tok
= (char *) malloc (strlen(order
) + 1)) != NULL
);
263 strcpy (tok
, order
); /* tok has to be larger than order */
264 assert (ioctl (pipefd
[0], FIONREAD
, &bytes
) == 0);
265 log_trace ("%d bytes read from FIFO.\n", bytes
);
267 for (idstr
= strtok_r (tok
, sep
, &last
);
268 (idstr
!= NULL
) && (count
< bytes
);
269 idstr
= strtok_r (NULL
, sep
, &last
)) {
271 /* Get the expected id: */
272 expected_id
= (int) strtol (idstr
, &endptr
, 10);
273 assert ((endptr
!= NULL
) && (*endptr
== '\0'));
275 /* Read the actual id from the pipe: */
276 assert (read (pipefd
[0], &id
, sizeof (id
)) == sizeof (id
));
277 count
= count
+ sizeof (id
);
279 if (id
!= expected_id
) {
280 log_trace ("Thread %d ran out of order.\n", id
);
284 log_trace ("Thread %d at priority %d reporting.\n",
285 (int) id
, states
[id
].priority
);
290 /* Clear the pipe: */
291 while (count
< bytes
) {
292 read (pipefd
[0], &id
, sizeof (id
));
297 else if (bytes
< count
)
298 errors
= errors
+ count
- bytes
;
303 log_error ("%d threads ran out of order\n", errors
);
310 thread_state_t
*statep
= (thread_state_t
*) arg
;
311 pthread_mutex_t
*held_mutex
[MAX_THREAD_CMDS
];
312 int held_mutex_owned
[MAX_THREAD_CMDS
];
314 struct timeval tv1
, tv2
;
316 int i
, mutex_count
= 0;
318 statep
->status
= STAT_INITIAL
;
320 /* Block all signals except for interrupt.*/
322 sigdelset (&mask
, SIGINT
);
323 sigprocmask (SIG_BLOCK
, &mask
, NULL
);
326 /* Wait for signal from the main thread to continue. */
327 statep
->status
= STAT_WAITMUTEX
;
328 log_trace ("Thread %d: locking cond_mutex.\n",
330 pthread_mutex_lock (&cond_mutex
);
332 /* Do we report our status. */
333 if (statep
->flags
& FLAGS_REPORT_WAITCONDMUTEX
)
334 write (pipefd
[1], &statep
->id
, sizeof (statep
->id
));
335 log_trace ("Thread %d: waiting for cond_var.\n",
338 /* Wait for a command. */
339 statep
->status
= STAT_WAITCONDVAR
;
342 * The threads are allowed commanded to wait either on
343 * their own unique condition variable (so they may be
344 * separately signaled) or on one global condition variable
345 * (so they may be signaled together).
347 if (use_global_condvar
!= 0)
348 pthread_cond_wait (&cond_var
, &cond_mutex
);
350 pthread_cond_wait (&statep
->cond_var
, &cond_mutex
);
352 /* Do we report our status? */
353 if (statep
->flags
& FLAGS_REPORT_WAITCONDVAR
) {
354 write (pipefd
[1], &statep
->id
, sizeof (statep
->id
));
355 log_trace ("Thread %d: wrote to pipe.\n",
358 log_trace ("Thread %d: received cond_var signal.\n",
361 /* Get a copy of the command before releasing the mutex. */
364 /* Clear the command after copying it. */
365 statep
->cmd
.cmd_id
= CMD_NONE
;
367 /* Unlock the condition variable mutex. */
368 assert (pthread_mutex_unlock (&cond_mutex
) == 0);
370 /* Peform the command.*/
371 switch (cmd
.cmd_id
) {
373 statep
->ret
= pthread_mutex_lock (cmd
.mutex
);
374 if (statep
->ret
== 0) {
375 assert (mutex_count
< sizeof (held_mutex
));
376 held_mutex
[mutex_count
] = cmd
.mutex
;
377 held_mutex_owned
[mutex_count
] = 1;
381 held_mutex_owned
[mutex_count
] = 0;
382 log_trace ("Thread id %d unable to lock mutex, "
383 "error = %d\n", (int) statep
->id
,
388 case CMD_RELEASE_MUTEX
:
389 assert ((mutex_count
<= sizeof (held_mutex
)) &&
392 if (held_mutex_owned
[mutex_count
] != 0)
393 assert (pthread_mutex_unlock
394 (held_mutex
[mutex_count
]) == 0);
397 case CMD_WAIT_FOR_SIGNAL
:
398 assert (pthread_mutex_lock (cmd
.mutex
) == 0);
399 assert (pthread_cond_wait (cmd
.cond
, cmd
.mutex
) == 0);
400 assert (pthread_mutex_unlock (cmd
.mutex
) == 0);
404 log_trace ("Thread %d: Entering busy loop.\n",
406 /* Spin for 15 seconds. */
407 assert (gettimeofday (&tv2
, NULL
) == 0);
408 tv1
.tv_sec
= tv2
.tv_sec
+ 5;
409 tv1
.tv_usec
= tv2
.tv_usec
;
410 statep
->flags
|= FLAGS_IS_BUSY
;
411 while (timercmp (&tv2
, &tv1
,<)) {
412 assert (gettimeofday (&tv2
, NULL
) == 0);
414 statep
->flags
&= ~FLAGS_IS_BUSY
;
415 statep
->flags
|= FLAGS_WAS_BUSY
;
417 /* Do we report our status? */
418 if (statep
->flags
& FLAGS_REPORT_BUSY_LOOP
)
419 write (pipefd
[1], &statep
->id
,
420 sizeof (statep
->id
));
422 log_trace ("Thread %d: Leaving busy loop.\n",
426 case CMD_PROTECTED_OP
:
427 assert (pthread_mutex_lock (cmd
.mutex
) == 0);
428 statep
->flags
|= FLAGS_WAS_BUSY
;
429 /* Do we report our status? */
430 if (statep
->flags
& FLAGS_REPORT_BUSY_LOOP
)
431 write (pipefd
[1], &statep
->id
,
432 sizeof (statep
->id
));
434 assert (pthread_mutex_unlock (cmd
.mutex
) == 0);
437 case CMD_RELEASE_ALL
:
438 assert ((mutex_count
<= sizeof (held_mutex
)) &&
440 for (i
= mutex_count
- 1; i
>= 0; i
--) {
441 if (held_mutex_owned
[i
] != 0)
442 assert (pthread_mutex_unlock
443 (held_mutex
[i
]) == 0);
453 /* Wait for the big giant waiter lock. */
454 statep
->status
= STAT_WAITMUTEX
;
455 log_trace ("Thread %d: waiting for big giant lock.\n",
457 pthread_mutex_lock (&waiter_mutex
);
458 if (statep
->flags
& FLAGS_REPORT_WAITMUTEX
)
459 write (pipefd
[1], &statep
->id
, sizeof (statep
->id
));
460 log_trace ("Thread %d: got big giant lock.\n",
462 statep
->status
= STAT_INITIAL
;
463 pthread_mutex_unlock (&waiter_mutex
);
466 log_trace ("Thread %d: Exiting thread 0x%p\n", (int) statep
->id
,
474 lock_twice (void *arg
)
476 thread_state_t
*statep
= (thread_state_t
*) arg
;
479 statep
->status
= STAT_INITIAL
;
481 /* Block all signals except for interrupt.*/
483 sigdelset (&mask
, SIGINT
);
484 sigprocmask (SIG_BLOCK
, &mask
, NULL
);
486 /* Wait for a signal to continue. */
487 log_trace ("Thread %d: locking cond_mutex.\n", (int) statep
->id
);
488 pthread_mutex_lock (&cond_mutex
);
490 log_trace ("Thread %d: waiting for cond_var.\n", (int) statep
->id
);
491 statep
->status
= STAT_WAITCONDVAR
;
492 pthread_cond_wait (&cond_var
, &cond_mutex
);
494 log_trace ("Thread %d: received cond_var signal.\n", (int) statep
->id
);
496 /* Unlock the condition variable mutex. */
497 assert (pthread_mutex_unlock (&cond_mutex
) == 0);
499 statep
->status
= STAT_WAITMUTEX
;
500 /* Lock the mutex once. */
501 assert (pthread_mutex_lock (statep
->cmd
.mutex
) == 0);
503 /* Lock it again and capture the error. */
504 statep
->ret
= pthread_mutex_lock (statep
->cmd
.mutex
);
507 assert (pthread_mutex_unlock (statep
->cmd
.mutex
) == 0);
509 /* Unlock it again if it is locked recursively. */
510 if (statep
->ret
== 0)
511 pthread_mutex_unlock (statep
->cmd
.mutex
);
513 log_trace ("Thread %d: Exiting thread 0x%p\n", (int) statep
->id
,
521 sighandler (int signo
)
523 log_info ("Signal handler caught signal %d, thread id 0x%p\n",
524 signo
, pthread_self());
532 send_cmd (int id
, thread_cmd_id_t cmd
)
534 assert (pthread_mutex_lock (&cond_mutex
) == 0);
535 assert (states
[id
].status
== STAT_WAITCONDVAR
);
536 states
[id
].cmd
.cmd_id
= cmd
;
537 states
[id
].cmd
.mutex
= NULL
;
538 states
[id
].cmd
.cond
= NULL
;
539 /* Clear the busy flags. */
540 states
[id
].flags
&= ~(FLAGS_WAS_BUSY
| FLAGS_IS_BUSY
);
541 assert (pthread_cond_signal (&states
[id
].cond_var
) == 0);
542 assert (pthread_mutex_unlock (&cond_mutex
) == 0);
547 send_mutex_cmd (int id
, thread_cmd_id_t cmd
, pthread_mutex_t
*m
)
549 assert (pthread_mutex_lock (&cond_mutex
) == 0);
550 assert (states
[id
].status
== STAT_WAITCONDVAR
);
551 states
[id
].cmd
.cmd_id
= cmd
;
552 states
[id
].cmd
.mutex
= m
;
553 states
[id
].cmd
.cond
= NULL
;
554 /* Clear the busy flags. */
555 states
[id
].flags
&= ~(FLAGS_WAS_BUSY
| FLAGS_IS_BUSY
);
556 assert (pthread_cond_signal (&states
[id
].cond_var
) == 0);
557 assert (pthread_mutex_unlock (&cond_mutex
) == 0);
562 send_mutex_cv_cmd (int id
, thread_cmd_id_t cmd
, pthread_mutex_t
*m
,
565 assert (pthread_mutex_lock (&cond_mutex
) == 0);
566 assert (states
[id
].status
== STAT_WAITCONDVAR
);
567 states
[id
].cmd
.cmd_id
= cmd
;
568 states
[id
].cmd
.mutex
= m
;
569 states
[id
].cmd
.cond
= cv
;
570 /* Clear the busy flags. */
571 states
[id
].flags
&= ~(FLAGS_WAS_BUSY
| FLAGS_IS_BUSY
);
572 assert (pthread_cond_signal (&states
[id
].cond_var
) == 0);
573 assert (pthread_mutex_unlock (&cond_mutex
) == 0);
578 mutex_init_test (void)
580 pthread_mutexattr_t mattr
;
581 pthread_mutex_t mutex
;
586 * Initialize a mutex attribute.
588 * pthread_mutexattr_init not tested for: ENOMEM
590 assert (pthread_mutexattr_init (&mattr
) == 0);
593 * Initialize a mutex.
595 * pthread_mutex_init not tested for: EAGAIN ENOMEM EPERM EBUSY
597 log_info ("Testing pthread_mutex_init\n");
598 log_info ("--------------------------\n");
600 for (mproto
= 0; mproto
< NELEMENTS(protocols
); mproto
++) {
601 for (mkind
= M_POSIX
; mkind
<= M_SS2_RECURSIVE
; mkind
++) {
602 /* Initialize the mutex attribute. */
603 assert (pthread_mutexattr_init (&mattr
) == 0);
604 assert (pthread_mutexattr_setprotocol (&mattr
,
605 protocols
[mproto
]) == 0);
608 * Ensure that the first mutex type is a POSIX
611 if (mkind
!= M_POSIX
) {
612 assert (pthread_mutexattr_settype (&mattr
,
613 mutex_types
[mkind
]) == 0);
616 log_info (" Protocol %s, Type %s - ",
617 protocol_strs
[mproto
], mutextype_strs
[mkind
]);
618 ret
= pthread_mutex_init (&mutex
, &mattr
);
619 check_result (/* expected */ 0, ret
);
620 assert (pthread_mutex_destroy (&mutex
) == 0);
623 * Destroy a mutex attribute.
625 * XXX - There should probably be a magic number
626 * associated with a mutex attribute so that
627 * destroy can be reasonably sure the attribute
630 * pthread_mutexattr_destroy not tested for: EINVAL
632 assert (pthread_mutexattr_destroy (&mattr
) == 0);
639 mutex_destroy_test (void)
641 pthread_mutexattr_t mattr
;
642 pthread_mutex_t mutex
;
643 pthread_condattr_t cattr
;
645 pthread_attr_t pattr
;
649 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_info ("Testing pthread_mutex_destroy\n");
662 log_info ("-----------------------------\n");
664 assert (pthread_attr_init (&pattr
) == 0);
665 assert (pthread_attr_setdetachstate (&pattr
,
666 PTHREAD_CREATE_DETACHED
) == 0);
668 state
.flags
= 0; /* No flags yet. */
671 for (mproto
= 0; mproto
< NELEMENTS(protocols
); mproto
++) {
672 for (mkind
= M_POSIX
; mkind
<= M_SS2_RECURSIVE
; mkind
++) {
673 /* Initialize the mutex attribute. */
674 assert (pthread_mutexattr_init (&mattr
) == 0);
675 assert (pthread_mutexattr_setprotocol (&mattr
,
676 protocols
[mproto
]) == 0);
679 * Ensure that the first mutex type is a POSIX
682 if (mkind
!= M_POSIX
) {
683 assert (pthread_mutexattr_settype (&mattr
,
684 mutex_types
[mkind
]) == 0);
687 /* Create the mutex. */
688 assert (pthread_mutex_init (&mutex
, &mattr
) == 0);
690 log_info (" Protocol %s, Type %s\n",
691 protocol_strs
[mproto
], mutextype_strs
[mkind
]);
693 log_info (" Destruction of unused mutex - ");
694 assert (pthread_mutex_init (&mutex
, &mattr
) == 0);
695 ret
= pthread_mutex_destroy (&mutex
);
696 check_result (/* expected */ 0, ret
);
698 log_info (" Destruction of mutex locked by self - ");
699 assert (pthread_mutex_init (&mutex
, &mattr
) == 0);
700 assert (pthread_mutex_lock (&mutex
) == 0);
701 ret
= pthread_mutex_destroy (&mutex
);
702 check_result (/* expected */ EBUSY
, ret
);
703 assert (pthread_mutex_unlock (&mutex
) == 0);
704 assert (pthread_mutex_destroy (&mutex
) == 0);
706 log_info (" Destruction of mutex locked by another "
708 assert (pthread_mutex_init (&mutex
, &mattr
) == 0);
709 send_mutex_cmd (0, CMD_TAKE_MUTEX
, &mutex
);
711 ret
= pthread_mutex_destroy (&mutex
);
712 check_result (/* expected */ EBUSY
, ret
);
713 send_cmd (0, CMD_RELEASE_ALL
);
715 assert (pthread_mutex_destroy (&mutex
) == 0);
717 log_info (" Destruction of mutex while being used in "
719 assert (pthread_mutex_init (&mutex
, &mattr
) == 0);
720 assert (pthread_condattr_init (&cattr
) == 0);
721 assert (pthread_cond_init (&cv
, &cattr
) == 0);
722 send_mutex_cv_cmd (0, CMD_WAIT_FOR_SIGNAL
, &mutex
, &cv
);
724 ret
= pthread_mutex_destroy (&mutex
);
725 check_result (/* expected */ EBUSY
, ret
);
726 pthread_cond_signal (&cv
);
728 assert (pthread_mutex_destroy (&mutex
) == 0);
735 mutex_lock_test (void)
737 pthread_mutexattr_t mattr
;
738 pthread_mutex_t mutex
;
739 pthread_attr_t pattr
;
742 thread_state_t state
;
747 * pthread_lock not tested for:
749 log_info ("Testing pthread_mutex_lock\n");
750 log_info ("--------------------------\n");
752 assert (pthread_attr_init (&pattr
) == 0);
753 assert (pthread_attr_setdetachstate (&pattr
,
754 PTHREAD_CREATE_DETACHED
) == 0);
755 state
.flags
= 0; /* No flags yet. */
757 for (mproto
= 0; mproto
< NELEMENTS(protocols
); mproto
++) {
758 for (mkind
= M_POSIX
; mkind
<= M_SS2_RECURSIVE
; mkind
++) {
759 /* Initialize the mutex attribute. */
760 assert (pthread_mutexattr_init (&mattr
) == 0);
761 assert (pthread_mutexattr_setprotocol (&mattr
,
762 protocols
[mproto
]) == 0);
765 * Ensure that the first mutex type is a POSIX
768 if (mkind
!= M_POSIX
) {
769 assert (pthread_mutexattr_settype (&mattr
,
770 mutex_types
[mkind
]) == 0);
773 /* Create the mutex. */
774 assert (pthread_mutex_init (&mutex
, &mattr
) == 0);
776 log_info (" Protocol %s, Type %s\n",
777 protocol_strs
[mproto
], mutextype_strs
[mkind
]);
779 log_info (" Lock on unlocked mutex - ");
780 ret
= pthread_mutex_lock (&mutex
);
781 check_result (/* expected */ 0, ret
);
782 pthread_mutex_unlock (&mutex
);
784 log_info (" Lock on invalid mutex - ");
785 ret
= pthread_mutex_lock (NULL
);
786 check_result (/* expected */ EINVAL
, ret
);
788 log_info (" Lock on mutex held by self - ");
789 assert (pthread_create (&state
.tid
, &pattr
, lock_twice
,
790 (void *) &state
) == 0);
791 /* Let the thread start. */
793 state
.cmd
.mutex
= &mutex
;
794 state
.ret
= 0xdeadbeef;
795 assert (pthread_mutex_lock (&cond_mutex
) == 0);
796 assert (pthread_cond_signal (&cond_var
) == 0);
797 assert (pthread_mutex_unlock (&cond_mutex
) == 0);
798 /* Let the thread receive and process the command. */
803 check_result (/* expected */ EDEADLK
,
807 check_result (/* expected */ EDEADLK
,
810 case M_SS2_ERRORCHECK
:
811 check_result (/* expected */ EDEADLK
,
815 check_result (/* expected */ 0xdeadbeef,
818 case M_SS2_RECURSIVE
:
819 check_result (/* expected */ 0, state
.ret
);
822 pthread_mutex_destroy (&mutex
);
823 pthread_mutexattr_destroy (&mattr
);
830 mutex_unlock_test (void)
832 const int test_thread_id
= 0; /* ID of test thread */
833 pthread_mutexattr_t mattr
;
834 pthread_mutex_t mutex
;
841 * pthread_unlock not tested for:
843 log_info ("Testing pthread_mutex_unlock\n");
844 log_info ("----------------------------\n");
846 for (mproto
= 0; mproto
< NELEMENTS(protocols
); mproto
++) {
847 for (mkind
= M_POSIX
; mkind
<= M_SS2_RECURSIVE
; mkind
++) {
848 /* Initialize the mutex attribute. */
849 assert (pthread_mutexattr_init (&mattr
) == 0);
850 assert (pthread_mutexattr_setprotocol (&mattr
,
851 protocols
[mproto
]) == 0);
854 * Ensure that the first mutex type is a POSIX
857 if (mkind
!= M_POSIX
) {
858 assert (pthread_mutexattr_settype (&mattr
,
859 mutex_types
[mkind
]) == 0);
862 /* Create the mutex. */
863 assert (pthread_mutex_init (&mutex
, &mattr
) == 0);
865 log_info (" Protocol %s, Type %s\n",
866 protocol_strs
[mproto
], mutextype_strs
[mkind
]);
868 log_info (" Unlock on mutex held by self - ");
869 assert (pthread_mutex_lock (&mutex
) == 0);
870 ret
= pthread_mutex_unlock (&mutex
);
871 check_result (/* expected */ 0, ret
);
873 log_info (" Unlock on invalid mutex - ");
874 ret
= pthread_mutex_unlock (NULL
);
875 check_result (/* expected */ EINVAL
, ret
);
877 log_info (" Unlock on mutex locked by another thread - ");
878 send_mutex_cmd (test_thread_id
, CMD_TAKE_MUTEX
, &mutex
);
880 ret
= pthread_mutex_unlock (&mutex
);
883 check_result (/* expected */ EPERM
, ret
);
886 check_result (/* expected */ EPERM
, ret
);
888 case M_SS2_ERRORCHECK
:
889 check_result (/* expected */ EPERM
, ret
);
892 check_result (/* expected */ EPERM
, ret
);
894 case M_SS2_RECURSIVE
:
895 check_result (/* expected */ EPERM
, ret
);
900 * If for some reason we were able to unlock
901 * the mutex, relock it so that the test
902 * thread has no problems releasing the mutex.
904 pthread_mutex_lock (&mutex
);
906 send_cmd (test_thread_id
, CMD_RELEASE_ALL
);
909 pthread_mutex_destroy (&mutex
);
910 pthread_mutexattr_destroy (&mattr
);
917 queueing_order_test (void)
921 log_info ("Testing queueing order\n");
922 log_info ("----------------------\n");
923 assert (pthread_mutex_lock (&waiter_mutex
) == 0);
925 * Tell the threads to report when they take the waiters mutex.
927 assert (pthread_mutex_lock (&cond_mutex
) == 0);
928 for (i
= 0; i
< NUM_THREADS
; i
++) {
929 states
[i
].flags
= FLAGS_REPORT_WAITMUTEX
;
930 assert (pthread_cond_signal (&states
[i
].cond_var
) == 0);
932 assert (pthread_mutex_unlock (&cond_mutex
) == 0);
934 /* Signal the threads to continue. */
937 /* Use the global condition variable next time. */
938 use_global_condvar
= 1;
940 /* Release the waiting threads and allow them to run again. */
941 assert (pthread_mutex_unlock (&waiter_mutex
) == 0);
944 log_info (" Queueing order on a mutex - ");
945 check_run_order ("9,8,7,6,5,4,3,2,1,0");
946 for (i
= 0; i
< NUM_THREADS
; i
= i
+ 1) {
947 /* Tell the threads to report when they've been signaled. */
948 states
[i
].flags
= FLAGS_REPORT_WAITCONDVAR
;
952 * Prevent the threads from continuing their loop after we
955 assert (pthread_mutex_lock (&waiter_mutex
) == 0);
958 log_info (" Queueing order on a condition variable - ");
960 * Signal one thread to run and see that the highest priority
963 assert (pthread_mutex_lock (&cond_mutex
) == 0);
964 assert (pthread_cond_signal (&cond_var
) == 0);
965 assert (pthread_mutex_unlock (&cond_mutex
) == 0);
967 if (states
[NUM_THREADS
- 1].status
!= STAT_WAITMUTEX
)
968 log_error ("highest priority thread does not run.\n");
970 /* Signal the remaining threads. */
971 assert (pthread_mutex_lock (&cond_mutex
) == 0);
972 assert (pthread_cond_broadcast (&cond_var
) == 0);
973 assert (pthread_mutex_unlock (&cond_mutex
) == 0);
976 check_run_order ("9,8,7,6,5,4,3,2,1,0");
977 for (i
= 0; i
< NUM_THREADS
; i
= i
+ 1) {
978 /* Tell the threads not to report anything. */
982 /* Use the thread unique condition variable next time. */
983 use_global_condvar
= 0;
985 /* Allow the threads to continue their loop. */
986 assert (pthread_mutex_unlock (&waiter_mutex
) == 0);
992 mutex_prioceiling_test (void)
994 const int test_thread_id
= 0; /* ID of test thread */
995 pthread_mutexattr_t mattr
;
996 struct sched_param param
;
997 pthread_mutex_t m
[3];
999 int i
, ret
, policy
, my_prio
, old_ceiling
;
1001 log_info ("Testing priority ceilings\n");
1002 log_info ("-------------------------\n");
1003 for (mkind
= M_POSIX
; mkind
<= M_SS2_RECURSIVE
; mkind
++) {
1005 log_info (" Protype PTHREAD_PRIO_PROTECT, Type %s\n",
1006 mutextype_strs
[mkind
]);
1009 * Initialize and create a mutex.
1011 assert (pthread_mutexattr_init (&mattr
) == 0);
1013 /* Get this threads current priority. */
1014 assert (pthread_getschedparam (pthread_self(), &policy
,
1016 my_prio
= param
.sched_priority
; /* save for later use */
1017 log_trace ("Current scheduling policy %d, priority %d\n",
1021 * Initialize and create 3 priority protection mutexes with
1022 * default (max priority) ceilings.
1024 assert (pthread_mutexattr_setprotocol(&mattr
,
1025 PTHREAD_PRIO_PROTECT
) == 0);
1028 * Ensure that the first mutex type is a POSIX
1031 if (mkind
!= M_POSIX
) {
1032 assert (pthread_mutexattr_settype (&mattr
,
1033 mutex_types
[mkind
]) == 0);
1036 for (i
= 0; i
< 3; i
++)
1037 assert (pthread_mutex_init (&m
[i
], &mattr
) == 0);
1040 * Set the ceiling priorities for the 3 priority protection
1041 * mutexes to, 5 less than, equal to, and 5 greater than,
1042 * this threads current priority.
1044 for (i
= 0; i
< 3; i
++)
1045 assert (pthread_mutex_setprioceiling (&m
[i
],
1046 my_prio
- 5 + 5*i
, &old_ceiling
) == 0);
1049 * Check that if we attempt to take a mutex whose priority
1050 * ceiling is lower than our priority, we get an error.
1052 log_info (" Lock with ceiling priority < thread priority - ");
1053 ret
= pthread_mutex_lock (&m
[0]);
1054 check_result (/* expected */ EINVAL
, ret
);
1056 pthread_mutex_unlock (&m
[0]);
1059 * Check that we can take a mutex whose priority ceiling
1060 * is equal to our priority.
1062 log_info (" Lock with ceiling priority = thread priority - ");
1063 ret
= pthread_mutex_lock (&m
[1]);
1064 check_result (/* expected */ 0, ret
);
1066 pthread_mutex_unlock (&m
[1]);
1069 * Check that we can take a mutex whose priority ceiling
1070 * is higher than our priority.
1072 log_info (" Lock with ceiling priority > thread priority - ");
1073 ret
= pthread_mutex_lock (&m
[2]);
1074 check_result (/* expected */ 0, ret
);
1076 pthread_mutex_unlock (&m
[2]);
1079 * Have the test thread go into a busy loop for 5 seconds
1080 * and see that it doesn't block this thread (since the
1081 * priority ceiling of mutex 0 and the priority of the test
1082 * thread are both less than the priority of this thread).
1084 log_info (" Preemption with ceiling priority < thread "
1086 /* Have the test thread take mutex 0. */
1087 send_mutex_cmd (test_thread_id
, CMD_TAKE_MUTEX
, &m
[0]);
1090 log_trace ("Sending busy command.\n");
1091 send_cmd (test_thread_id
, CMD_BUSY_LOOP
);
1092 log_trace ("Busy sent, yielding\n");
1094 log_trace ("Returned from yield.\n");
1095 if (states
[test_thread_id
].flags
&
1096 (FLAGS_IS_BUSY
| FLAGS_WAS_BUSY
))
1097 log_error ("test thread inproperly preempted us.\n");
1099 /* Let the thread finish its busy loop. */
1101 if ((states
[test_thread_id
].flags
& FLAGS_WAS_BUSY
) == 0)
1102 log_error ("test thread never finished.\n");
1106 states
[test_thread_id
].flags
&= ~FLAGS_WAS_BUSY
;
1108 /* Have the test thread release mutex 0. */
1109 send_cmd (test_thread_id
, CMD_RELEASE_ALL
);
1113 * Have the test thread go into a busy loop for 5 seconds
1114 * and see that it preempts this thread (since the priority
1115 * ceiling of mutex 1 is the same as the priority of this
1116 * thread). The test thread should not run to completion
1117 * as its time quantum should expire before the 5 seconds
1120 log_info (" Preemption with ceiling priority = thread "
1123 /* Have the test thread take mutex 1. */
1124 send_mutex_cmd (test_thread_id
, CMD_TAKE_MUTEX
, &m
[1]);
1127 log_trace ("Sending busy\n");
1128 send_cmd (test_thread_id
, CMD_BUSY_LOOP
);
1129 log_trace ("Busy sent, yielding\n");
1131 log_trace ("Returned from yield.\n");
1132 if ((states
[test_thread_id
].flags
& FLAGS_IS_BUSY
) == 0)
1133 log_error ("test thread did not switch in on yield.\n");
1134 else if (states
[test_thread_id
].flags
& FLAGS_WAS_BUSY
)
1135 log_error ("test thread ran to completion.\n");
1137 /* Let the thread finish its busy loop. */
1139 if ((states
[test_thread_id
].flags
& FLAGS_WAS_BUSY
) == 0)
1140 log_error ("test thread never finished.\n");
1144 states
[test_thread_id
].flags
&= ~FLAGS_WAS_BUSY
;
1146 /* Have the test thread release mutex 1. */
1147 send_cmd (test_thread_id
, CMD_RELEASE_ALL
);
1151 * Set the scheduling policy of the test thread to SCHED_FIFO
1152 * and have it go into a busy loop for 5 seconds. This
1153 * thread is SCHED_RR, and since the priority ceiling of
1154 * mutex 1 is the same as the priority of this thread, the
1155 * test thread should run to completion once it is switched
1158 log_info (" SCHED_FIFO scheduling and ceiling priority = "
1159 "thread priority - ");
1160 param
.sched_priority
= states
[test_thread_id
].priority
;
1161 assert (pthread_setschedparam (states
[test_thread_id
].tid
,
1162 SCHED_FIFO
, ¶m
) == 0);
1164 /* Have the test thread take mutex 1. */
1165 send_mutex_cmd (test_thread_id
, CMD_TAKE_MUTEX
, &m
[1]);
1168 log_trace ("Sending busy\n");
1169 send_cmd (test_thread_id
, CMD_BUSY_LOOP
);
1170 log_trace ("Busy sent, yielding\n");
1172 log_trace ("Returned from yield.\n");
1173 if ((states
[test_thread_id
].flags
& FLAGS_WAS_BUSY
) == 0) {
1174 log_error ("test thread did not run to completion.\n");
1175 /* Let the thread finish it's busy loop. */
1180 states
[test_thread_id
].flags
&= ~FLAGS_WAS_BUSY
;
1182 /* Restore the test thread scheduling parameters. */
1183 param
.sched_priority
= states
[test_thread_id
].priority
;
1184 assert (pthread_setschedparam (states
[test_thread_id
].tid
,
1185 SCHED_RR
, ¶m
) == 0);
1187 /* Have the test thread release mutex 1. */
1188 send_cmd (test_thread_id
, CMD_RELEASE_ALL
);
1192 * Have the test thread go into a busy loop for 5 seconds
1193 * and see that it preempts this thread (since the priority
1194 * ceiling of mutex 2 is the greater than the priority of
1195 * this thread). The test thread should run to completion
1196 * and block this thread because its active priority is
1199 log_info (" SCHED_FIFO scheduling and ceiling priority > "
1200 "thread priority - ");
1201 /* Have the test thread take mutex 2. */
1202 send_mutex_cmd (test_thread_id
, CMD_TAKE_MUTEX
, &m
[2]);
1205 log_trace ("Sending busy\n");
1206 send_cmd (test_thread_id
, CMD_BUSY_LOOP
);
1207 log_trace ("Busy sent, yielding\n");
1209 log_trace ("Returned from yield.\n");
1210 if ((states
[test_thread_id
].flags
& FLAGS_IS_BUSY
) != 0) {
1211 log_error ("test thread did not run to completion.\n");
1212 /* Let the thread finish it's busy loop. */
1215 else if ((states
[test_thread_id
].flags
& FLAGS_WAS_BUSY
) == 0)
1216 log_error ("test thread never finished.\n");
1219 states
[test_thread_id
].flags
&= ~FLAGS_WAS_BUSY
;
1221 /* Have the test thread release mutex 2. */
1222 send_cmd (test_thread_id
, CMD_RELEASE_ALL
);
1225 /* Destroy the mutexes. */
1226 for (i
= 0; i
< 3; i
++)
1227 assert (pthread_mutex_destroy (&m
[i
]) == 0);
1233 mutex_prioinherit_test (void)
1235 pthread_mutexattr_t mattr
;
1236 struct sched_param param
;
1237 pthread_mutex_t m
[3];
1239 int i
, policy
, my_prio
;
1241 /* Get this threads current priority. */
1242 assert (pthread_getschedparam (pthread_self(), &policy
,
1244 my_prio
= param
.sched_priority
; /* save for later use */
1245 log_trace ("Current scheduling policy %d, priority %d\n",
1248 log_info ("Testing priority inheritance\n");
1249 log_info ("----------------------------\n");
1250 for (mkind
= M_POSIX
; mkind
<= M_SS2_RECURSIVE
; mkind
++) {
1252 log_info (" Protype PTHREAD_PRIO_INHERIT, Type %s\n",
1253 mutextype_strs
[mkind
]);
1256 * Initialize and create a mutex.
1258 assert (pthread_mutexattr_init (&mattr
) == 0);
1261 * Initialize and create 3 priority inheritance mutexes with
1262 * default (max priority) ceilings.
1264 assert (pthread_mutexattr_setprotocol(&mattr
,
1265 PTHREAD_PRIO_INHERIT
) == 0);
1268 * Ensure that the first mutex type is a POSIX
1271 if (mkind
!= M_POSIX
) {
1272 assert (pthread_mutexattr_settype (&mattr
,
1273 mutex_types
[mkind
]) == 0);
1276 for (i
= 0; i
< 3; i
++)
1277 assert (pthread_mutex_init (&m
[i
], &mattr
) == 0);
1281 * Thread 4 - take mutex 0, 1
1282 * Thread 2 - enter protected busy loop with mutex 0
1283 * Thread 3 - enter protected busy loop with mutex 1
1284 * Thread 4 - enter protected busy loop with mutex 2
1285 * Thread 5 - enter busy loop
1286 * Thread 6 - enter protected busy loop with mutex 0
1287 * Thread 4 - releases mutexes 1 and 0.
1290 * Threads complete in order 4, 6, 5, 3, 2
1292 log_info (" Simple inheritance test - ");
1295 * Command thread 4 to take mutexes 0 and 1.
1297 send_mutex_cmd (4, CMD_TAKE_MUTEX
, &m
[0]);
1298 sleep (1); /* Allow command to be received. */
1299 send_mutex_cmd (4, CMD_TAKE_MUTEX
, &m
[1]);
1303 * Tell the threads to report themselves when they are
1304 * at the bottom of their loop (waiting on wait_mutex).
1306 for (i
= 0; i
< NUM_THREADS
; i
++)
1307 states
[i
].flags
|= FLAGS_REPORT_WAITMUTEX
;
1310 * Command thread 2 to take mutex 0 and thread 3 to take
1311 * mutex 1, both via a protected operation command. Since
1312 * thread 4 owns mutexes 0 and 1, both threads 2 and 3
1313 * will block until the mutexes are released by thread 4.
1315 log_trace ("Commanding protected operation to thread 2.\n");
1316 send_mutex_cmd (2, CMD_PROTECTED_OP
, &m
[0]);
1317 log_trace ("Commanding protected operation to thread 3.\n");
1318 send_mutex_cmd (3, CMD_PROTECTED_OP
, &m
[1]);
1322 * Command thread 4 to take mutex 2 via a protected operation
1323 * and thread 5 to enter a busy loop for 5 seconds. Since
1324 * thread 5 has higher priority than thread 4, thread 5 will
1325 * enter the busy loop before thread 4 is activated.
1327 log_trace ("Commanding protected operation to thread 4.\n");
1328 send_mutex_cmd (4, CMD_PROTECTED_OP
, &m
[2]);
1329 log_trace ("Commanding busy loop to thread 5.\n");
1330 send_cmd (5, CMD_BUSY_LOOP
);
1332 if ((states
[5].flags
& FLAGS_IS_BUSY
) == 0)
1333 log_error ("thread 5 is not running.\n");
1334 log_trace ("Commanding protected operation thread 6.\n");
1335 send_mutex_cmd (6, CMD_PROTECTED_OP
, &m
[0]);
1337 if ((states
[4].flags
& FLAGS_WAS_BUSY
) == 0)
1338 log_error ("thread 4 failed to inherit priority.\n");
1339 states
[4].flags
= 0;
1340 send_cmd (4, CMD_RELEASE_ALL
);
1342 check_run_order ("4,6,5,3,2");
1347 for (i
= 0; i
< NUM_THREADS
; i
++)
1348 states
[i
].flags
= 0;
1352 * Thread 2 - enter busy loop (SCHED_FIFO)
1353 * Thread 4 - take mutex 0
1354 * Thread 4 - priority change to same priority as thread 2
1355 * Thread 4 - release mutex 0
1358 * Since thread 4 owns a priority mutex, it should be
1359 * placed at the front of the run queue (for its new
1360 * priority slot) when its priority is lowered to the
1361 * same priority as thread 2. If thread 4 did not own
1362 * a priority mutex, then it would have been added to
1363 * the end of the run queue and thread 2 would have
1364 * executed until it blocked (because it's scheduling
1365 * policy is SCHED_FIFO).
1368 log_info (" Inheritance test with change of priority - ");
1371 * Change threads 2 and 4 scheduling policies to be
1374 param
.sched_priority
= states
[2].priority
;
1375 assert (pthread_setschedparam (states
[2].tid
, SCHED_FIFO
,
1377 param
.sched_priority
= states
[4].priority
;
1378 assert (pthread_setschedparam (states
[4].tid
, SCHED_FIFO
,
1382 * Command thread 4 to take mutex 0.
1384 send_mutex_cmd (4, CMD_TAKE_MUTEX
, &m
[0]);
1388 * Command thread 2 to enter busy loop.
1390 send_cmd (2, CMD_BUSY_LOOP
);
1391 sleep (1); /* Allow command to be received. */
1394 * Command thread 4 to enter busy loop.
1396 send_cmd (4, CMD_BUSY_LOOP
);
1397 sleep (1); /* Allow command to be received. */
1399 /* Have threads 2 and 4 report themselves. */
1400 states
[2].flags
= FLAGS_REPORT_WAITMUTEX
;
1401 states
[4].flags
= FLAGS_REPORT_WAITMUTEX
;
1403 /* Change the priority of thread 4. */
1404 param
.sched_priority
= states
[2].priority
;
1405 assert (pthread_setschedparam (states
[4].tid
, SCHED_FIFO
,
1408 check_run_order ("4,2");
1410 /* Clear the flags */
1411 states
[2].flags
= 0;
1412 states
[4].flags
= 0;
1414 /* Reset the policies. */
1415 param
.sched_priority
= states
[2].priority
;
1416 assert (pthread_setschedparam (states
[2].tid
, SCHED_RR
,
1418 param
.sched_priority
= states
[4].priority
;
1419 assert (pthread_setschedparam (states
[4].tid
, SCHED_RR
,
1422 send_cmd (4, CMD_RELEASE_MUTEX
);
1425 /* Destroy the mutexes. */
1426 for (i
= 0; i
< 3; i
++)
1427 assert (pthread_mutex_destroy (&m
[i
]) == 0);
1432 int main (int argc
, char *argv
[])
1434 pthread_mutexattr_t mattr
;
1435 pthread_condattr_t cattr
;
1436 pthread_attr_t pattr
;
1437 int i
, policy
, main_prio
;
1440 struct sigaction act
;
1441 struct sched_param param
;
1446 assert (pthread_getschedparam (pthread_self (), &policy
, ¶m
) == 0);
1447 main_prio
= param
.sched_priority
;
1449 /* Setupt our signal mask. */
1451 sigdelset (&mask
, SIGINT
);
1452 sigprocmask (SIG_SETMASK
, &mask
, NULL
);
1454 /* Install a signal handler for SIGINT */
1455 sigemptyset (&act
.sa_mask
);
1456 sigaddset (&act
.sa_mask
, SIGINT
);
1457 act
.sa_handler
= sighandler
;
1458 act
.sa_flags
= SA_RESTART
;
1459 sigaction (SIGINT
, &act
, NULL
);
1462 * Initialize the thread attribute.
1464 assert (pthread_attr_init (&pattr
) == 0);
1465 assert (pthread_attr_setdetachstate (&pattr
,
1466 PTHREAD_CREATE_JOINABLE
) == 0);
1469 * Initialize and create the waiter and condvar mutexes.
1471 assert (pthread_mutexattr_init (&mattr
) == 0);
1472 assert (pthread_mutex_init (&waiter_mutex
, &mattr
) == 0);
1473 assert (pthread_mutex_init (&cond_mutex
, &mattr
) == 0);
1476 * Initialize and create a condition variable.
1478 assert (pthread_condattr_init (&cattr
) == 0);
1479 assert (pthread_cond_init (&cond_var
, &cattr
) == 0);
1481 /* Create a pipe to catch the results of thread wakeups. */
1482 assert (pipe (pipefd
) == 0);
1485 assert (pthread_switch_add_np (kern_switch
) == 0);
1489 * Create the waiting threads.
1491 for (i
= 0; i
< NUM_THREADS
; i
++) {
1492 assert (pthread_cond_init (&states
[i
].cond_var
, &cattr
) == 0);
1493 states
[i
].id
= (u_int8_t
) i
; /* NUM_THREADS must be <= 256 */
1494 states
[i
].status
= 0;
1495 states
[i
].cmd
.cmd_id
= CMD_NONE
;
1496 states
[i
].flags
= 0; /* No flags yet. */
1497 assert (pthread_create (&states
[i
].tid
, &pattr
, waiter
,
1498 (void *) &states
[i
]) == 0);
1499 param
.sched_priority
= main_prio
- 10 + i
;
1500 states
[i
].priority
= param
.sched_priority
;
1501 assert (pthread_setschedparam (states
[i
].tid
, SCHED_OTHER
,
1503 snprintf (buf
, sizeof(buf
), "waiter_%d", i
);
1504 pthread_set_name_np (states
[i
].tid
, buf
);
1507 /* Allow the threads to start. */
1509 log_trace ("Done creating threads.\n");
1514 mutex_destroy_test ();
1518 mutex_unlock_test ();
1520 queueing_order_test ();
1522 mutex_prioinherit_test ();
1524 mutex_prioceiling_test ();
1527 log_info ("Total tests %d, passed %d, failed %d\n",
1528 total
, pass_count
, error_count
);
1530 /* Set the done flag and signal the threads to exit. */
1531 log_trace ("Setting done flag.\n");
1535 * Wait for the threads to finish.
1537 log_trace ("Trying to join threads.\n");
1538 for (i
= 0; i
< NUM_THREADS
; i
++) {
1539 send_cmd (i
, CMD_NONE
);
1540 assert (pthread_join (states
[i
].tid
, &exit_status
) == 0);
1543 /* Clean up after ourselves. */
1547 if (error_count
!= 0)
1548 exit (EX_OSERR
); /* any better ideas??? */