mutex_d.c revision 99239
11592Srgrimes/*
21592Srgrimes * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com>
31592Srgrimes * All rights reserved.
41592Srgrimes *
51592Srgrimes * Redistribution and use in source and binary forms, with or without
61592Srgrimes * modification, are permitted provided that the following conditions
71592Srgrimes * are met:
81592Srgrimes * 1. Redistributions of source code must retain the above copyright
91592Srgrimes *    notice, this list of conditions and the following disclaimer.
101592Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111592Srgrimes *    notice, this list of conditions and the following disclaimer in the
121592Srgrimes *    documentation and/or other materials provided with the distribution.
131592Srgrimes * 3. All advertising materials mentioning features or use of this software
141592Srgrimes *    must display the following acknowledgement:
151592Srgrimes *	This product includes software developed by Daniel M. Eischen.
161592Srgrimes * 4. Neither the name of the author nor the names of any co-contributors
171592Srgrimes *    may be used to endorse or promote products derived from this software
181592Srgrimes *    without specific prior written permission.
191592Srgrimes *
201592Srgrimes * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS''
211592Srgrimes * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221592Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231592Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
241592Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251592Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261592Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271592Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281592Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291592Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301592Srgrimes * SUCH DAMAGE.
311592Srgrimes *
321592Srgrimes * $FreeBSD: head/lib/libkse/test/mutex_d.c 99239 2002-07-02 01:26:16Z deischen $
331592Srgrimes */
341592Srgrimes#include <stdlib.h>
351592Srgrimes#include <unistd.h>
361592Srgrimes
371592Srgrimes#include <sys/ioctl.h>
381592Srgrimes#include <assert.h>
391592Srgrimes#include <errno.h>
401592Srgrimes#include "pthread.h"
411592Srgrimes#include <sched.h>
421592Srgrimes#include <signal.h>
431592Srgrimes#include <stdarg.h>
4431329Scharnier#include <stdio.h>
451592Srgrimes#include <string.h>
4631329Scharnier#include <sysexits.h>
4731329Scharnier
4850476Speter#if defined(_LIBC_R_)
491592Srgrimes#include <pthread_np.h>
501592Srgrimes#endif
511592Srgrimes
521592Srgrimes#ifndef NELEMENTS
531592Srgrimes#define NELEMENTS(arr)	(sizeof (arr) / sizeof (arr[0]))
541592Srgrimes#endif
551592Srgrimes
561592Srgrimes#ifndef NUM_THREADS
571592Srgrimes#define NUM_THREADS	10
581592Srgrimes#endif
591592Srgrimes
601592Srgrimes#define MAX_THREAD_CMDS	10
6156668Sshin
621592Srgrimesstatic void log_error(const char *, ...) __printflike(1, 2);
631592Srgrimesstatic void log_trace (const char *, ...) __printflike(1, 2);
641592Srgrimesstatic void log (const char *, ...) __printflike(1, 2);
651592Srgrimes
661592Srgrimes/*------------------------------------------------------------
671592Srgrimes * Types
681592Srgrimes *----------------------------------------------------------*/
691592Srgrimes
701592Srgrimestypedef enum {
7113139Speter	STAT_INITIAL,		/* initial state */
721592Srgrimes	STAT_WAITCONDVAR,	/* waiting for condition variable signal */
731592Srgrimes	STAT_WAITMUTEX		/* waiting for mutex lock */
741592Srgrimes} thread_status_t;
7556668Sshin
761592Srgrimestypedef enum {
771592Srgrimes	FLAGS_REPORT_WAITCONDMUTEX	= 0x01,
781592Srgrimes	FLAGS_REPORT_WAITCONDVAR	= 0x02,
7917435Spst	FLAGS_REPORT_WAITMUTEX		= 0x04,
801592Srgrimes	FLAGS_REPORT_BUSY_LOOP		= 0x08,
811592Srgrimes	FLAGS_IS_BUSY			= 0x10,
821592Srgrimes	FLAGS_WAS_BUSY			= 0x20
831592Srgrimes} thread_flags_t;
841592Srgrimes
851592Srgrimestypedef enum {
861592Srgrimes	CMD_NONE,
8727650Sdavidn	CMD_TAKE_MUTEX,
8827650Sdavidn	CMD_RELEASE_MUTEX,
891592Srgrimes	CMD_WAIT_FOR_SIGNAL,
901592Srgrimes	CMD_BUSY_LOOP,
911592Srgrimes	CMD_PROTECTED_OP,
921592Srgrimes	CMD_RELEASE_ALL
931592Srgrimes} thread_cmd_id_t;
941592Srgrimes
951592Srgrimestypedef struct {
961592Srgrimes	thread_cmd_id_t	cmd_id;
971592Srgrimes	pthread_mutex_t	*mutex;
981592Srgrimes	pthread_cond_t	*cond;
991592Srgrimes} thread_cmd_t;
1001592Srgrimes
1011592Srgrimestypedef struct {
10256668Sshin	pthread_cond_t	cond_var;
10356668Sshin	thread_status_t	status;
1041592Srgrimes	thread_cmd_t	cmd;
1051592Srgrimes	int		flags;
1061592Srgrimes	int		priority;
1071592Srgrimes	int		ret;
1081592Srgrimes	pthread_t	tid;
1091592Srgrimes	u_int8_t	id;
1101592Srgrimes} thread_state_t;
1111592Srgrimes
1121592Srgrimestypedef enum {
1131592Srgrimes	M_POSIX,
11456668Sshin	M_SS2_DEFAULT,
1151592Srgrimes	M_SS2_ERRORCHECK,
1161592Srgrimes	M_SS2_NORMAL,
1171592Srgrimes	M_SS2_RECURSIVE
1181592Srgrimes} mutex_kind_t;
1191592Srgrimes
1201592Srgrimes
1211592Srgrimes/*------------------------------------------------------------
1221592Srgrimes * Constants
1231592Srgrimes *----------------------------------------------------------*/
1241592Srgrimes
12556668Sshinconst char *protocol_strs[] = {
1261592Srgrimes	"PTHREAD_PRIO_NONE",
1271592Srgrimes	"PTHREAD_PRIO_INHERIT",
1281592Srgrimes	"PTHREAD_PRIO_PROTECT"
1291592Srgrimes};
1301592Srgrimes
1311592Srgrimesconst int protocols[] = {
1321592Srgrimes	PTHREAD_PRIO_NONE,
1331592Srgrimes	PTHREAD_PRIO_INHERIT,
1341592Srgrimes	PTHREAD_PRIO_PROTECT
1351592Srgrimes};
13656668Sshin
13756668Sshinconst char *mutextype_strs[] = {
1381592Srgrimes	"POSIX (type not specified)",
1391592Srgrimes	"SS2 PTHREAD_MUTEX_DEFAULT",
1401592Srgrimes	"SS2 PTHREAD_MUTEX_ERRORCHECK",
1411592Srgrimes	"SS2 PTHREAD_MUTEX_NORMAL",
1421592Srgrimes	"SS2 PTHREAD_MUTEX_RECURSIVE"
1431592Srgrimes};
1441592Srgrimes
1451592Srgrimesconst int mutex_types[] = {
1461592Srgrimes	0,				/* M_POSIX		*/
1471592Srgrimes	PTHREAD_MUTEX_DEFAULT,		/* M_SS2_DEFAULT	*/
1481592Srgrimes	PTHREAD_MUTEX_ERRORCHECK,	/* M_SS2_ERRORCHECK	*/
1491592Srgrimes	PTHREAD_MUTEX_NORMAL,		/* M_SS2_NORMAL		*/
1501592Srgrimes	PTHREAD_MUTEX_RECURSIVE		/* M_SS2_RECURSIVE	*/
1511592Srgrimes};
1521592Srgrimes
1531592Srgrimes
1541592Srgrimes/*------------------------------------------------------------
1551592Srgrimes * Objects
1561592Srgrimes *----------------------------------------------------------*/
1571592Srgrimes
1581592Srgrimesstatic int		done = 0;
1591592Srgrimesstatic int		trace_enabled = 0;
1601592Srgrimesstatic int		use_global_condvar = 0;
1611592Srgrimesstatic thread_state_t	states[NUM_THREADS];
1621592Srgrimesstatic int		pipefd[2];
1631592Srgrimes
16417433Spststatic pthread_mutex_t	waiter_mutex;
1651592Srgrimesstatic pthread_mutex_t	cond_mutex;
16656668Sshinstatic pthread_cond_t	cond_var;
16756668Sshin
16856668Sshinstatic FILE *logfile;
16956668Sshinstatic int error_count = 0, pass_count = 0, total = 0;
17056668Sshin
17156668Sshin
17256668Sshin/*------------------------------------------------------------
17356668Sshin * Prototypes
17456668Sshin *----------------------------------------------------------*/
17556668Sshinextern char *strtok_r(char *str, const char *sep, char **last);
17656668Sshin
17756668Sshin
17856668Sshin/*------------------------------------------------------------
17956668Sshin * Functions
18056668Sshin *----------------------------------------------------------*/
18156668Sshin
18256668Sshin#ifdef DEBUG
18356668Sshinstatic void
18456668Sshinkern_switch (pthread_t pthread_out, pthread_t pthread_in)
18556668Sshin{
18656668Sshin	if (pthread_out != NULL)
18756668Sshin		printf ("Swapping out thread 0x%x, ", (int) pthread_out);
18856668Sshin	else
18956668Sshin		printf ("Swapping out kernel thread, ");
19056668Sshin
19156668Sshin	if (pthread_in != NULL)
19256668Sshin		printf ("swapping in thread 0x%x\n", (int) pthread_in);
19356668Sshin	else
19456668Sshin		printf ("swapping in kernel thread.\n");
19556668Sshin}
19656668Sshin#endif
19756668Sshin
19856668Sshin
19956668Sshinstatic void
20056668Sshinlog_error (const char *fmt, ...)
20156668Sshin{
20256668Sshin	va_list ap;
20356668Sshin
20456668Sshin	va_start (ap, fmt);
20556668Sshin	fprintf (logfile, "FAIL: ");
20656668Sshin	vfprintf (logfile, fmt, ap);
20756668Sshin	error_count = error_count + 1;
20856668Sshin	total = total + 1;
20956668Sshin}
21056668Sshin
21156668Sshin
21256668Sshinstatic void
21356668Sshinlog_pass (void)
21456668Sshin{
21556668Sshin	fprintf (logfile, "PASS\n");
21656668Sshin	pass_count = pass_count + 1;
21756668Sshin	total = total + 1;
21856668Sshin}
21956668Sshin
22056668Sshin
22156668Sshinstatic void
22256668Sshinlog_trace (const char *fmt, ...)
22356668Sshin{
22456668Sshin	va_list ap;
22556668Sshin
22656668Sshin	if (trace_enabled) {
22756668Sshin		va_start (ap, fmt);
22856668Sshin		vfprintf (logfile, fmt, ap);
22956668Sshin	}
23056668Sshin}
23156668Sshin
23256668Sshin
23356668Sshinstatic void
23456668Sshinlog (const char *fmt, ...)
23556668Sshin{
23656668Sshin	va_list ap;
23756668Sshin
23856668Sshin	va_start (ap, fmt);
23956668Sshin	vfprintf (logfile, fmt, ap);
24056668Sshin}
24156668Sshin
24256668Sshin
24356668Sshinstatic void
24417433Spstcheck_result (int expected, int actual)
24556668Sshin{
24617433Spst	if (expected != actual)
24756668Sshin		log_error ("expected %d, returned %d\n", expected, actual);
24856668Sshin	else
24956668Sshin		log_pass ();
25056668Sshin}
25156668Sshin
2521592Srgrimes
25356668Sshin/*
25456668Sshin * Check to see that the threads ran in the specified order.
25556668Sshin */
25656668Sshinstatic void
25756668Sshincheck_run_order (char *order)
25856668Sshin{
25956668Sshin	const char *sep = ":,";
26056668Sshin	char *tok, *last, *idstr, *endptr;
26156668Sshin	int expected_id, bytes, count = 0, errors = 0;
26256668Sshin	u_int8_t id;
26356668Sshin
26456668Sshin	assert ((tok = (char *) malloc (strlen(order) + 1)) != NULL);
26556668Sshin	strcpy (tok, order);	/* tok has to be larger than order */
26656668Sshin	assert (ioctl (pipefd[0], FIONREAD, &bytes) == 0);
26756668Sshin	log_trace ("%d bytes read from FIFO.\n", bytes);
26856668Sshin
26956668Sshin	for (idstr = strtok_r (tok, sep, &last);
27056668Sshin	     (idstr != NULL) && (count < bytes);
27156668Sshin	     idstr = strtok_r (NULL, sep, &last)) {
27256668Sshin
27356668Sshin		/* Get the expected id: */
27456668Sshin		expected_id = (int) strtol (idstr, &endptr, 10);
27556668Sshin		assert ((endptr != NULL) && (*endptr == '\0'));
27656668Sshin
27756668Sshin		/* Read the actual id from the pipe: */
27856668Sshin		assert (read (pipefd[0], &id, sizeof (id)) == sizeof (id));
27956668Sshin		count = count + sizeof (id);
28056668Sshin
28156668Sshin		if (id != expected_id) {
28256668Sshin			log_trace ("Thread %d ran out of order.\n", id);
28356668Sshin			errors = errors + 1;
28456668Sshin		}
28556668Sshin		else {
28656668Sshin			log_trace ("Thread %d at priority %d reporting.\n",
28756668Sshin			    (int) id, states[id].priority);
28856668Sshin		}
28956668Sshin	}
29056668Sshin
29156668Sshin	if (count < bytes) {
29256668Sshin		/* Clear the pipe: */
29356668Sshin		while (count < bytes) {
29456668Sshin			read (pipefd[0], &id, sizeof (id));
29556668Sshin			count = count + 1;
29656668Sshin			errors = errors + 1;
29756668Sshin		}
29856668Sshin	}
29956668Sshin	else if (bytes < count)
30056668Sshin		errors = errors + count - bytes;
30156668Sshin
30256668Sshin	if (errors == 0)
30356668Sshin		log_pass ();
30456668Sshin	else
30556668Sshin		log_error ("%d threads ran out of order", errors);
3061592Srgrimes}
30717433Spst
3081592Srgrimes
30956668Sshinstatic void *
31056668Sshinwaiter (void *arg)
31156668Sshin{
31217433Spst	thread_state_t	*statep = (thread_state_t *) arg;
3131592Srgrimes	pthread_mutex_t	*held_mutex[MAX_THREAD_CMDS];
31456668Sshin	int 		held_mutex_owned[MAX_THREAD_CMDS];
31556668Sshin	sigset_t	mask;
31656668Sshin	struct timeval	tv1, tv2;
31756668Sshin	thread_cmd_t	cmd;
31856668Sshin	int 		i, mutex_count = 0;
31956668Sshin
32056668Sshin	statep->status = STAT_INITIAL;
32156668Sshin
32256668Sshin	/* Block all signals except for interrupt.*/
32356668Sshin	sigfillset (&mask);
32456668Sshin	sigdelset (&mask, SIGINT);
32556668Sshin	sigprocmask (SIG_BLOCK, &mask, NULL);
32656668Sshin
32756668Sshin	while (done == 0) {
32856668Sshin		/* Wait for signal from the main thread to continue. */
32956668Sshin		statep->status = STAT_WAITMUTEX;
33056668Sshin		log_trace ("Thread %d: locking cond_mutex.\n",
33156668Sshin		    (int) statep->id);
33256668Sshin		pthread_mutex_lock (&cond_mutex);
33356668Sshin
33456668Sshin		/* Do we report our status. */
33556668Sshin		if (statep->flags & FLAGS_REPORT_WAITCONDMUTEX)
33656668Sshin			write (pipefd[1], &statep->id, sizeof (statep->id));
33756668Sshin		log_trace ("Thread %d: waiting for cond_var.\n",
33856668Sshin		    (int) statep->id);
33956668Sshin
34056668Sshin		/* Wait for a command. */
34156668Sshin		statep->status = STAT_WAITCONDVAR;
34256668Sshin
34356668Sshin		/*
34456668Sshin		 * The threads are allowed commanded to wait either on
34556668Sshin		 * their own unique condition variable (so they may be
34656668Sshin		 * separately signaled) or on one global condition variable
34756668Sshin		 * (so they may be signaled together).
34856668Sshin		 */
34956668Sshin		if (use_global_condvar != 0)
35056668Sshin			pthread_cond_wait (&cond_var, &cond_mutex);
35156668Sshin		else
35256668Sshin			pthread_cond_wait (&statep->cond_var, &cond_mutex);
35356668Sshin
3541592Srgrimes		/* Do we report our status? */
3551592Srgrimes		if (statep->flags & FLAGS_REPORT_WAITCONDVAR) {
3561592Srgrimes			write (pipefd[1], &statep->id, sizeof (statep->id));
3571592Srgrimes			log_trace ("Thread %d: wrote to pipe.\n",
3581592Srgrimes			    (int) statep->id);
3591592Srgrimes		}
3601592Srgrimes		log_trace ("Thread %d: received cond_var signal.\n",
3611592Srgrimes		    (int) statep->id);
3621592Srgrimes
3631592Srgrimes		/* Get a copy of the command before releasing the mutex. */
3641592Srgrimes		cmd = statep->cmd;
3651592Srgrimes
3661592Srgrimes		/* Clear the command after copying it. */
3671592Srgrimes		statep->cmd.cmd_id = CMD_NONE;
3681592Srgrimes
3691592Srgrimes		/* Unlock the condition variable mutex. */
3701592Srgrimes		assert (pthread_mutex_unlock (&cond_mutex) == 0);
3711592Srgrimes
3721592Srgrimes		/* Peform the command.*/
3731592Srgrimes		switch (cmd.cmd_id) {
3741592Srgrimes		case CMD_TAKE_MUTEX:
3751592Srgrimes			statep->ret = pthread_mutex_lock (cmd.mutex);
3761592Srgrimes			if (statep->ret == 0) {
3771592Srgrimes				assert (mutex_count < sizeof (held_mutex));
3781592Srgrimes				held_mutex[mutex_count] = cmd.mutex;
3791592Srgrimes				held_mutex_owned[mutex_count] = 1;
3801592Srgrimes				mutex_count++;
3811592Srgrimes			}
3821592Srgrimes			else {
3831592Srgrimes				held_mutex_owned[mutex_count] = 0;
3841592Srgrimes				log_trace ("Thread id %d unable to lock mutex, "
3851592Srgrimes				    "error = %d\n", (int) statep->id,
3861592Srgrimes				    statep->ret);
3871592Srgrimes			}
3881592Srgrimes			break;
3891592Srgrimes
3901592Srgrimes		case CMD_RELEASE_MUTEX:
3911592Srgrimes			assert ((mutex_count <= sizeof (held_mutex)) &&
3921592Srgrimes			    (mutex_count > 0));
3931592Srgrimes			mutex_count--;
3941592Srgrimes			if (held_mutex_owned[mutex_count] != 0)
3951592Srgrimes				assert (pthread_mutex_unlock
3961592Srgrimes				    (held_mutex[mutex_count]) == 0);
3971592Srgrimes			break;
3981592Srgrimes
3991592Srgrimes		case CMD_WAIT_FOR_SIGNAL:
4001592Srgrimes			assert (pthread_mutex_lock (cmd.mutex) == 0);
4011592Srgrimes			assert (pthread_cond_wait (cmd.cond, cmd.mutex) == 0);
4021592Srgrimes			assert (pthread_mutex_unlock (cmd.mutex) == 0);
4031592Srgrimes			break;
4041592Srgrimes
4051592Srgrimes		case CMD_BUSY_LOOP:
4061592Srgrimes			log_trace ("Thread %d: Entering busy loop.\n",
4071592Srgrimes			    (int) statep->id);
4081592Srgrimes			/* Spin for 15 seconds. */
4091592Srgrimes			assert (gettimeofday (&tv2, NULL) == 0);
4101592Srgrimes			tv1.tv_sec = tv2.tv_sec + 5;
4111592Srgrimes			tv1.tv_usec = tv2.tv_usec;
4121592Srgrimes			statep->flags |= FLAGS_IS_BUSY;
4131592Srgrimes			while (timercmp (&tv2, &tv1,<)) {
4141592Srgrimes				assert (gettimeofday (&tv2, NULL) == 0);
4151592Srgrimes			}
4161592Srgrimes			statep->flags &= ~FLAGS_IS_BUSY;
4171592Srgrimes			statep->flags |= FLAGS_WAS_BUSY;
4181592Srgrimes
4191592Srgrimes			/* Do we report our status? */
4201592Srgrimes			if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
4211592Srgrimes				write (pipefd[1], &statep->id,
4221592Srgrimes				    sizeof (statep->id));
4231592Srgrimes
4241592Srgrimes			log_trace ("Thread %d: Leaving busy loop.\n",
4251592Srgrimes			    (int) statep->id);
4261592Srgrimes			break;
4271592Srgrimes
4281592Srgrimes		case CMD_PROTECTED_OP:
4291592Srgrimes			assert (pthread_mutex_lock (cmd.mutex) == 0);
4301592Srgrimes			statep->flags |= FLAGS_WAS_BUSY;
4311592Srgrimes			/* Do we report our status? */
4321592Srgrimes			if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
4331592Srgrimes				write (pipefd[1], &statep->id,
4341592Srgrimes				    sizeof (statep->id));
4351592Srgrimes
4361592Srgrimes			assert (pthread_mutex_unlock (cmd.mutex) == 0);
4371592Srgrimes			break;
4381592Srgrimes
4391592Srgrimes		case CMD_RELEASE_ALL:
4401592Srgrimes			assert ((mutex_count <= sizeof (held_mutex)) &&
4411592Srgrimes			    (mutex_count > 0));
4421592Srgrimes			for (i = mutex_count - 1; i >= 0; i--) {
4431592Srgrimes				if (held_mutex_owned[i] != 0)
4441592Srgrimes					assert (pthread_mutex_unlock
4451592Srgrimes					    (held_mutex[i]) == 0);
4461592Srgrimes			}
4471592Srgrimes			mutex_count = 0;
4481592Srgrimes			break;
4491592Srgrimes
4501592Srgrimes		case CMD_NONE:
4511592Srgrimes		default:
4521592Srgrimes			break;
4531592Srgrimes		}
4541592Srgrimes
4551592Srgrimes		/* Wait for the big giant waiter lock. */
4561592Srgrimes		statep->status = STAT_WAITMUTEX;
4571592Srgrimes		log_trace ("Thread %d: waiting for big giant lock.\n",
4581592Srgrimes		    (int) statep->id);
4591592Srgrimes		pthread_mutex_lock (&waiter_mutex);
4601592Srgrimes		if (statep->flags & FLAGS_REPORT_WAITMUTEX)
4611592Srgrimes			write (pipefd[1], &statep->id, sizeof (statep->id));
4621592Srgrimes		log_trace ("Thread %d: got big giant lock.\n",
4631592Srgrimes		    (int) statep->id);
4641592Srgrimes		statep->status = STAT_INITIAL;
4651592Srgrimes		pthread_mutex_unlock (&waiter_mutex);
4661592Srgrimes	}
4671592Srgrimes
4681592Srgrimes	log_trace ("Thread %d: Exiting thread 0x%x\n", (int) statep->id,
4691592Srgrimes	    (int) pthread_self());
4701592Srgrimes	pthread_exit (arg);
4711592Srgrimes	return (NULL);
4721592Srgrimes}
4731592Srgrimes
4741592Srgrimes
4751592Srgrimesstatic void *
4761592Srgrimeslock_twice (void *arg)
4771592Srgrimes{
4781592Srgrimes	thread_state_t	*statep = (thread_state_t *) arg;
4791592Srgrimes	sigset_t	mask;
4801592Srgrimes
4811592Srgrimes	statep->status = STAT_INITIAL;
4821592Srgrimes
4831592Srgrimes	/* Block all signals except for interrupt.*/
48417433Spst	sigfillset (&mask);
4851592Srgrimes	sigdelset (&mask, SIGINT);
48617433Spst	sigprocmask (SIG_BLOCK, &mask, NULL);
48717433Spst
48817433Spst	/* Wait for a signal to continue. */
48917433Spst	log_trace ("Thread %d: locking cond_mutex.\n", (int) statep->id);
49017433Spst	pthread_mutex_lock (&cond_mutex);
49117433Spst
49217433Spst	log_trace ("Thread %d: waiting for cond_var.\n", (int) statep->id);
49317433Spst	statep->status = STAT_WAITCONDVAR;
4941592Srgrimes	pthread_cond_wait (&cond_var, &cond_mutex);
49517433Spst
4961592Srgrimes	log_trace ("Thread %d: received cond_var signal.\n", (int) statep->id);
4971592Srgrimes
4981592Srgrimes	/* Unlock the condition variable mutex. */
4991592Srgrimes	assert (pthread_mutex_unlock (&cond_mutex) == 0);
5001592Srgrimes
5011592Srgrimes	statep->status = STAT_WAITMUTEX;
5021592Srgrimes	/* Lock the mutex once. */
5031592Srgrimes	assert (pthread_mutex_lock (statep->cmd.mutex) == 0);
5041592Srgrimes
5051592Srgrimes	/* Lock it again and capture the error. */
5061592Srgrimes	statep->ret = pthread_mutex_lock (statep->cmd.mutex);
5071592Srgrimes	statep->status = 0;
5081592Srgrimes
5091592Srgrimes	assert (pthread_mutex_unlock (statep->cmd.mutex) == 0);
5101592Srgrimes
5111592Srgrimes	/* Unlock it again if it is locked recursively. */
5121592Srgrimes	if (statep->ret == 0)
5131592Srgrimes		pthread_mutex_unlock (statep->cmd.mutex);
5141592Srgrimes
5151592Srgrimes	log_trace ("Thread %d: Exiting thread 0x%x\n", (int) statep->id,
5161592Srgrimes	    (int) pthread_self());
5171592Srgrimes	pthread_exit (arg);
5181592Srgrimes	return (NULL);
5191592Srgrimes}
5201592Srgrimes
5211592Srgrimes
5221592Srgrimesstatic void
5231592Srgrimessighandler (int signo)
5241592Srgrimes{
5251592Srgrimes	log ("Signal handler caught signal %d, thread id 0x%x\n",
5261592Srgrimes	    signo, (int) pthread_self());
5271592Srgrimes
5281592Srgrimes	if (signo == SIGINT)
5291592Srgrimes		done = 1;
5301592Srgrimes}
5311592Srgrimes
5321592Srgrimes
5331592Srgrimesstatic void
5341592Srgrimessend_cmd (int id, thread_cmd_id_t cmd)
5351592Srgrimes{
5361592Srgrimes	assert (pthread_mutex_lock (&cond_mutex) == 0);
5371592Srgrimes	assert (states[id].status == STAT_WAITCONDVAR);
5381592Srgrimes	states[id].cmd.cmd_id = cmd;
5391592Srgrimes	states[id].cmd.mutex = NULL;
5401592Srgrimes	states[id].cmd.cond = NULL;
5411592Srgrimes	/* Clear the busy flags. */
5421592Srgrimes	states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
5431592Srgrimes	assert (pthread_cond_signal (&states[id].cond_var) == 0);
5441592Srgrimes	assert (pthread_mutex_unlock (&cond_mutex) == 0);
5451592Srgrimes}
5461592Srgrimes
5471592Srgrimes
5481592Srgrimesstatic void
5491592Srgrimessend_mutex_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m)
5501592Srgrimes{
5511592Srgrimes	assert (pthread_mutex_lock (&cond_mutex) == 0);
5521592Srgrimes	assert (states[id].status == STAT_WAITCONDVAR);
5531592Srgrimes	states[id].cmd.cmd_id = cmd;
5541592Srgrimes	states[id].cmd.mutex = m;
5551592Srgrimes	states[id].cmd.cond = NULL;
5561592Srgrimes	/* Clear the busy flags. */
5571592Srgrimes	states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
5581592Srgrimes	assert (pthread_cond_signal (&states[id].cond_var) == 0);
5591592Srgrimes	assert (pthread_mutex_unlock (&cond_mutex) == 0);
5601592Srgrimes}
5611592Srgrimes
5621592Srgrimes
5631592Srgrimesstatic void
5641592Srgrimessend_mutex_cv_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m,
5651592Srgrimes    pthread_cond_t *cv)
5661592Srgrimes{
5671592Srgrimes	assert (pthread_mutex_lock (&cond_mutex) == 0);
5681592Srgrimes	assert (states[id].status == STAT_WAITCONDVAR);
5691592Srgrimes	states[id].cmd.cmd_id = cmd;
5701592Srgrimes	states[id].cmd.mutex = m;
5711592Srgrimes	states[id].cmd.cond = cv;
5721592Srgrimes	/* Clear the busy flags. */
5731592Srgrimes	states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
5741592Srgrimes	assert (pthread_cond_signal (&states[id].cond_var) == 0);
5751592Srgrimes	assert (pthread_mutex_unlock (&cond_mutex) == 0);
5761592Srgrimes}
5771592Srgrimes
5781592Srgrimes
5791592Srgrimesstatic void
5801592Srgrimesmutex_init_test (void)
5811592Srgrimes{
5821592Srgrimes	pthread_mutexattr_t mattr;
5831592Srgrimes	pthread_mutex_t	mutex;
5841592Srgrimes	mutex_kind_t mkind;
5851592Srgrimes	int mproto, ret;
5861592Srgrimes
5871592Srgrimes	/*
5881592Srgrimes	 * Initialize a mutex attribute.
5891592Srgrimes	 *
5901592Srgrimes	 * pthread_mutexattr_init not tested for: ENOMEM
5911592Srgrimes	 */
5921592Srgrimes	assert (pthread_mutexattr_init (&mattr) == 0);
5931592Srgrimes
5941592Srgrimes	/*
5951592Srgrimes	 * Initialize a mutex.
5961592Srgrimes	 *
5971592Srgrimes	 * pthread_mutex_init not tested for: EAGAIN ENOMEM EPERM EBUSY
5981592Srgrimes	 */
5991592Srgrimes	log ("Testing pthread_mutex_init\n");
6001592Srgrimes	log ("--------------------------\n");
6011592Srgrimes
6021592Srgrimes	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
6031592Srgrimes		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
6041592Srgrimes			/* Initialize the mutex attribute. */
6051592Srgrimes			assert (pthread_mutexattr_init (&mattr) == 0);
6061592Srgrimes			assert (pthread_mutexattr_setprotocol (&mattr,
6071592Srgrimes			    protocols[mproto]) == 0);
6081592Srgrimes
6091592Srgrimes			/*
6101592Srgrimes			 * Ensure that the first mutex type is a POSIX
6111592Srgrimes			 * compliant mutex.
6121592Srgrimes			 */
6131592Srgrimes			if (mkind != M_POSIX) {
6141592Srgrimes				assert (pthread_mutexattr_settype (&mattr,
6151592Srgrimes				    mutex_types[mkind]) == 0);
6161592Srgrimes			}
6171592Srgrimes
6181592Srgrimes			log ("  Protocol %s, Type %s - ",
6191592Srgrimes			    protocol_strs[mproto], mutextype_strs[mkind]);
6201592Srgrimes			ret = pthread_mutex_init (&mutex, &mattr);
6211592Srgrimes			check_result (/* expected */ 0, ret);
6221592Srgrimes			assert (pthread_mutex_destroy (&mutex) == 0);
6231592Srgrimes
6241592Srgrimes			/*
6251592Srgrimes			 * Destroy a mutex attribute.
6261592Srgrimes			 *
6271592Srgrimes			 * XXX - There should probably be a magic number
6281592Srgrimes			 *       associated with a mutex attribute so that
6291592Srgrimes			 *       destroy can be reasonably sure the attribute
6301592Srgrimes			 *       is valid.
6311592Srgrimes			 *
6321592Srgrimes			 * pthread_mutexattr_destroy not tested for: EINVAL
6331592Srgrimes			 */
6341592Srgrimes			assert (pthread_mutexattr_destroy (&mattr) == 0);
6351592Srgrimes		}
6361592Srgrimes	}
6371592Srgrimes}
6381592Srgrimes
6391592Srgrimes
6401592Srgrimesstatic void
6411592Srgrimesmutex_destroy_test (void)
6421592Srgrimes{
6431592Srgrimes	pthread_mutexattr_t mattr;
6441592Srgrimes	pthread_mutex_t	mutex;
6451592Srgrimes	pthread_condattr_t cattr;
6461592Srgrimes	pthread_cond_t	cv;
6471592Srgrimes	pthread_attr_t pattr;
6481592Srgrimes	int mproto, ret;
6491592Srgrimes	mutex_kind_t mkind;
6501592Srgrimes	thread_state_t state;
6511592Srgrimes
6521592Srgrimes	/*
6531592Srgrimes	 * Destroy a mutex.
6541592Srgrimes	 *
6551592Srgrimes	 * XXX - There should probably be a magic number associated
6561592Srgrimes	 *       with a mutex so that destroy can be reasonably sure
6571592Srgrimes	 *       the mutex is valid.
6581592Srgrimes	 *
6591592Srgrimes	 * pthread_mutex_destroy not tested for:
6601592Srgrimes	 */
6611592Srgrimes	log ("Testing pthread_mutex_destroy\n");
6621592Srgrimes	log ("-----------------------------\n");
6631592Srgrimes
6641592Srgrimes	assert (pthread_attr_init (&pattr) == 0);
6651592Srgrimes	assert (pthread_attr_setdetachstate (&pattr,
6661592Srgrimes	    PTHREAD_CREATE_DETACHED) == 0);
6671592Srgrimes	state.flags = 0;	/* No flags yet. */
6681592Srgrimes
6691592Srgrimes	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
6701592Srgrimes		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
6711592Srgrimes			/* Initialize the mutex attribute. */
6721592Srgrimes			assert (pthread_mutexattr_init (&mattr) == 0);
6731592Srgrimes			assert (pthread_mutexattr_setprotocol (&mattr,
6741592Srgrimes			    protocols[mproto]) == 0);
6751592Srgrimes
6761592Srgrimes			/*
6771592Srgrimes			 * Ensure that the first mutex type is a POSIX
6781592Srgrimes			 * compliant mutex.
6791592Srgrimes			 */
6801592Srgrimes			if (mkind != M_POSIX) {
6811592Srgrimes				assert (pthread_mutexattr_settype (&mattr,
6821592Srgrimes				    mutex_types[mkind]) == 0);
6831592Srgrimes			}
6841592Srgrimes
68517435Spst			/* Create the mutex. */
68617435Spst			assert (pthread_mutex_init (&mutex, &mattr) == 0);
68717435Spst
6881592Srgrimes			log ("  Protocol %s, Type %s\n",
6891592Srgrimes			    protocol_strs[mproto], mutextype_strs[mkind]);
6901592Srgrimes
6911592Srgrimes			log ("    Destruction of unused mutex - ");
6921592Srgrimes			assert (pthread_mutex_init (&mutex, &mattr) == 0);
6931592Srgrimes			ret = pthread_mutex_destroy (&mutex);
6941592Srgrimes			check_result (/* expected */ 0, ret);
6951592Srgrimes
6961592Srgrimes			log ("    Destruction of mutex locked by self - ");
6971592Srgrimes			assert (pthread_mutex_init (&mutex, &mattr) == 0);
6981592Srgrimes			assert (pthread_mutex_lock (&mutex) == 0);
6991592Srgrimes			ret = pthread_mutex_destroy (&mutex);
7001592Srgrimes			check_result (/* expected */ EBUSY, ret);
7011592Srgrimes			assert (pthread_mutex_unlock (&mutex) == 0);
7021592Srgrimes			assert (pthread_mutex_destroy (&mutex) == 0);
7031592Srgrimes
7041592Srgrimes			log ("    Destruction of mutex locked by another "
7051592Srgrimes			    "thread - ");
7061592Srgrimes			assert (pthread_mutex_init (&mutex, &mattr) == 0);
7071592Srgrimes			send_mutex_cmd (0, CMD_TAKE_MUTEX, &mutex);
7081592Srgrimes			sleep (1);
7091592Srgrimes			ret = pthread_mutex_destroy (&mutex);
7101592Srgrimes			check_result (/* expected */ EBUSY, ret);
7111592Srgrimes			send_cmd (0, CMD_RELEASE_ALL);
7121592Srgrimes			sleep (1);
7131592Srgrimes			assert (pthread_mutex_destroy (&mutex) == 0);
7141592Srgrimes
7151592Srgrimes			log ("    Destruction of mutex while being used in "
7161592Srgrimes			    "cond_wait - ");
7171592Srgrimes			assert (pthread_mutex_init (&mutex, &mattr) == 0);
7181592Srgrimes			assert (pthread_condattr_init (&cattr) == 0);
7191592Srgrimes			assert (pthread_cond_init (&cv, &cattr) == 0);
7201592Srgrimes			send_mutex_cv_cmd (0, CMD_WAIT_FOR_SIGNAL, &mutex, &cv);
7211592Srgrimes			sleep (1);
7221592Srgrimes			ret = pthread_mutex_destroy (&mutex);
7231592Srgrimes			check_result (/* expected */ EBUSY, ret);
7241592Srgrimes			pthread_cond_signal (&cv);
7251592Srgrimes			sleep (1);
7261592Srgrimes			assert (pthread_mutex_destroy (&mutex) == 0);
7271592Srgrimes		}
7281592Srgrimes	}
7291592Srgrimes}
7301592Srgrimes
7311592Srgrimes
7321592Srgrimesstatic void
7331592Srgrimesmutex_lock_test (void)
7341592Srgrimes{
7351592Srgrimes	pthread_mutexattr_t mattr;
7361592Srgrimes	pthread_mutex_t	mutex;
7371592Srgrimes	pthread_attr_t pattr;
7381592Srgrimes	int mproto, ret;
7391592Srgrimes	mutex_kind_t mkind;
7401592Srgrimes	thread_state_t state;
7411592Srgrimes
7421592Srgrimes	/*
7431592Srgrimes	 * Lock a mutex.
7441592Srgrimes	 *
7451592Srgrimes	 * pthread_lock not tested for:
7461592Srgrimes	 */
7471592Srgrimes	log ("Testing pthread_mutex_lock\n");
74856668Sshin	log ("--------------------------\n");
74956668Sshin
75056668Sshin	assert (pthread_attr_init (&pattr) == 0);
75117435Spst	assert (pthread_attr_setdetachstate (&pattr,
75256668Sshin	    PTHREAD_CREATE_DETACHED) == 0);
7531592Srgrimes	state.flags = 0;	/* No flags yet. */
7541592Srgrimes
7551592Srgrimes	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
7561592Srgrimes		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
75756668Sshin			/* Initialize the mutex attribute. */
75856668Sshin			assert (pthread_mutexattr_init (&mattr) == 0);
75956668Sshin			assert (pthread_mutexattr_setprotocol (&mattr,
76056668Sshin			    protocols[mproto]) == 0);
76156668Sshin
76256668Sshin			/*
76356668Sshin			 * Ensure that the first mutex type is a POSIX
76456668Sshin			 * compliant mutex.
76556668Sshin			 */
76656668Sshin			if (mkind != M_POSIX) {
76756668Sshin				assert (pthread_mutexattr_settype (&mattr,
76856668Sshin				    mutex_types[mkind]) == 0);
76956668Sshin			}
77056668Sshin
77156668Sshin			/* Create the mutex. */
77256668Sshin			assert (pthread_mutex_init (&mutex, &mattr) == 0);
77356668Sshin
77456668Sshin			log ("  Protocol %s, Type %s\n",
77556668Sshin			    protocol_strs[mproto], mutextype_strs[mkind]);
77656668Sshin
77756668Sshin			log ("    Lock on unlocked mutex - ");
77856668Sshin			ret = pthread_mutex_lock (&mutex);
77956668Sshin			check_result (/* expected */ 0, ret);
78056668Sshin			pthread_mutex_unlock (&mutex);
78156668Sshin
78256668Sshin			log ("    Lock on invalid mutex - ");
78356668Sshin			ret = pthread_mutex_lock (NULL);
78456668Sshin			check_result (/* expected */ EINVAL, ret);
78556668Sshin
78656668Sshin			log ("    Lock on mutex held by self - ");
78756668Sshin			assert (pthread_create (&state.tid, &pattr, lock_twice,
78856668Sshin			    (void *) &state) == 0);
78956668Sshin			/* Let the thread start. */
79056668Sshin			sleep (1);
79156668Sshin			state.cmd.mutex = &mutex;
79256668Sshin			state.ret = 0xdeadbeef;
79356668Sshin			assert (pthread_mutex_lock (&cond_mutex) == 0);
79456668Sshin			assert (pthread_cond_signal (&cond_var) == 0);
79556668Sshin			assert (pthread_mutex_unlock (&cond_mutex) == 0);
79656668Sshin			/* Let the thread receive and process the command. */
79756668Sshin			sleep (1);
79856668Sshin
79956668Sshin			switch (mkind) {
80056668Sshin			case M_POSIX:
80156668Sshin				check_result (/* expected */ EDEADLK,
80256668Sshin				    state.ret);
8031592Srgrimes				break;
8041592Srgrimes			case M_SS2_DEFAULT:
8051592Srgrimes				check_result (/* expected */ EDEADLK,
8061592Srgrimes				    state.ret);
8071592Srgrimes				break;
8081592Srgrimes			case M_SS2_ERRORCHECK:
8091592Srgrimes				check_result (/* expected */ EDEADLK,
8101592Srgrimes				    state.ret);
8111592Srgrimes				break;
8121592Srgrimes			case M_SS2_NORMAL:
8131592Srgrimes				check_result (/* expected */ 0xdeadbeef,
8141592Srgrimes				    state.ret);
8151592Srgrimes				break;
8161592Srgrimes			case M_SS2_RECURSIVE:
8171592Srgrimes				check_result (/* expected */ 0, state.ret);
8181592Srgrimes				break;
8191592Srgrimes			}
8201592Srgrimes			pthread_mutex_destroy (&mutex);
8211592Srgrimes			pthread_mutexattr_destroy (&mattr);
8221592Srgrimes		}
8231592Srgrimes	}
8241592Srgrimes}
8251592Srgrimes
8261592Srgrimes
8271592Srgrimesstatic void
8281592Srgrimesmutex_unlock_test (void)
8291592Srgrimes{
8301592Srgrimes	const int test_thread_id = 0;	/* ID of test thread */
8311592Srgrimes	pthread_mutexattr_t mattr;
8321592Srgrimes	pthread_mutex_t	mutex;
8331592Srgrimes	int mproto, ret;
8341592Srgrimes	mutex_kind_t mkind;
8351592Srgrimes
8361592Srgrimes	/*
8371592Srgrimes	 * Unlock a mutex.
8381592Srgrimes	 *
8391592Srgrimes	 * pthread_unlock not tested for:
8401592Srgrimes	 */
8411592Srgrimes	log ("Testing pthread_mutex_unlock\n");
8421592Srgrimes	log ("----------------------------\n");
8431592Srgrimes
8441592Srgrimes	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
8451592Srgrimes		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
8461592Srgrimes			/* Initialize the mutex attribute. */
8471592Srgrimes			assert (pthread_mutexattr_init (&mattr) == 0);
8481592Srgrimes			assert (pthread_mutexattr_setprotocol (&mattr,
8491592Srgrimes			    protocols[mproto]) == 0);
8501592Srgrimes
8511592Srgrimes			/*
8521592Srgrimes			 * Ensure that the first mutex type is a POSIX
8531592Srgrimes			 * compliant mutex.
8541592Srgrimes			 */
8551592Srgrimes			if (mkind != M_POSIX) {
8561592Srgrimes				assert (pthread_mutexattr_settype (&mattr,
8571592Srgrimes				    mutex_types[mkind]) == 0);
8581592Srgrimes			}
8591592Srgrimes
8601592Srgrimes			/* Create the mutex. */
8611592Srgrimes			assert (pthread_mutex_init (&mutex, &mattr) == 0);
8621592Srgrimes
8631592Srgrimes			log ("  Protocol %s, Type %s\n",
8641592Srgrimes			    protocol_strs[mproto], mutextype_strs[mkind]);
8651592Srgrimes
8661592Srgrimes			log ("    Unlock on mutex held by self - ");
8671592Srgrimes			assert (pthread_mutex_lock (&mutex) == 0);
8681592Srgrimes			ret = pthread_mutex_unlock (&mutex);
8691592Srgrimes			check_result (/* expected */ 0, ret);
8701592Srgrimes
8711592Srgrimes			log ("    Unlock on invalid mutex - ");
8721592Srgrimes			ret = pthread_mutex_unlock (NULL);
8731592Srgrimes			check_result (/* expected */ EINVAL, ret);
8741592Srgrimes
8751592Srgrimes			log ("    Unlock on mutex locked by another thread - ");
8761592Srgrimes			send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &mutex);
8771592Srgrimes			sleep (1);
8781592Srgrimes			ret = pthread_mutex_unlock (&mutex);
8791592Srgrimes			switch (mkind) {
8801592Srgrimes			case M_POSIX:
8811592Srgrimes				check_result (/* expected */ EPERM, ret);
8821592Srgrimes				break;
8831592Srgrimes			case M_SS2_DEFAULT:
8841592Srgrimes				check_result (/* expected */ EPERM, ret);
8851592Srgrimes				break;
8861592Srgrimes			case M_SS2_ERRORCHECK:
8871592Srgrimes				check_result (/* expected */ EPERM, ret);
8881592Srgrimes				break;
8891592Srgrimes			case M_SS2_NORMAL:
8901592Srgrimes				check_result (/* expected */ EPERM, ret);
8911592Srgrimes				break;
8921592Srgrimes			case M_SS2_RECURSIVE:
8931592Srgrimes				check_result (/* expected */ EPERM, ret);
8941592Srgrimes				break;
8951592Srgrimes			}
8961592Srgrimes			if (ret == 0) {
8971592Srgrimes				/*
8981592Srgrimes				 * If for some reason we were able to unlock
8991592Srgrimes				 * the mutex, relock it so that the test
9001592Srgrimes				 * thread has no problems releasing the mutex.
9011592Srgrimes				 */
9021592Srgrimes				pthread_mutex_lock (&mutex);
9031592Srgrimes			}
9041592Srgrimes			send_cmd (test_thread_id, CMD_RELEASE_ALL);
9051592Srgrimes			sleep (1);
9061592Srgrimes
9071592Srgrimes			pthread_mutex_destroy (&mutex);
9081592Srgrimes			pthread_mutexattr_destroy (&mattr);
9091592Srgrimes		}
9101592Srgrimes	}
9111592Srgrimes}
9121592Srgrimes
9131592Srgrimes
9141592Srgrimesstatic void
9151592Srgrimesqueueing_order_test (void)
9161592Srgrimes{
9171592Srgrimes	int i;
9181592Srgrimes
9191592Srgrimes	log ("Testing queueing order\n");
9201592Srgrimes	log ("----------------------\n");
9211592Srgrimes	assert (pthread_mutex_lock (&waiter_mutex) == 0);
9221592Srgrimes	/*
9231592Srgrimes	 * Tell the threads to report when they take the waiters mutex.
9241592Srgrimes	 */
9251592Srgrimes	assert (pthread_mutex_lock (&cond_mutex) == 0);
9261592Srgrimes	for (i = 0; i < NUM_THREADS; i++) {
9271592Srgrimes		states[i].flags = FLAGS_REPORT_WAITMUTEX;
9281592Srgrimes		assert (pthread_cond_signal (&states[i].cond_var) == 0);
9291592Srgrimes	}
9301592Srgrimes	assert (pthread_mutex_unlock (&cond_mutex) == 0);
9311592Srgrimes
9321592Srgrimes	/* Signal the threads to continue. */
9331592Srgrimes	sleep (1);
9341592Srgrimes
9351592Srgrimes	/* Use the global condition variable next time. */
9361592Srgrimes	use_global_condvar = 1;
9371592Srgrimes
9381592Srgrimes	/* Release the waiting threads and allow them to run again. */
9391592Srgrimes	assert (pthread_mutex_unlock (&waiter_mutex) == 0);
9401592Srgrimes	sleep (1);
9411592Srgrimes
9421592Srgrimes	log ("  Queueing order on a mutex - ");
9431592Srgrimes	check_run_order ("9,8,7,6,5,4,3,2,1,0");
9441592Srgrimes	for (i = 0; i < NUM_THREADS; i = i + 1) {
9451592Srgrimes		/* Tell the threads to report when they've been signaled. */
9461592Srgrimes		states[i].flags = FLAGS_REPORT_WAITCONDVAR;
9471592Srgrimes	}
9481592Srgrimes
9491592Srgrimes	/*
9501592Srgrimes	 * Prevent the threads from continuing their loop after we
9511592Srgrimes	 * signal them.
9521592Srgrimes	 */
9531592Srgrimes	assert (pthread_mutex_lock (&waiter_mutex) == 0);
9541592Srgrimes
9551592Srgrimes
9561592Srgrimes	log ("  Queueing order on a condition variable - ");
9571592Srgrimes	/*
9581592Srgrimes	 * Signal one thread to run and see that the highest priority
9591592Srgrimes	 * thread executes.
9601592Srgrimes	 */
9611592Srgrimes	assert (pthread_mutex_lock (&cond_mutex) == 0);
9621592Srgrimes	assert (pthread_cond_signal (&cond_var) == 0);
9631592Srgrimes	assert (pthread_mutex_unlock (&cond_mutex) == 0);
9641592Srgrimes	sleep (1);
9651592Srgrimes	if (states[NUM_THREADS - 1].status != STAT_WAITMUTEX)
9661592Srgrimes		log_error ("highest priority thread does not run.\n");
9671592Srgrimes
9681592Srgrimes	/* Signal the remaining threads. */
9691592Srgrimes	assert (pthread_mutex_lock (&cond_mutex) == 0);
9701592Srgrimes	assert (pthread_cond_broadcast (&cond_var) == 0);
9711592Srgrimes	assert (pthread_mutex_unlock (&cond_mutex) == 0);
9721592Srgrimes	sleep (1);
9731592Srgrimes
9741592Srgrimes	check_run_order ("9,8,7,6,5,4,3,2,1,0");
9751592Srgrimes	for (i = 0; i < NUM_THREADS; i = i + 1) {
9761592Srgrimes		/* Tell the threads not to report anything. */
9771592Srgrimes		states[i].flags = 0;
9781592Srgrimes	}
9791592Srgrimes
9801592Srgrimes	/* Use the thread unique condition variable next time. */
9811592Srgrimes	use_global_condvar = 0;
9821592Srgrimes
9831592Srgrimes	/* Allow the threads to continue their loop. */
9841592Srgrimes	assert (pthread_mutex_unlock (&waiter_mutex) == 0);
9851592Srgrimes	sleep (1);
9861592Srgrimes}
9871592Srgrimes
9881592Srgrimes
9891592Srgrimesstatic void
9901592Srgrimesmutex_prioceiling_test (void)
9911592Srgrimes{
99256668Sshin	const int test_thread_id = 0;	/* ID of test thread */
99356668Sshin	pthread_mutexattr_t mattr;
9941592Srgrimes	struct sched_param param;
99556668Sshin	pthread_mutex_t	m[3];
99656668Sshin	mutex_kind_t	mkind;
9971592Srgrimes	int		i, ret, policy, my_prio, old_ceiling;
9981592Srgrimes
9991592Srgrimes	log ("Testing priority ceilings\n");
10001592Srgrimes	log ("-------------------------\n");
10011592Srgrimes	for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
10021592Srgrimes
10031592Srgrimes		log ("  Protype PTHREAD_PRIO_PROTECT, Type %s\n",
10041592Srgrimes		    mutextype_strs[mkind]);
10051592Srgrimes
10061592Srgrimes		/*
10071592Srgrimes		 * Initialize and create a mutex.
10081592Srgrimes		 */
10091592Srgrimes		assert (pthread_mutexattr_init (&mattr) == 0);
10101592Srgrimes
10111592Srgrimes		/* Get this threads current priority. */
10121592Srgrimes		assert (pthread_getschedparam (pthread_self(), &policy,
10131592Srgrimes		    &param) == 0);
10141592Srgrimes		my_prio = param.sched_priority;	/* save for later use */
10151592Srgrimes		log_trace ("Current scheduling policy %d, priority %d\n",
10161592Srgrimes		    policy, my_prio);
10171592Srgrimes
10181592Srgrimes		/*
10191592Srgrimes		 * Initialize and create 3 priority protection mutexes with
10201592Srgrimes		 * default (max priority) ceilings.
10211592Srgrimes		 */
10221592Srgrimes		assert (pthread_mutexattr_setprotocol(&mattr,
10231592Srgrimes		    PTHREAD_PRIO_PROTECT) == 0);
10241592Srgrimes
10251592Srgrimes		/*
10261592Srgrimes		 * Ensure that the first mutex type is a POSIX
10271592Srgrimes		 * compliant mutex.
10281592Srgrimes		 */
10291592Srgrimes		if (mkind != M_POSIX) {
10301592Srgrimes			assert (pthread_mutexattr_settype (&mattr,
10311592Srgrimes			    mutex_types[mkind]) == 0);
10321592Srgrimes		}
10331592Srgrimes
10341592Srgrimes		for (i = 0; i < 3; i++)
10351592Srgrimes			assert (pthread_mutex_init (&m[i], &mattr) == 0);
10361592Srgrimes
10371592Srgrimes		/*
10381592Srgrimes		 * Set the ceiling priorities for the 3 priority protection
10391592Srgrimes		 * mutexes to, 5 less than, equal to, and 5 greater than,
10401592Srgrimes		 * this threads current priority.
10411592Srgrimes		 */
10421592Srgrimes		for (i = 0; i < 3; i++)
10431592Srgrimes			assert (pthread_mutex_setprioceiling (&m[i],
10441592Srgrimes			    my_prio - 5 + 5*i, &old_ceiling) == 0);
10451592Srgrimes
10461592Srgrimes		/*
10471592Srgrimes		 * Check that if we attempt to take a mutex whose priority
10481592Srgrimes		 * ceiling is lower than our priority, we get an error.
10491592Srgrimes		 */
10501592Srgrimes		log ("    Lock with ceiling priority < thread priority - ");
105156668Sshin		ret = pthread_mutex_lock (&m[0]);
105256668Sshin		check_result (/* expected */ EINVAL, ret);
10531592Srgrimes		if (ret == 0)
10541592Srgrimes			pthread_mutex_unlock (&m[0]);
105556668Sshin
10561592Srgrimes		/*
10571592Srgrimes		 * Check that we can take a mutex whose priority ceiling
10581592Srgrimes		 * is equal to our priority.
10591592Srgrimes		 */
10601592Srgrimes		log ("    Lock with ceiling priority = thread priority - ");
10611592Srgrimes		ret = pthread_mutex_lock (&m[1]);
10621592Srgrimes		check_result (/* expected */ 0, ret);
10631592Srgrimes		if (ret == 0)
10641592Srgrimes			pthread_mutex_unlock (&m[1]);
10651592Srgrimes
10661592Srgrimes		/*
10671592Srgrimes		 * Check that we can take a mutex whose priority ceiling
10681592Srgrimes		 * is higher than our priority.
10691592Srgrimes		 */
10701592Srgrimes		log ("    Lock with ceiling priority > thread priority - ");
10711592Srgrimes		ret = pthread_mutex_lock (&m[2]);
10721592Srgrimes		check_result (/* expected */ 0, ret);
10731592Srgrimes		if (ret == 0)
10741592Srgrimes			pthread_mutex_unlock (&m[2]);
10751592Srgrimes
10761592Srgrimes		/*
10771592Srgrimes		 * Have the test thread go into a busy loop for 5 seconds
10781592Srgrimes		 * and see that it doesn't block this thread (since the
10791592Srgrimes		 * priority ceiling of mutex 0 and the priority of the test
10801592Srgrimes		 * thread are both less than the priority of this thread).
10811592Srgrimes		 */
10821592Srgrimes		log ("    Preemption with ceiling priority < thread "
10831592Srgrimes		    "priority - ");
10841592Srgrimes		/* Have the test thread take mutex 0. */
10851592Srgrimes		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[0]);
10861592Srgrimes		sleep (1);
10871592Srgrimes
10881592Srgrimes		log_trace ("Sending busy command.\n");
10891592Srgrimes		send_cmd (test_thread_id, CMD_BUSY_LOOP);
10901592Srgrimes		log_trace ("Busy sent, yielding\n");
10911592Srgrimes		pthread_yield ();
10921592Srgrimes		log_trace ("Returned from yield.\n");
10931592Srgrimes		if (states[test_thread_id].flags &
10941592Srgrimes		    (FLAGS_IS_BUSY | FLAGS_WAS_BUSY))
10951592Srgrimes			log_error ("test thread inproperly preempted us.\n");
10961592Srgrimes		else {
10971592Srgrimes			/* Let the thread finish its busy loop. */
10981592Srgrimes			sleep (6);
10991592Srgrimes			if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
11001592Srgrimes				log_error ("test thread never finished.\n");
11011592Srgrimes			else
11021592Srgrimes				log_pass ();
11031592Srgrimes		}
11041592Srgrimes		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
11051592Srgrimes
11061592Srgrimes		/* Have the test thread release mutex 0. */
11071592Srgrimes		send_cmd (test_thread_id, CMD_RELEASE_ALL);
11081592Srgrimes		sleep (1);
11091592Srgrimes
11101592Srgrimes		/*
11111592Srgrimes		 * Have the test thread go into a busy loop for 5 seconds
11121592Srgrimes		 * and see that it preempts this thread (since the priority
11131592Srgrimes		 * ceiling of mutex 1 is the same as the priority of this
11141592Srgrimes		 * thread).  The test thread should not run to completion
11151592Srgrimes		 * as its time quantum should expire before the 5 seconds
11161592Srgrimes		 * are up.
11171592Srgrimes		 */
11181592Srgrimes		log ("    Preemption with ceiling priority = thread "
11191592Srgrimes		    "priority - ");
11201592Srgrimes
11211592Srgrimes		/* Have the test thread take mutex 1. */
11221592Srgrimes		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
11231592Srgrimes		sleep (1);
11241592Srgrimes
11251592Srgrimes		log_trace ("Sending busy\n");
11261592Srgrimes		send_cmd (test_thread_id, CMD_BUSY_LOOP);
11271592Srgrimes		log_trace ("Busy sent, yielding\n");
11281592Srgrimes		pthread_yield ();
11291592Srgrimes		log_trace ("Returned from yield.\n");
11301592Srgrimes		if ((states[test_thread_id].flags & FLAGS_IS_BUSY) == 0)
11311592Srgrimes			log_error ("test thread did not switch in on yield.\n");
11321592Srgrimes		else if (states[test_thread_id].flags & FLAGS_WAS_BUSY)
11331592Srgrimes			log_error ("test thread ran to completion.\n");
11341592Srgrimes		else {
11351592Srgrimes			/* Let the thread finish its busy loop. */
11361592Srgrimes			sleep (6);
11371592Srgrimes			if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
11381592Srgrimes				log_error ("test thread never finished.\n");
11391592Srgrimes			else
11401592Srgrimes				log_pass ();
11411592Srgrimes		}
11421592Srgrimes		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
11431592Srgrimes
11441592Srgrimes		/* Have the test thread release mutex 1. */
11451592Srgrimes		send_cmd (test_thread_id, CMD_RELEASE_ALL);
11461592Srgrimes		sleep (1);
11471592Srgrimes
11481592Srgrimes		/*
11491592Srgrimes		 * Set the scheduling policy of the test thread to SCHED_FIFO
11501592Srgrimes		 * and have it go into a busy loop for 5 seconds.  This
11511592Srgrimes		 * thread is SCHED_RR, and since the priority ceiling of
11521592Srgrimes		 * mutex 1 is the same as the priority of this thread, the
11531592Srgrimes		 * test thread should run to completion once it is switched
11541592Srgrimes		 * in.
11551592Srgrimes		 */
11561592Srgrimes		log ("    SCHED_FIFO scheduling and ceiling priority = "
11571592Srgrimes		    "thread priority - ");
11581592Srgrimes		param.sched_priority = states[test_thread_id].priority;
11591592Srgrimes		assert (pthread_setschedparam (states[test_thread_id].tid,
11601592Srgrimes		    SCHED_FIFO, &param) == 0);
11611592Srgrimes
11621592Srgrimes		/* Have the test thread take mutex 1. */
11631592Srgrimes		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
11641592Srgrimes		sleep (1);
11651592Srgrimes
11661592Srgrimes		log_trace ("Sending busy\n");
11671592Srgrimes		send_cmd (test_thread_id, CMD_BUSY_LOOP);
11681592Srgrimes		log_trace ("Busy sent, yielding\n");
11691592Srgrimes		pthread_yield ();
11701592Srgrimes		log_trace ("Returned from yield.\n");
11711592Srgrimes		if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) {
11721592Srgrimes			log_error ("test thread did not run to completion.\n");
11731592Srgrimes			/* Let the thread finish it's busy loop. */
11741592Srgrimes			sleep (6);
11751592Srgrimes		}
11761592Srgrimes		else
11771592Srgrimes			log_pass ();
11781592Srgrimes		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
11791592Srgrimes
11801592Srgrimes		/* Restore the test thread scheduling parameters. */
11811592Srgrimes		param.sched_priority = states[test_thread_id].priority;
11821592Srgrimes		assert (pthread_setschedparam (states[test_thread_id].tid,
11831592Srgrimes		    SCHED_RR, &param) == 0);
11841592Srgrimes
118529574Sphk		/* Have the test thread release mutex 1. */
11861592Srgrimes		send_cmd (test_thread_id, CMD_RELEASE_ALL);
11871592Srgrimes		sleep (1);
11881592Srgrimes
11891592Srgrimes		/*
11901592Srgrimes		 * Have the test thread go into a busy loop for 5 seconds
11911592Srgrimes		 * and see that it preempts this thread (since the priority
11921592Srgrimes		 * ceiling of mutex 2 is the greater than the priority of
11931592Srgrimes		 * this thread).  The test thread should run to completion
11941592Srgrimes		 * and block this thread because its active priority is
11951592Srgrimes		 * higher.
11961592Srgrimes		 */
11971592Srgrimes		log ("    SCHED_FIFO scheduling and ceiling priority > "
11981592Srgrimes		    "thread priority - ");
11991592Srgrimes		/* Have the test thread take mutex 2. */
12001592Srgrimes		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[2]);
12013776Spst		sleep (1);
12021592Srgrimes
12031592Srgrimes		log_trace ("Sending busy\n");
12041592Srgrimes		send_cmd (test_thread_id, CMD_BUSY_LOOP);
12051592Srgrimes		log_trace ("Busy sent, yielding\n");
12061592Srgrimes		pthread_yield ();
12071592Srgrimes		log_trace ("Returned from yield.\n");
12081592Srgrimes		if ((states[test_thread_id].flags & FLAGS_IS_BUSY) != 0) {
12091592Srgrimes			log_error ("test thread did not run to completion.\n");
12101592Srgrimes			/* Let the thread finish it's busy loop. */
12111592Srgrimes			sleep (6);
12121592Srgrimes		}
12131592Srgrimes		else if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
12141592Srgrimes			log_error ("test thread never finished.\n");
12151592Srgrimes		else
12161592Srgrimes			log_pass ();
12171592Srgrimes		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
12181592Srgrimes
12191592Srgrimes		/* Have the test thread release mutex 2. */
12201592Srgrimes		send_cmd (test_thread_id, CMD_RELEASE_ALL);
12211592Srgrimes		sleep (1);
12221592Srgrimes
12231592Srgrimes		/* Destroy the mutexes. */
12241592Srgrimes		for (i = 0; i < 3; i++)
12251592Srgrimes			assert (pthread_mutex_destroy (&m[i]) == 0);
12263777Spst	}
12271592Srgrimes}
12281592Srgrimes
12291592Srgrimes
12301592Srgrimesstatic void
12311592Srgrimesmutex_prioinherit_test (void)
12321592Srgrimes{
12331592Srgrimes	pthread_mutexattr_t mattr;
12341592Srgrimes	struct sched_param param;
12351592Srgrimes	pthread_mutex_t	m[3];
12361592Srgrimes	mutex_kind_t	mkind;
12371592Srgrimes	int		i, policy, my_prio;
12381592Srgrimes
12391592Srgrimes	/* Get this threads current priority. */
12401592Srgrimes	assert (pthread_getschedparam (pthread_self(), &policy,
12411592Srgrimes	    &param) == 0);
12421592Srgrimes	my_prio = param.sched_priority;	/* save for later use */
12431592Srgrimes	log_trace ("Current scheduling policy %d, priority %d\n",
12441592Srgrimes	    policy, my_prio);
12451592Srgrimes
12461592Srgrimes	log ("Testing priority inheritence\n");
12471592Srgrimes	log ("----------------------------\n");
12481592Srgrimes	for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
12491592Srgrimes
12501592Srgrimes		log ("  Protype PTHREAD_PRIO_INHERIT, Type %s\n",
12511592Srgrimes		    mutextype_strs[mkind]);
125251979Salfred
12531592Srgrimes		/*
12541592Srgrimes		 * Initialize and create a mutex.
12551592Srgrimes		 */
12561592Srgrimes		assert (pthread_mutexattr_init (&mattr) == 0);
12571592Srgrimes
12581592Srgrimes		/*
12591592Srgrimes		 * Initialize and create 3 priority inheritence mutexes with
12601592Srgrimes		 * default (max priority) ceilings.
12611592Srgrimes		 */
12621592Srgrimes		assert (pthread_mutexattr_setprotocol(&mattr,
12631592Srgrimes		    PTHREAD_PRIO_INHERIT) == 0);
12641592Srgrimes
12651592Srgrimes		/*
12661592Srgrimes		 * Ensure that the first mutex type is a POSIX
12671592Srgrimes		 * compliant mutex.
12681592Srgrimes		 */
12691592Srgrimes		if (mkind != M_POSIX) {
12701592Srgrimes			assert (pthread_mutexattr_settype (&mattr,
12711592Srgrimes			    mutex_types[mkind]) == 0);
12721592Srgrimes		}
12731592Srgrimes
12741592Srgrimes		for (i = 0; i < 3; i++)
12751592Srgrimes			assert (pthread_mutex_init (&m[i], &mattr) == 0);
12761592Srgrimes
12771592Srgrimes		/*
12781592Srgrimes		 * Test setup:
12791592Srgrimes		 *   Thread 4 - take mutex 0, 1
12801592Srgrimes		 *   Thread 2 - enter protected busy loop with mutex 0
12811592Srgrimes		 *   Thread 3 - enter protected busy loop with mutex 1
12821592Srgrimes		 *   Thread 4 - enter protected busy loop with mutex 2
12831592Srgrimes		 *   Thread 5 - enter busy loop
12841592Srgrimes		 *   Thread 6 - enter protected busy loop with mutex 0
12851592Srgrimes		 *   Thread 4 - releases mutexes 1 and 0.
12861592Srgrimes		 *
12871592Srgrimes		 * Expected results:
12881592Srgrimes		 *   Threads complete in order 4, 6, 5, 3, 2
12891592Srgrimes		 */
12901592Srgrimes		log ("    Simple inheritence test - ");
12911592Srgrimes
12921592Srgrimes		/*
12931592Srgrimes		 * Command thread 4 to take mutexes 0 and 1.
12941592Srgrimes		 */
12951592Srgrimes		send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
12961592Srgrimes		sleep (1);	/* Allow command to be received. */
12971592Srgrimes		send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[1]);
12981592Srgrimes		sleep (1);
12991592Srgrimes
13001592Srgrimes		/*
13011592Srgrimes		 * Tell the threads to report themselves when they are
13021592Srgrimes		 * at the bottom of their loop (waiting on wait_mutex).
13031592Srgrimes		 */
13041592Srgrimes		for (i = 0; i < NUM_THREADS; i++)
13051592Srgrimes			states[i].flags |= FLAGS_REPORT_WAITMUTEX;
13061592Srgrimes
13071592Srgrimes		/*
13081592Srgrimes		 * Command thread 2 to take mutex 0 and thread 3 to take
13091592Srgrimes		 * mutex 1, both via a protected operation command.  Since
131056668Sshin		 * thread 4 owns mutexes 0 and 1, both threads 2 and 3
131156668Sshin		 * will block until the mutexes are released by thread 4.
131256668Sshin		 */
131356668Sshin		log_trace ("Commanding protected operation to thread 2.\n");
131456668Sshin		send_mutex_cmd (2, CMD_PROTECTED_OP, &m[0]);
13151592Srgrimes		log_trace ("Commanding protected operation to thread 3.\n");
13161592Srgrimes		send_mutex_cmd (3, CMD_PROTECTED_OP, &m[1]);
13171592Srgrimes		sleep (1);
13181592Srgrimes
13191592Srgrimes		/*
13201592Srgrimes		 * Command thread 4 to take mutex 2 via a protected operation
13211592Srgrimes		 * and thread 5 to enter a busy loop for 5 seconds.  Since
13221592Srgrimes		 * thread 5 has higher priority than thread 4, thread 5 will
13231592Srgrimes		 * enter the busy loop before thread 4 is activated.
13241592Srgrimes		 */
13251592Srgrimes		log_trace ("Commanding protected operation to thread 4.\n");
13261592Srgrimes		send_mutex_cmd (4, CMD_PROTECTED_OP, &m[2]);
13271592Srgrimes		log_trace ("Commanding busy loop to thread 5.\n");
13281592Srgrimes		send_cmd (5, CMD_BUSY_LOOP);
13291592Srgrimes		sleep (1);
13301592Srgrimes		if ((states[5].flags & FLAGS_IS_BUSY) == 0)
13311592Srgrimes			log_error ("thread 5 is not running.\n");
13321592Srgrimes		log_trace ("Commanding protected operation thread 6.\n");
13331592Srgrimes		send_mutex_cmd (6, CMD_PROTECTED_OP, &m[0]);
13341592Srgrimes		sleep (1);
13351592Srgrimes		if ((states[4].flags & FLAGS_WAS_BUSY) == 0)
13361592Srgrimes			log_error ("thread 4 failed to inherit priority.\n");
13371592Srgrimes		states[4].flags = 0;
13381592Srgrimes		send_cmd (4, CMD_RELEASE_ALL);
13391592Srgrimes		sleep (5);
13401592Srgrimes		check_run_order ("4,6,5,3,2");
13411592Srgrimes
13421592Srgrimes		/*
13431592Srgrimes		 * Clear the flags.
13441592Srgrimes		 */
13451592Srgrimes		for (i = 0; i < NUM_THREADS; i++)
13461592Srgrimes			states[i].flags = 0;
13471592Srgrimes
13481592Srgrimes		/*
13491592Srgrimes		 * Test setup:
13501592Srgrimes		 *   Thread 2 - enter busy loop (SCHED_FIFO)
13511592Srgrimes		 *   Thread 4 - take mutex 0
13521592Srgrimes		 *   Thread 4 - priority change to same priority as thread 2
13531592Srgrimes		 *   Thread 4 - release mutex 0
13541592Srgrimes		 *
13551592Srgrimes		 * Expected results:
13561592Srgrimes		 *   Since thread 4 owns a priority mutex, it should be
13571592Srgrimes		 *   placed at the front of the run queue (for its new
13581592Srgrimes		 *   priority slot) when its priority is lowered to the
13591592Srgrimes		 *   same priority as thread 2.  If thread 4 did not own
13601592Srgrimes		 *   a priority mutex, then it would have been added to
13611592Srgrimes		 *   the end of the run queue and thread 2 would have
13621592Srgrimes		 *   executed until it blocked (because it's scheduling
13631592Srgrimes		 *   policy is SCHED_FIFO).
13641592Srgrimes		 *
13651592Srgrimes		 */
13661592Srgrimes		log ("    Inheritence test with change of priority - ");
13671592Srgrimes
13681592Srgrimes		/*
13691592Srgrimes		 * Change threads 2 and 4 scheduling policies to be
13701592Srgrimes		 * SCHED_FIFO.
13711592Srgrimes		 */
13721592Srgrimes		param.sched_priority = states[2].priority;
13731592Srgrimes		assert (pthread_setschedparam (states[2].tid, SCHED_FIFO,
13741592Srgrimes		    &param) == 0);
13751592Srgrimes		param.sched_priority = states[4].priority;
13761592Srgrimes		assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
13771592Srgrimes		    &param) == 0);
13781592Srgrimes
13791592Srgrimes		/*
13801592Srgrimes		 * Command thread 4 to take mutex 0.
13811592Srgrimes		 */
13821592Srgrimes		send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
13831592Srgrimes		sleep (1);
13841592Srgrimes
13851592Srgrimes		/*
13861592Srgrimes		 * Command thread 2 to enter busy loop.
13871592Srgrimes		 */
13881592Srgrimes		send_cmd (2, CMD_BUSY_LOOP);
13891592Srgrimes		sleep (1);	/* Allow command to be received. */
13901592Srgrimes
13911592Srgrimes		/*
13921592Srgrimes		 * Command thread 4 to enter busy loop.
13931592Srgrimes		 */
13941592Srgrimes		send_cmd (4, CMD_BUSY_LOOP);
13951592Srgrimes		sleep (1);	/* Allow command to be received. */
13961592Srgrimes
13971592Srgrimes		/* Have threads 2 and 4 report themselves. */
13981592Srgrimes		states[2].flags = FLAGS_REPORT_WAITMUTEX;
13991592Srgrimes		states[4].flags = FLAGS_REPORT_WAITMUTEX;
14001592Srgrimes
14011592Srgrimes		/* Change the priority of thread 4. */
14021592Srgrimes		param.sched_priority = states[2].priority;
14031592Srgrimes		assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
14041592Srgrimes		    &param) == 0);
14051592Srgrimes		sleep (5);
14061592Srgrimes		check_run_order ("4,2");
14071592Srgrimes
14081592Srgrimes		/* Clear the flags */
14091592Srgrimes		states[2].flags = 0;
14101592Srgrimes		states[4].flags = 0;
14111592Srgrimes
14121592Srgrimes		/* Reset the policies. */
14131592Srgrimes		param.sched_priority = states[2].priority;
14141592Srgrimes		assert (pthread_setschedparam (states[2].tid, SCHED_RR,
14151592Srgrimes		    &param) == 0);
14161592Srgrimes		param.sched_priority = states[4].priority;
14171592Srgrimes		assert (pthread_setschedparam (states[4].tid, SCHED_RR,
14181592Srgrimes		    &param) == 0);
14191592Srgrimes
14201592Srgrimes		send_cmd (4, CMD_RELEASE_MUTEX);
14211592Srgrimes		sleep (1);
14221592Srgrimes
14231592Srgrimes		/* Destroy the mutexes. */
14241592Srgrimes		for (i = 0; i < 3; i++)
14251592Srgrimes			assert (pthread_mutex_destroy (&m[i]) == 0);
14261592Srgrimes	}
14271592Srgrimes}
14281592Srgrimes
14291592Srgrimes
14301592Srgrimesint main (int argc, char *argv[])
14311592Srgrimes{
14321592Srgrimes	pthread_mutexattr_t mattr;
14331592Srgrimes	pthread_condattr_t cattr;
14341592Srgrimes	pthread_attr_t	pattr;
14351592Srgrimes	int		i, policy, main_prio;
14361592Srgrimes	void *		exit_status;
14371592Srgrimes	sigset_t	mask;
14381592Srgrimes	struct sigaction act;
14391592Srgrimes	struct sched_param param;
14401592Srgrimes
14411592Srgrimes	logfile = stdout;
14421592Srgrimes
14431592Srgrimes	assert (pthread_getschedparam (pthread_self (), &policy, &param) == 0);
14441592Srgrimes	main_prio = param.sched_priority;
14451592Srgrimes
14461592Srgrimes	/* Setupt our signal mask. */
14471592Srgrimes	sigfillset (&mask);
14481592Srgrimes	sigdelset (&mask, SIGINT);
14491592Srgrimes	sigprocmask (SIG_SETMASK, &mask, NULL);
14501592Srgrimes
14511592Srgrimes	/* Install a signal handler for SIGINT */
14521592Srgrimes	sigemptyset (&act.sa_mask);
14531592Srgrimes	sigaddset (&act.sa_mask, SIGINT);
14541592Srgrimes	act.sa_handler = sighandler;
14551592Srgrimes	act.sa_flags = SA_RESTART;
14561592Srgrimes	sigaction (SIGINT, &act, NULL);
14571592Srgrimes
14581592Srgrimes	/*
14591592Srgrimes	 * Initialize the thread attribute.
14601592Srgrimes	 */
14611592Srgrimes	assert (pthread_attr_init (&pattr) == 0);
14621592Srgrimes	assert (pthread_attr_setdetachstate (&pattr,
14631592Srgrimes	    PTHREAD_CREATE_JOINABLE) == 0);
14641592Srgrimes
14651592Srgrimes	/*
14661592Srgrimes	 * Initialize and create the waiter and condvar mutexes.
14671592Srgrimes	 */
14681592Srgrimes	assert (pthread_mutexattr_init (&mattr) == 0);
14691592Srgrimes	assert (pthread_mutex_init (&waiter_mutex, &mattr) == 0);
14701592Srgrimes	assert (pthread_mutex_init (&cond_mutex, &mattr) == 0);
14711592Srgrimes
14721592Srgrimes	/*
14731592Srgrimes	 * Initialize and create a condition variable.
14741592Srgrimes	 */
14751592Srgrimes	assert (pthread_condattr_init (&cattr) == 0);
14761592Srgrimes	assert (pthread_cond_init (&cond_var, &cattr) == 0);
14771592Srgrimes
14781592Srgrimes	/* Create a pipe to catch the results of thread wakeups. */
14791592Srgrimes	assert (pipe (pipefd) == 0);
14801592Srgrimes
14811592Srgrimes#ifdef DEBUG
14821592Srgrimes	assert (pthread_switch_add_np (kern_switch) == 0);
14831592Srgrimes#endif
148463350Sdes
148563350Sdes	/*
148663350Sdes	 * Create the waiting threads.
14871592Srgrimes	 */
14881592Srgrimes	for (i = 0; i < NUM_THREADS; i++) {
14891592Srgrimes		assert (pthread_cond_init (&states[i].cond_var, &cattr) == 0);
14901592Srgrimes		states[i].id = (u_int8_t) i;  /* NUM_THREADS must be <= 256 */
14911592Srgrimes		states[i].status = 0;
14921592Srgrimes		states[i].cmd.cmd_id = CMD_NONE;
14931592Srgrimes		states[i].flags = 0;	/* No flags yet. */
14941592Srgrimes		assert (pthread_create (&states[i].tid, &pattr, waiter,
14951592Srgrimes		    (void *) &states[i]) == 0);
14961592Srgrimes		param.sched_priority = main_prio - 10 + i;
14971592Srgrimes		states[i].priority = param.sched_priority;
14981592Srgrimes		assert (pthread_setschedparam (states[i].tid, SCHED_OTHER,
14991592Srgrimes		    &param) == 0);
15001592Srgrimes#if defined(_LIBC_R_)
150163350Sdes		{
150263350Sdes			char buf[30];
150363350Sdes
150463350Sdes			snprintf (buf, sizeof(buf), "waiter_%d", i);
150563350Sdes			pthread_set_name_np (states[i].tid, buf);
15061592Srgrimes		}
15071592Srgrimes#endif
15081592Srgrimes	}
15091592Srgrimes
15101592Srgrimes	/* Allow the threads to start. */
15111592Srgrimes	sleep (1);
15121592Srgrimes	log_trace ("Done creating threads.\n");
15131592Srgrimes
15141592Srgrimes	log ("\n");
15151592Srgrimes	mutex_init_test ();
15161592Srgrimes	log ("\n");
15171592Srgrimes	mutex_destroy_test ();
15181592Srgrimes	log ("\n");
15191592Srgrimes	mutex_lock_test ();
15201592Srgrimes	log ("\n");
15211592Srgrimes	mutex_unlock_test ();
15221592Srgrimes	log ("\n");
15231592Srgrimes	queueing_order_test ();
15241592Srgrimes	log ("\n");
152556668Sshin	mutex_prioinherit_test ();
152656668Sshin	log ("\n");
152756668Sshin	mutex_prioceiling_test ();
152856668Sshin	log ("\n");
152956668Sshin
153056668Sshin	log ("Total tests %d, passed %d, failed %d\n",
153156668Sshin	    total, pass_count, error_count);
153256668Sshin
153356668Sshin	/* Set the done flag and signal the threads to exit. */
153456668Sshin	log_trace ("Setting done flag.\n");
153556668Sshin	done = 1;
153656668Sshin
153756668Sshin	/*
153856668Sshin	 * Wait for the threads to finish.
153956668Sshin	 */
154056668Sshin	log_trace ("Trying to join threads.\n");
154156668Sshin	for (i = 0; i < NUM_THREADS; i++) {
154256668Sshin		send_cmd (i, CMD_NONE);
154356668Sshin		assert (pthread_join (states[i].tid, &exit_status) == 0);
154456668Sshin	}
154556668Sshin
154656668Sshin	/* Clean up after ourselves. */
154756668Sshin	close (pipefd[0]);
154856668Sshin	close (pipefd[1]);
154956668Sshin
155056668Sshin	if (error_count != 0)
155156668Sshin		exit (EX_OSERR);	/* any better ideas??? */
155256668Sshin	else
155356668Sshin		exit (EX_OK);
155456668Sshin}
155556668Sshin