159612Sjasone/*
259612Sjasone * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com>
359612Sjasone * All rights reserved.
459612Sjasone *
559612Sjasone * Redistribution and use in source and binary forms, with or without
659612Sjasone * modification, are permitted provided that the following conditions
759612Sjasone * are met:
859612Sjasone * 1. Redistributions of source code must retain the above copyright
959612Sjasone *    notice, this list of conditions and the following disclaimer.
1059612Sjasone * 2. Redistributions in binary form must reproduce the above copyright
1159612Sjasone *    notice, this list of conditions and the following disclaimer in the
1259612Sjasone *    documentation and/or other materials provided with the distribution.
1359612Sjasone * 3. All advertising materials mentioning features or use of this software
1459612Sjasone *    must display the following acknowledgement:
1559612Sjasone *	This product includes software developed by Daniel M. Eischen.
1659612Sjasone * 4. Neither the name of the author nor the names of any co-contributors
1759612Sjasone *    may be used to endorse or promote products derived from this software
1859612Sjasone *    without specific prior written permission.
1959612Sjasone *
2059612Sjasone * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS''
2159612Sjasone * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2259612Sjasone * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2359612Sjasone * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2459612Sjasone * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2559612Sjasone * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2659612Sjasone * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2759612Sjasone * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2859612Sjasone * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2959612Sjasone * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3059612Sjasone * SUCH DAMAGE.
3159612Sjasone *
3259612Sjasone * $FreeBSD$
3359612Sjasone */
34152599Smarcel
35152599Smarcel#include <sys/time.h>
36152599Smarcel#include <sys/ioctl.h>
3759612Sjasone#include <stdlib.h>
3859612Sjasone#include <unistd.h>
3959612Sjasone#include <assert.h>
4059612Sjasone#include <errno.h>
4159612Sjasone#include <sched.h>
4259612Sjasone#include <signal.h>
4359612Sjasone#include <stdarg.h>
4459612Sjasone#include <stdio.h>
4559612Sjasone#include <string.h>
4659612Sjasone#include <sysexits.h>
47152599Smarcel#include "pthread.h"
4859612Sjasone
4959612Sjasone#if defined(_LIBC_R_)
5059612Sjasone#include <pthread_np.h>
5159612Sjasone#endif
5259612Sjasone
5359612Sjasone#ifndef NELEMENTS
5459612Sjasone#define NELEMENTS(arr)	(sizeof (arr) / sizeof (arr[0]))
5559612Sjasone#endif
5659612Sjasone
5759612Sjasone#ifndef NUM_THREADS
5859612Sjasone#define NUM_THREADS	10
5959612Sjasone#endif
6059612Sjasone
6159612Sjasone#define MAX_THREAD_CMDS	10
6259612Sjasone
6381975Skrisstatic void log_error(const char *, ...) __printflike(1, 2);
6481975Skrisstatic void log_trace (const char *, ...) __printflike(1, 2);
6581975Skrisstatic void log (const char *, ...) __printflike(1, 2);
6659612Sjasone
6759612Sjasone/*------------------------------------------------------------
6859612Sjasone * Types
6959612Sjasone *----------------------------------------------------------*/
7059612Sjasone
7159612Sjasonetypedef enum {
7259612Sjasone	STAT_INITIAL,		/* initial state */
7359612Sjasone	STAT_WAITCONDVAR,	/* waiting for condition variable signal */
7459612Sjasone	STAT_WAITMUTEX		/* waiting for mutex lock */
7559612Sjasone} thread_status_t;
7659612Sjasone
7759612Sjasonetypedef enum {
7859612Sjasone	FLAGS_REPORT_WAITCONDMUTEX	= 0x01,
7959612Sjasone	FLAGS_REPORT_WAITCONDVAR	= 0x02,
8059612Sjasone	FLAGS_REPORT_WAITMUTEX		= 0x04,
8159612Sjasone	FLAGS_REPORT_BUSY_LOOP		= 0x08,
8259612Sjasone	FLAGS_IS_BUSY			= 0x10,
8359612Sjasone	FLAGS_WAS_BUSY			= 0x20
8459612Sjasone} thread_flags_t;
8559612Sjasone
8659612Sjasonetypedef enum {
8759612Sjasone	CMD_NONE,
8859612Sjasone	CMD_TAKE_MUTEX,
8959612Sjasone	CMD_RELEASE_MUTEX,
9059612Sjasone	CMD_WAIT_FOR_SIGNAL,
9159612Sjasone	CMD_BUSY_LOOP,
9259612Sjasone	CMD_PROTECTED_OP,
9359612Sjasone	CMD_RELEASE_ALL
9459612Sjasone} thread_cmd_id_t;
9559612Sjasone
9659612Sjasonetypedef struct {
9759612Sjasone	thread_cmd_id_t	cmd_id;
9859612Sjasone	pthread_mutex_t	*mutex;
9959612Sjasone	pthread_cond_t	*cond;
10059612Sjasone} thread_cmd_t;
10159612Sjasone
10259612Sjasonetypedef struct {
10359612Sjasone	pthread_cond_t	cond_var;
10459612Sjasone	thread_status_t	status;
10559612Sjasone	thread_cmd_t	cmd;
10659612Sjasone	int		flags;
10759612Sjasone	int		priority;
10859612Sjasone	int		ret;
10959612Sjasone	pthread_t	tid;
11059612Sjasone	u_int8_t	id;
11159612Sjasone} thread_state_t;
11259612Sjasone
11359612Sjasonetypedef enum {
11459612Sjasone	M_POSIX,
11559612Sjasone	M_SS2_DEFAULT,
11659612Sjasone	M_SS2_ERRORCHECK,
11759612Sjasone	M_SS2_NORMAL,
11859612Sjasone	M_SS2_RECURSIVE
11959612Sjasone} mutex_kind_t;
12059612Sjasone
12159612Sjasone
12259612Sjasone/*------------------------------------------------------------
12359612Sjasone * Constants
12459612Sjasone *----------------------------------------------------------*/
12559612Sjasone
12659612Sjasoneconst char *protocol_strs[] = {
12759612Sjasone	"PTHREAD_PRIO_NONE",
12859612Sjasone	"PTHREAD_PRIO_INHERIT",
12959612Sjasone	"PTHREAD_PRIO_PROTECT"
13059612Sjasone};
13159612Sjasone
13259612Sjasoneconst int protocols[] = {
13359612Sjasone	PTHREAD_PRIO_NONE,
13459612Sjasone	PTHREAD_PRIO_INHERIT,
13559612Sjasone	PTHREAD_PRIO_PROTECT
13659612Sjasone};
13759612Sjasone
13859612Sjasoneconst char *mutextype_strs[] = {
13959612Sjasone	"POSIX (type not specified)",
14059612Sjasone	"SS2 PTHREAD_MUTEX_DEFAULT",
14159612Sjasone	"SS2 PTHREAD_MUTEX_ERRORCHECK",
14259612Sjasone	"SS2 PTHREAD_MUTEX_NORMAL",
14359612Sjasone	"SS2 PTHREAD_MUTEX_RECURSIVE"
14459612Sjasone};
14559612Sjasone
14659612Sjasoneconst int mutex_types[] = {
14759612Sjasone	0,				/* M_POSIX		*/
14859612Sjasone	PTHREAD_MUTEX_DEFAULT,		/* M_SS2_DEFAULT	*/
14959612Sjasone	PTHREAD_MUTEX_ERRORCHECK,	/* M_SS2_ERRORCHECK	*/
15059612Sjasone	PTHREAD_MUTEX_NORMAL,		/* M_SS2_NORMAL		*/
15159612Sjasone	PTHREAD_MUTEX_RECURSIVE		/* M_SS2_RECURSIVE	*/
15259612Sjasone};
15359612Sjasone
15459612Sjasone
15559612Sjasone/*------------------------------------------------------------
15659612Sjasone * Objects
15759612Sjasone *----------------------------------------------------------*/
15859612Sjasone
15959612Sjasonestatic int		done = 0;
16059612Sjasonestatic int		trace_enabled = 0;
16159612Sjasonestatic int		use_global_condvar = 0;
16259612Sjasonestatic thread_state_t	states[NUM_THREADS];
16359612Sjasonestatic int		pipefd[2];
16459612Sjasone
16559612Sjasonestatic pthread_mutex_t	waiter_mutex;
16659612Sjasonestatic pthread_mutex_t	cond_mutex;
16759612Sjasonestatic pthread_cond_t	cond_var;
16859612Sjasone
16999239Sdeischenstatic FILE *logfile;
17059612Sjasonestatic int error_count = 0, pass_count = 0, total = 0;
17159612Sjasone
17259612Sjasone
17359612Sjasone/*------------------------------------------------------------
17459612Sjasone * Prototypes
17559612Sjasone *----------------------------------------------------------*/
17659612Sjasoneextern char *strtok_r(char *str, const char *sep, char **last);
17759612Sjasone
17859612Sjasone
17959612Sjasone/*------------------------------------------------------------
18059612Sjasone * Functions
18159612Sjasone *----------------------------------------------------------*/
18259612Sjasone
183152599Smarcel#if defined(_LIBC_R_) && defined(DEBUG)
18459612Sjasonestatic void
18559612Sjasonekern_switch (pthread_t pthread_out, pthread_t pthread_in)
18659612Sjasone{
18759612Sjasone	if (pthread_out != NULL)
188152599Smarcel		printf ("Swapping out thread 0x%lx, ", (long) pthread_out);
18959612Sjasone	else
19059612Sjasone		printf ("Swapping out kernel thread, ");
19159612Sjasone
19259612Sjasone	if (pthread_in != NULL)
193152599Smarcel		printf ("swapping in thread 0x%lx\n", (long) pthread_in);
19459612Sjasone	else
19559612Sjasone		printf ("swapping in kernel thread.\n");
19659612Sjasone}
19759612Sjasone#endif
19859612Sjasone
19959612Sjasone
20059612Sjasonestatic void
20159612Sjasonelog_error (const char *fmt, ...)
20259612Sjasone{
20359612Sjasone	va_list ap;
20459612Sjasone
20559612Sjasone	va_start (ap, fmt);
20659612Sjasone	fprintf (logfile, "FAIL: ");
20759612Sjasone	vfprintf (logfile, fmt, ap);
20859612Sjasone	error_count = error_count + 1;
20959612Sjasone	total = total + 1;
21059612Sjasone}
21159612Sjasone
21259612Sjasone
21359612Sjasonestatic void
21459612Sjasonelog_pass (void)
21559612Sjasone{
21659612Sjasone	fprintf (logfile, "PASS\n");
21759612Sjasone	pass_count = pass_count + 1;
21859612Sjasone	total = total + 1;
21959612Sjasone}
22059612Sjasone
22159612Sjasone
22259612Sjasonestatic void
22359612Sjasonelog_trace (const char *fmt, ...)
22459612Sjasone{
22559612Sjasone	va_list ap;
22659612Sjasone
22759612Sjasone	if (trace_enabled) {
22859612Sjasone		va_start (ap, fmt);
22959612Sjasone		vfprintf (logfile, fmt, ap);
23059612Sjasone	}
23159612Sjasone}
23259612Sjasone
23359612Sjasone
23459612Sjasonestatic void
23559612Sjasonelog (const char *fmt, ...)
23659612Sjasone{
23759612Sjasone	va_list ap;
23859612Sjasone
23959612Sjasone	va_start (ap, fmt);
24059612Sjasone	vfprintf (logfile, fmt, ap);
24159612Sjasone}
24259612Sjasone
24359612Sjasone
24459612Sjasonestatic void
24559612Sjasonecheck_result (int expected, int actual)
24659612Sjasone{
24759612Sjasone	if (expected != actual)
24859612Sjasone		log_error ("expected %d, returned %d\n", expected, actual);
24959612Sjasone	else
25059612Sjasone		log_pass ();
25159612Sjasone}
25259612Sjasone
25359612Sjasone
25459612Sjasone/*
25559612Sjasone * Check to see that the threads ran in the specified order.
25659612Sjasone */
25759612Sjasonestatic void
25859612Sjasonecheck_run_order (char *order)
25959612Sjasone{
26059612Sjasone	const char *sep = ":,";
26159612Sjasone	char *tok, *last, *idstr, *endptr;
26259612Sjasone	int expected_id, bytes, count = 0, errors = 0;
26359612Sjasone	u_int8_t id;
26459612Sjasone
26559612Sjasone	assert ((tok = (char *) malloc (strlen(order) + 1)) != NULL);
26659612Sjasone	strcpy (tok, order);	/* tok has to be larger than order */
26759612Sjasone	assert (ioctl (pipefd[0], FIONREAD, &bytes) == 0);
26859612Sjasone	log_trace ("%d bytes read from FIFO.\n", bytes);
26959612Sjasone
27059612Sjasone	for (idstr = strtok_r (tok, sep, &last);
27159612Sjasone	     (idstr != NULL) && (count < bytes);
27259612Sjasone	     idstr = strtok_r (NULL, sep, &last)) {
27359612Sjasone
27459612Sjasone		/* Get the expected id: */
27559612Sjasone		expected_id = (int) strtol (idstr, &endptr, 10);
27659612Sjasone		assert ((endptr != NULL) && (*endptr == '\0'));
27759612Sjasone
27859612Sjasone		/* Read the actual id from the pipe: */
27959612Sjasone		assert (read (pipefd[0], &id, sizeof (id)) == sizeof (id));
28059612Sjasone		count = count + sizeof (id);
28159612Sjasone
28259612Sjasone		if (id != expected_id) {
28359612Sjasone			log_trace ("Thread %d ran out of order.\n", id);
28459612Sjasone			errors = errors + 1;
28559612Sjasone		}
28659612Sjasone		else {
28759612Sjasone			log_trace ("Thread %d at priority %d reporting.\n",
28859612Sjasone			    (int) id, states[id].priority);
28959612Sjasone		}
29059612Sjasone	}
29159612Sjasone
29259612Sjasone	if (count < bytes) {
29359612Sjasone		/* Clear the pipe: */
29459612Sjasone		while (count < bytes) {
29559612Sjasone			read (pipefd[0], &id, sizeof (id));
29659612Sjasone			count = count + 1;
29759612Sjasone			errors = errors + 1;
29859612Sjasone		}
29959612Sjasone	}
30059612Sjasone	else if (bytes < count)
30159612Sjasone		errors = errors + count - bytes;
30259612Sjasone
30359612Sjasone	if (errors == 0)
30459612Sjasone		log_pass ();
30559612Sjasone	else
30659612Sjasone		log_error ("%d threads ran out of order", errors);
30759612Sjasone}
30859612Sjasone
30959612Sjasone
31059612Sjasonestatic void *
31159612Sjasonewaiter (void *arg)
31259612Sjasone{
31359612Sjasone	thread_state_t	*statep = (thread_state_t *) arg;
31459612Sjasone	pthread_mutex_t	*held_mutex[MAX_THREAD_CMDS];
31559612Sjasone	int 		held_mutex_owned[MAX_THREAD_CMDS];
31659612Sjasone	sigset_t	mask;
31759612Sjasone	struct timeval	tv1, tv2;
31859612Sjasone	thread_cmd_t	cmd;
31959612Sjasone	int 		i, mutex_count = 0;
32059612Sjasone
32159612Sjasone	statep->status = STAT_INITIAL;
32259612Sjasone
32359612Sjasone	/* Block all signals except for interrupt.*/
32459612Sjasone	sigfillset (&mask);
32559612Sjasone	sigdelset (&mask, SIGINT);
32659612Sjasone	sigprocmask (SIG_BLOCK, &mask, NULL);
32759612Sjasone
32859612Sjasone	while (done == 0) {
32959612Sjasone		/* Wait for signal from the main thread to continue. */
33059612Sjasone		statep->status = STAT_WAITMUTEX;
33159612Sjasone		log_trace ("Thread %d: locking cond_mutex.\n",
33259612Sjasone		    (int) statep->id);
33359612Sjasone		pthread_mutex_lock (&cond_mutex);
33459612Sjasone
33559612Sjasone		/* Do we report our status. */
33659612Sjasone		if (statep->flags & FLAGS_REPORT_WAITCONDMUTEX)
33759612Sjasone			write (pipefd[1], &statep->id, sizeof (statep->id));
33859612Sjasone		log_trace ("Thread %d: waiting for cond_var.\n",
33959612Sjasone		    (int) statep->id);
34059612Sjasone
34159612Sjasone		/* Wait for a command. */
34259612Sjasone		statep->status = STAT_WAITCONDVAR;
34359612Sjasone
34459612Sjasone		/*
34559612Sjasone		 * The threads are allowed commanded to wait either on
34659612Sjasone		 * their own unique condition variable (so they may be
34759612Sjasone		 * separately signaled) or on one global condition variable
34859612Sjasone		 * (so they may be signaled together).
34959612Sjasone		 */
35059612Sjasone		if (use_global_condvar != 0)
35159612Sjasone			pthread_cond_wait (&cond_var, &cond_mutex);
35259612Sjasone		else
35359612Sjasone			pthread_cond_wait (&statep->cond_var, &cond_mutex);
35459612Sjasone
35559612Sjasone		/* Do we report our status? */
35659612Sjasone		if (statep->flags & FLAGS_REPORT_WAITCONDVAR) {
35759612Sjasone			write (pipefd[1], &statep->id, sizeof (statep->id));
35899239Sdeischen			log_trace ("Thread %d: wrote to pipe.\n",
35959612Sjasone			    (int) statep->id);
36059612Sjasone		}
36159612Sjasone		log_trace ("Thread %d: received cond_var signal.\n",
36259612Sjasone		    (int) statep->id);
36359612Sjasone
36459612Sjasone		/* Get a copy of the command before releasing the mutex. */
36559612Sjasone		cmd = statep->cmd;
36659612Sjasone
36759612Sjasone		/* Clear the command after copying it. */
36859612Sjasone		statep->cmd.cmd_id = CMD_NONE;
36959612Sjasone
37059612Sjasone		/* Unlock the condition variable mutex. */
37159612Sjasone		assert (pthread_mutex_unlock (&cond_mutex) == 0);
37259612Sjasone
37359612Sjasone		/* Peform the command.*/
37459612Sjasone		switch (cmd.cmd_id) {
37559612Sjasone		case CMD_TAKE_MUTEX:
37659612Sjasone			statep->ret = pthread_mutex_lock (cmd.mutex);
37759612Sjasone			if (statep->ret == 0) {
37859612Sjasone				assert (mutex_count < sizeof (held_mutex));
37959612Sjasone				held_mutex[mutex_count] = cmd.mutex;
38059612Sjasone				held_mutex_owned[mutex_count] = 1;
38159612Sjasone				mutex_count++;
38259612Sjasone			}
38359612Sjasone			else {
38459612Sjasone				held_mutex_owned[mutex_count] = 0;
38559612Sjasone				log_trace ("Thread id %d unable to lock mutex, "
38659612Sjasone				    "error = %d\n", (int) statep->id,
38759612Sjasone				    statep->ret);
38859612Sjasone			}
38959612Sjasone			break;
39059612Sjasone
39159612Sjasone		case CMD_RELEASE_MUTEX:
39259612Sjasone			assert ((mutex_count <= sizeof (held_mutex)) &&
39359612Sjasone			    (mutex_count > 0));
39459612Sjasone			mutex_count--;
39559612Sjasone			if (held_mutex_owned[mutex_count] != 0)
39659612Sjasone				assert (pthread_mutex_unlock
39759612Sjasone				    (held_mutex[mutex_count]) == 0);
39859612Sjasone			break;
39959612Sjasone
40059612Sjasone		case CMD_WAIT_FOR_SIGNAL:
40159612Sjasone			assert (pthread_mutex_lock (cmd.mutex) == 0);
40259612Sjasone			assert (pthread_cond_wait (cmd.cond, cmd.mutex) == 0);
40359612Sjasone			assert (pthread_mutex_unlock (cmd.mutex) == 0);
40459612Sjasone			break;
40559612Sjasone
40659612Sjasone		case CMD_BUSY_LOOP:
40759612Sjasone			log_trace ("Thread %d: Entering busy loop.\n",
40859612Sjasone			    (int) statep->id);
40959612Sjasone			/* Spin for 15 seconds. */
41059612Sjasone			assert (gettimeofday (&tv2, NULL) == 0);
41159612Sjasone			tv1.tv_sec = tv2.tv_sec + 5;
41259612Sjasone			tv1.tv_usec = tv2.tv_usec;
41359612Sjasone			statep->flags |= FLAGS_IS_BUSY;
41459612Sjasone			while (timercmp (&tv2, &tv1,<)) {
41559612Sjasone				assert (gettimeofday (&tv2, NULL) == 0);
41659612Sjasone			}
41759612Sjasone			statep->flags &= ~FLAGS_IS_BUSY;
41859612Sjasone			statep->flags |= FLAGS_WAS_BUSY;
41959612Sjasone
42059612Sjasone			/* Do we report our status? */
42159612Sjasone			if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
42259612Sjasone				write (pipefd[1], &statep->id,
42359612Sjasone				    sizeof (statep->id));
42459612Sjasone
42559612Sjasone			log_trace ("Thread %d: Leaving busy loop.\n",
42659612Sjasone			    (int) statep->id);
42759612Sjasone			break;
42859612Sjasone
42959612Sjasone		case CMD_PROTECTED_OP:
43059612Sjasone			assert (pthread_mutex_lock (cmd.mutex) == 0);
43159612Sjasone			statep->flags |= FLAGS_WAS_BUSY;
43259612Sjasone			/* Do we report our status? */
43359612Sjasone			if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
43459612Sjasone				write (pipefd[1], &statep->id,
43559612Sjasone				    sizeof (statep->id));
43659612Sjasone
43759612Sjasone			assert (pthread_mutex_unlock (cmd.mutex) == 0);
43859612Sjasone			break;
43959612Sjasone
44059612Sjasone		case CMD_RELEASE_ALL:
44159612Sjasone			assert ((mutex_count <= sizeof (held_mutex)) &&
44259612Sjasone			    (mutex_count > 0));
44359612Sjasone			for (i = mutex_count - 1; i >= 0; i--) {
44459612Sjasone				if (held_mutex_owned[i] != 0)
44559612Sjasone					assert (pthread_mutex_unlock
44659612Sjasone					    (held_mutex[i]) == 0);
44759612Sjasone			}
44859612Sjasone			mutex_count = 0;
44959612Sjasone			break;
45059612Sjasone
45159612Sjasone		case CMD_NONE:
45259612Sjasone		default:
45359612Sjasone			break;
45459612Sjasone		}
45559612Sjasone
45659612Sjasone		/* Wait for the big giant waiter lock. */
45759612Sjasone		statep->status = STAT_WAITMUTEX;
45859612Sjasone		log_trace ("Thread %d: waiting for big giant lock.\n",
45959612Sjasone		    (int) statep->id);
46059612Sjasone		pthread_mutex_lock (&waiter_mutex);
46159612Sjasone		if (statep->flags & FLAGS_REPORT_WAITMUTEX)
46259612Sjasone			write (pipefd[1], &statep->id, sizeof (statep->id));
46359612Sjasone		log_trace ("Thread %d: got big giant lock.\n",
46459612Sjasone		    (int) statep->id);
46559612Sjasone		statep->status = STAT_INITIAL;
46659612Sjasone		pthread_mutex_unlock (&waiter_mutex);
46759612Sjasone	}
46859612Sjasone
469152599Smarcel	log_trace ("Thread %ld: Exiting thread 0x%lx\n", (long) statep->id,
470152599Smarcel	    (long) pthread_self());
47159612Sjasone	pthread_exit (arg);
47259612Sjasone	return (NULL);
47359612Sjasone}
47459612Sjasone
47559612Sjasone
47659612Sjasonestatic void *
47759612Sjasonelock_twice (void *arg)
47859612Sjasone{
47959612Sjasone	thread_state_t	*statep = (thread_state_t *) arg;
48059612Sjasone	sigset_t	mask;
48159612Sjasone
48259612Sjasone	statep->status = STAT_INITIAL;
48359612Sjasone
48459612Sjasone	/* Block all signals except for interrupt.*/
48559612Sjasone	sigfillset (&mask);
48659612Sjasone	sigdelset (&mask, SIGINT);
48759612Sjasone	sigprocmask (SIG_BLOCK, &mask, NULL);
48859612Sjasone
48959612Sjasone	/* Wait for a signal to continue. */
49059612Sjasone	log_trace ("Thread %d: locking cond_mutex.\n", (int) statep->id);
49159612Sjasone	pthread_mutex_lock (&cond_mutex);
49259612Sjasone
49359612Sjasone	log_trace ("Thread %d: waiting for cond_var.\n", (int) statep->id);
49459612Sjasone	statep->status = STAT_WAITCONDVAR;
49559612Sjasone	pthread_cond_wait (&cond_var, &cond_mutex);
49659612Sjasone
49759612Sjasone	log_trace ("Thread %d: received cond_var signal.\n", (int) statep->id);
49859612Sjasone
49959612Sjasone	/* Unlock the condition variable mutex. */
50059612Sjasone	assert (pthread_mutex_unlock (&cond_mutex) == 0);
50159612Sjasone
50259612Sjasone	statep->status = STAT_WAITMUTEX;
50359612Sjasone	/* Lock the mutex once. */
50459612Sjasone	assert (pthread_mutex_lock (statep->cmd.mutex) == 0);
50559612Sjasone
50659612Sjasone	/* Lock it again and capture the error. */
50759612Sjasone	statep->ret = pthread_mutex_lock (statep->cmd.mutex);
50859612Sjasone	statep->status = 0;
50959612Sjasone
51059612Sjasone	assert (pthread_mutex_unlock (statep->cmd.mutex) == 0);
51159612Sjasone
51259612Sjasone	/* Unlock it again if it is locked recursively. */
51359612Sjasone	if (statep->ret == 0)
51459612Sjasone		pthread_mutex_unlock (statep->cmd.mutex);
51559612Sjasone
516152599Smarcel	log_trace ("Thread %ld: Exiting thread 0x%lx\n", (long) statep->id,
517152599Smarcel	    (long) pthread_self());
51859612Sjasone	pthread_exit (arg);
51959612Sjasone	return (NULL);
52059612Sjasone}
52159612Sjasone
52259612Sjasone
52359612Sjasonestatic void
52459612Sjasonesighandler (int signo)
52559612Sjasone{
526152599Smarcel	log ("Signal handler caught signal %d, thread id 0x%lx\n",
527152599Smarcel	    signo, (long) pthread_self());
52859612Sjasone
52959612Sjasone	if (signo == SIGINT)
53059612Sjasone		done = 1;
53159612Sjasone}
53259612Sjasone
53359612Sjasone
53459612Sjasonestatic void
53559612Sjasonesend_cmd (int id, thread_cmd_id_t cmd)
53659612Sjasone{
53759612Sjasone	assert (pthread_mutex_lock (&cond_mutex) == 0);
53859612Sjasone	assert (states[id].status == STAT_WAITCONDVAR);
53959612Sjasone	states[id].cmd.cmd_id = cmd;
54059612Sjasone	states[id].cmd.mutex = NULL;
54159612Sjasone	states[id].cmd.cond = NULL;
54259612Sjasone	/* Clear the busy flags. */
54359612Sjasone	states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
54459612Sjasone	assert (pthread_cond_signal (&states[id].cond_var) == 0);
54559612Sjasone	assert (pthread_mutex_unlock (&cond_mutex) == 0);
54659612Sjasone}
54759612Sjasone
54859612Sjasone
54959612Sjasonestatic void
55059612Sjasonesend_mutex_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m)
55159612Sjasone{
55259612Sjasone	assert (pthread_mutex_lock (&cond_mutex) == 0);
55359612Sjasone	assert (states[id].status == STAT_WAITCONDVAR);
55459612Sjasone	states[id].cmd.cmd_id = cmd;
55559612Sjasone	states[id].cmd.mutex = m;
55659612Sjasone	states[id].cmd.cond = NULL;
55759612Sjasone	/* Clear the busy flags. */
55859612Sjasone	states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
55959612Sjasone	assert (pthread_cond_signal (&states[id].cond_var) == 0);
56059612Sjasone	assert (pthread_mutex_unlock (&cond_mutex) == 0);
56159612Sjasone}
56259612Sjasone
56359612Sjasone
56459612Sjasonestatic void
56559612Sjasonesend_mutex_cv_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m,
56659612Sjasone    pthread_cond_t *cv)
56759612Sjasone{
56859612Sjasone	assert (pthread_mutex_lock (&cond_mutex) == 0);
56959612Sjasone	assert (states[id].status == STAT_WAITCONDVAR);
57059612Sjasone	states[id].cmd.cmd_id = cmd;
57159612Sjasone	states[id].cmd.mutex = m;
57259612Sjasone	states[id].cmd.cond = cv;
57359612Sjasone	/* Clear the busy flags. */
57459612Sjasone	states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
57559612Sjasone	assert (pthread_cond_signal (&states[id].cond_var) == 0);
57659612Sjasone	assert (pthread_mutex_unlock (&cond_mutex) == 0);
57759612Sjasone}
57859612Sjasone
57959612Sjasone
58059612Sjasonestatic void
58159612Sjasonemutex_init_test (void)
58259612Sjasone{
58359612Sjasone	pthread_mutexattr_t mattr;
58459612Sjasone	pthread_mutex_t	mutex;
58559612Sjasone	mutex_kind_t mkind;
58659612Sjasone	int mproto, ret;
58759612Sjasone
58859612Sjasone	/*
58959612Sjasone	 * Initialize a mutex attribute.
59059612Sjasone	 *
59159612Sjasone	 * pthread_mutexattr_init not tested for: ENOMEM
59259612Sjasone	 */
59359612Sjasone	assert (pthread_mutexattr_init (&mattr) == 0);
59459612Sjasone
59559612Sjasone	/*
59659612Sjasone	 * Initialize a mutex.
59759612Sjasone	 *
59859612Sjasone	 * pthread_mutex_init not tested for: EAGAIN ENOMEM EPERM EBUSY
59959612Sjasone	 */
60059612Sjasone	log ("Testing pthread_mutex_init\n");
60159612Sjasone	log ("--------------------------\n");
60259612Sjasone
60359612Sjasone	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
60459612Sjasone		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
60559612Sjasone			/* Initialize the mutex attribute. */
60659612Sjasone			assert (pthread_mutexattr_init (&mattr) == 0);
60759612Sjasone			assert (pthread_mutexattr_setprotocol (&mattr,
60859612Sjasone			    protocols[mproto]) == 0);
60959612Sjasone
61059612Sjasone			/*
61159612Sjasone			 * Ensure that the first mutex type is a POSIX
61259612Sjasone			 * compliant mutex.
61359612Sjasone			 */
61459612Sjasone			if (mkind != M_POSIX) {
61559612Sjasone				assert (pthread_mutexattr_settype (&mattr,
61659612Sjasone				    mutex_types[mkind]) == 0);
61759612Sjasone			}
61859612Sjasone
61959612Sjasone			log ("  Protocol %s, Type %s - ",
62059612Sjasone			    protocol_strs[mproto], mutextype_strs[mkind]);
62159612Sjasone			ret = pthread_mutex_init (&mutex, &mattr);
62259612Sjasone			check_result (/* expected */ 0, ret);
62359612Sjasone			assert (pthread_mutex_destroy (&mutex) == 0);
62459612Sjasone
62559612Sjasone			/*
62659612Sjasone			 * Destroy a mutex attribute.
62759612Sjasone			 *
62859612Sjasone			 * XXX - There should probably be a magic number
62959612Sjasone			 *       associated with a mutex attribute so that
63059612Sjasone			 *       destroy can be reasonably sure the attribute
63159612Sjasone			 *       is valid.
63259612Sjasone			 *
63359612Sjasone			 * pthread_mutexattr_destroy not tested for: EINVAL
63459612Sjasone			 */
63559612Sjasone			assert (pthread_mutexattr_destroy (&mattr) == 0);
63659612Sjasone		}
63759612Sjasone	}
63859612Sjasone}
63959612Sjasone
64059612Sjasone
64159612Sjasonestatic void
64259612Sjasonemutex_destroy_test (void)
64359612Sjasone{
64459612Sjasone	pthread_mutexattr_t mattr;
64559612Sjasone	pthread_mutex_t	mutex;
64659612Sjasone	pthread_condattr_t cattr;
64759612Sjasone	pthread_cond_t	cv;
64859612Sjasone	pthread_attr_t pattr;
64959612Sjasone	int mproto, ret;
65059612Sjasone	mutex_kind_t mkind;
65159612Sjasone	thread_state_t state;
65259612Sjasone
65359612Sjasone	/*
65459612Sjasone	 * Destroy a mutex.
65559612Sjasone	 *
65659612Sjasone	 * XXX - There should probably be a magic number associated
65759612Sjasone	 *       with a mutex so that destroy can be reasonably sure
65859612Sjasone	 *       the mutex is valid.
65959612Sjasone	 *
66059612Sjasone	 * pthread_mutex_destroy not tested for:
66159612Sjasone	 */
66259612Sjasone	log ("Testing pthread_mutex_destroy\n");
66359612Sjasone	log ("-----------------------------\n");
66459612Sjasone
66559612Sjasone	assert (pthread_attr_init (&pattr) == 0);
66659612Sjasone	assert (pthread_attr_setdetachstate (&pattr,
66759612Sjasone	    PTHREAD_CREATE_DETACHED) == 0);
66859612Sjasone	state.flags = 0;	/* No flags yet. */
66959612Sjasone
67059612Sjasone	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
67159612Sjasone		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
67259612Sjasone			/* Initialize the mutex attribute. */
67359612Sjasone			assert (pthread_mutexattr_init (&mattr) == 0);
67459612Sjasone			assert (pthread_mutexattr_setprotocol (&mattr,
67559612Sjasone			    protocols[mproto]) == 0);
67659612Sjasone
67759612Sjasone			/*
67859612Sjasone			 * Ensure that the first mutex type is a POSIX
67959612Sjasone			 * compliant mutex.
68059612Sjasone			 */
68159612Sjasone			if (mkind != M_POSIX) {
68259612Sjasone				assert (pthread_mutexattr_settype (&mattr,
68359612Sjasone				    mutex_types[mkind]) == 0);
68459612Sjasone			}
68559612Sjasone
68659612Sjasone			/* Create the mutex. */
68759612Sjasone			assert (pthread_mutex_init (&mutex, &mattr) == 0);
68859612Sjasone
68959612Sjasone			log ("  Protocol %s, Type %s\n",
69059612Sjasone			    protocol_strs[mproto], mutextype_strs[mkind]);
69159612Sjasone
69259612Sjasone			log ("    Destruction of unused mutex - ");
69359612Sjasone			assert (pthread_mutex_init (&mutex, &mattr) == 0);
69459612Sjasone			ret = pthread_mutex_destroy (&mutex);
69559612Sjasone			check_result (/* expected */ 0, ret);
69659612Sjasone
69759612Sjasone			log ("    Destruction of mutex locked by self - ");
69859612Sjasone			assert (pthread_mutex_init (&mutex, &mattr) == 0);
69959612Sjasone			assert (pthread_mutex_lock (&mutex) == 0);
70059612Sjasone			ret = pthread_mutex_destroy (&mutex);
70159612Sjasone			check_result (/* expected */ EBUSY, ret);
70259612Sjasone			assert (pthread_mutex_unlock (&mutex) == 0);
70359612Sjasone			assert (pthread_mutex_destroy (&mutex) == 0);
70459612Sjasone
70559612Sjasone			log ("    Destruction of mutex locked by another "
70659612Sjasone			    "thread - ");
70759612Sjasone			assert (pthread_mutex_init (&mutex, &mattr) == 0);
70859612Sjasone			send_mutex_cmd (0, CMD_TAKE_MUTEX, &mutex);
70959612Sjasone			sleep (1);
71059612Sjasone			ret = pthread_mutex_destroy (&mutex);
71159612Sjasone			check_result (/* expected */ EBUSY, ret);
71259612Sjasone			send_cmd (0, CMD_RELEASE_ALL);
71359612Sjasone			sleep (1);
71459612Sjasone			assert (pthread_mutex_destroy (&mutex) == 0);
71559612Sjasone
71659612Sjasone			log ("    Destruction of mutex while being used in "
71759612Sjasone			    "cond_wait - ");
71859612Sjasone			assert (pthread_mutex_init (&mutex, &mattr) == 0);
71959612Sjasone			assert (pthread_condattr_init (&cattr) == 0);
72059612Sjasone			assert (pthread_cond_init (&cv, &cattr) == 0);
72159612Sjasone			send_mutex_cv_cmd (0, CMD_WAIT_FOR_SIGNAL, &mutex, &cv);
72259612Sjasone			sleep (1);
72359612Sjasone			ret = pthread_mutex_destroy (&mutex);
72459612Sjasone			check_result (/* expected */ EBUSY, ret);
72559612Sjasone			pthread_cond_signal (&cv);
72659612Sjasone			sleep (1);
72759612Sjasone			assert (pthread_mutex_destroy (&mutex) == 0);
72859612Sjasone		}
72959612Sjasone	}
73059612Sjasone}
73159612Sjasone
73259612Sjasone
73359612Sjasonestatic void
73459612Sjasonemutex_lock_test (void)
73559612Sjasone{
73659612Sjasone	pthread_mutexattr_t mattr;
73759612Sjasone	pthread_mutex_t	mutex;
73859612Sjasone	pthread_attr_t pattr;
73959612Sjasone	int mproto, ret;
74059612Sjasone	mutex_kind_t mkind;
74159612Sjasone	thread_state_t state;
74259612Sjasone
74359612Sjasone	/*
74459612Sjasone	 * Lock a mutex.
74559612Sjasone	 *
74659612Sjasone	 * pthread_lock not tested for:
74759612Sjasone	 */
74859612Sjasone	log ("Testing pthread_mutex_lock\n");
74959612Sjasone	log ("--------------------------\n");
75059612Sjasone
75159612Sjasone	assert (pthread_attr_init (&pattr) == 0);
75259612Sjasone	assert (pthread_attr_setdetachstate (&pattr,
75359612Sjasone	    PTHREAD_CREATE_DETACHED) == 0);
75459612Sjasone	state.flags = 0;	/* No flags yet. */
75559612Sjasone
75659612Sjasone	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
75759612Sjasone		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
75859612Sjasone			/* Initialize the mutex attribute. */
75959612Sjasone			assert (pthread_mutexattr_init (&mattr) == 0);
76059612Sjasone			assert (pthread_mutexattr_setprotocol (&mattr,
76159612Sjasone			    protocols[mproto]) == 0);
76259612Sjasone
76359612Sjasone			/*
76459612Sjasone			 * Ensure that the first mutex type is a POSIX
76559612Sjasone			 * compliant mutex.
76659612Sjasone			 */
76759612Sjasone			if (mkind != M_POSIX) {
76859612Sjasone				assert (pthread_mutexattr_settype (&mattr,
76959612Sjasone				    mutex_types[mkind]) == 0);
77059612Sjasone			}
77159612Sjasone
77259612Sjasone			/* Create the mutex. */
77359612Sjasone			assert (pthread_mutex_init (&mutex, &mattr) == 0);
77459612Sjasone
77559612Sjasone			log ("  Protocol %s, Type %s\n",
77659612Sjasone			    protocol_strs[mproto], mutextype_strs[mkind]);
77759612Sjasone
77859612Sjasone			log ("    Lock on unlocked mutex - ");
77959612Sjasone			ret = pthread_mutex_lock (&mutex);
78059612Sjasone			check_result (/* expected */ 0, ret);
78159612Sjasone			pthread_mutex_unlock (&mutex);
78259612Sjasone
78359612Sjasone			log ("    Lock on invalid mutex - ");
78459612Sjasone			ret = pthread_mutex_lock (NULL);
78559612Sjasone			check_result (/* expected */ EINVAL, ret);
78659612Sjasone
78759612Sjasone			log ("    Lock on mutex held by self - ");
78859612Sjasone			assert (pthread_create (&state.tid, &pattr, lock_twice,
78959612Sjasone			    (void *) &state) == 0);
79059612Sjasone			/* Let the thread start. */
79159612Sjasone			sleep (1);
79259612Sjasone			state.cmd.mutex = &mutex;
79359612Sjasone			state.ret = 0xdeadbeef;
79459612Sjasone			assert (pthread_mutex_lock (&cond_mutex) == 0);
79559612Sjasone			assert (pthread_cond_signal (&cond_var) == 0);
79659612Sjasone			assert (pthread_mutex_unlock (&cond_mutex) == 0);
79759612Sjasone			/* Let the thread receive and process the command. */
79859612Sjasone			sleep (1);
79959612Sjasone
80059612Sjasone			switch (mkind) {
80159612Sjasone			case M_POSIX:
80259612Sjasone				check_result (/* expected */ EDEADLK,
80359612Sjasone				    state.ret);
80459612Sjasone				break;
80559612Sjasone			case M_SS2_DEFAULT:
80659612Sjasone				check_result (/* expected */ EDEADLK,
80759612Sjasone				    state.ret);
80859612Sjasone				break;
80959612Sjasone			case M_SS2_ERRORCHECK:
81059612Sjasone				check_result (/* expected */ EDEADLK,
81159612Sjasone				    state.ret);
81259612Sjasone				break;
81359612Sjasone			case M_SS2_NORMAL:
81459612Sjasone				check_result (/* expected */ 0xdeadbeef,
81559612Sjasone				    state.ret);
81659612Sjasone				break;
81759612Sjasone			case M_SS2_RECURSIVE:
81859612Sjasone				check_result (/* expected */ 0, state.ret);
81959612Sjasone				break;
82059612Sjasone			}
82159612Sjasone			pthread_mutex_destroy (&mutex);
82259612Sjasone			pthread_mutexattr_destroy (&mattr);
82359612Sjasone		}
82459612Sjasone	}
82559612Sjasone}
82659612Sjasone
82759612Sjasone
82859612Sjasonestatic void
82959612Sjasonemutex_unlock_test (void)
83059612Sjasone{
83159612Sjasone	const int test_thread_id = 0;	/* ID of test thread */
83259612Sjasone	pthread_mutexattr_t mattr;
83359612Sjasone	pthread_mutex_t	mutex;
83459612Sjasone	int mproto, ret;
83559612Sjasone	mutex_kind_t mkind;
83659612Sjasone
83759612Sjasone	/*
83859612Sjasone	 * Unlock a mutex.
83959612Sjasone	 *
84059612Sjasone	 * pthread_unlock not tested for:
84159612Sjasone	 */
84259612Sjasone	log ("Testing pthread_mutex_unlock\n");
84359612Sjasone	log ("----------------------------\n");
84459612Sjasone
84559612Sjasone	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
84659612Sjasone		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
84759612Sjasone			/* Initialize the mutex attribute. */
84859612Sjasone			assert (pthread_mutexattr_init (&mattr) == 0);
84959612Sjasone			assert (pthread_mutexattr_setprotocol (&mattr,
85059612Sjasone			    protocols[mproto]) == 0);
85159612Sjasone
85259612Sjasone			/*
85359612Sjasone			 * Ensure that the first mutex type is a POSIX
85459612Sjasone			 * compliant mutex.
85559612Sjasone			 */
85659612Sjasone			if (mkind != M_POSIX) {
85759612Sjasone				assert (pthread_mutexattr_settype (&mattr,
85859612Sjasone				    mutex_types[mkind]) == 0);
85959612Sjasone			}
86059612Sjasone
86159612Sjasone			/* Create the mutex. */
86259612Sjasone			assert (pthread_mutex_init (&mutex, &mattr) == 0);
86359612Sjasone
86459612Sjasone			log ("  Protocol %s, Type %s\n",
86559612Sjasone			    protocol_strs[mproto], mutextype_strs[mkind]);
86659612Sjasone
86759612Sjasone			log ("    Unlock on mutex held by self - ");
86859612Sjasone			assert (pthread_mutex_lock (&mutex) == 0);
86959612Sjasone			ret = pthread_mutex_unlock (&mutex);
87059612Sjasone			check_result (/* expected */ 0, ret);
87159612Sjasone
87259612Sjasone			log ("    Unlock on invalid mutex - ");
87359612Sjasone			ret = pthread_mutex_unlock (NULL);
87459612Sjasone			check_result (/* expected */ EINVAL, ret);
87559612Sjasone
87659612Sjasone			log ("    Unlock on mutex locked by another thread - ");
87759612Sjasone			send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &mutex);
87859612Sjasone			sleep (1);
87959612Sjasone			ret = pthread_mutex_unlock (&mutex);
88059612Sjasone			switch (mkind) {
88159612Sjasone			case M_POSIX:
88259612Sjasone				check_result (/* expected */ EPERM, ret);
88359612Sjasone				break;
88459612Sjasone			case M_SS2_DEFAULT:
88559612Sjasone				check_result (/* expected */ EPERM, ret);
88659612Sjasone				break;
88759612Sjasone			case M_SS2_ERRORCHECK:
88859612Sjasone				check_result (/* expected */ EPERM, ret);
88959612Sjasone				break;
89059612Sjasone			case M_SS2_NORMAL:
89159612Sjasone				check_result (/* expected */ EPERM, ret);
89259612Sjasone				break;
89359612Sjasone			case M_SS2_RECURSIVE:
89459612Sjasone				check_result (/* expected */ EPERM, ret);
89559612Sjasone				break;
89659612Sjasone			}
89759612Sjasone			if (ret == 0) {
89859612Sjasone				/*
89959612Sjasone				 * If for some reason we were able to unlock
90059612Sjasone				 * the mutex, relock it so that the test
90159612Sjasone				 * thread has no problems releasing the mutex.
90259612Sjasone				 */
90359612Sjasone				pthread_mutex_lock (&mutex);
90459612Sjasone			}
90559612Sjasone			send_cmd (test_thread_id, CMD_RELEASE_ALL);
90659612Sjasone			sleep (1);
90759612Sjasone
90859612Sjasone			pthread_mutex_destroy (&mutex);
90959612Sjasone			pthread_mutexattr_destroy (&mattr);
91059612Sjasone		}
91159612Sjasone	}
91259612Sjasone}
91359612Sjasone
91459612Sjasone
91559612Sjasonestatic void
91659612Sjasonequeueing_order_test (void)
91759612Sjasone{
91859612Sjasone	int i;
91959612Sjasone
92059612Sjasone	log ("Testing queueing order\n");
92159612Sjasone	log ("----------------------\n");
92259612Sjasone	assert (pthread_mutex_lock (&waiter_mutex) == 0);
92359612Sjasone	/*
92459612Sjasone	 * Tell the threads to report when they take the waiters mutex.
92559612Sjasone	 */
92659612Sjasone	assert (pthread_mutex_lock (&cond_mutex) == 0);
92759612Sjasone	for (i = 0; i < NUM_THREADS; i++) {
92859612Sjasone		states[i].flags = FLAGS_REPORT_WAITMUTEX;
92959612Sjasone		assert (pthread_cond_signal (&states[i].cond_var) == 0);
93059612Sjasone	}
93159612Sjasone	assert (pthread_mutex_unlock (&cond_mutex) == 0);
93259612Sjasone
93359612Sjasone	/* Signal the threads to continue. */
93459612Sjasone	sleep (1);
93559612Sjasone
93659612Sjasone	/* Use the global condition variable next time. */
93759612Sjasone	use_global_condvar = 1;
93859612Sjasone
93959612Sjasone	/* Release the waiting threads and allow them to run again. */
94059612Sjasone	assert (pthread_mutex_unlock (&waiter_mutex) == 0);
94159612Sjasone	sleep (1);
94259612Sjasone
94359612Sjasone	log ("  Queueing order on a mutex - ");
94459612Sjasone	check_run_order ("9,8,7,6,5,4,3,2,1,0");
94559612Sjasone	for (i = 0; i < NUM_THREADS; i = i + 1) {
94659612Sjasone		/* Tell the threads to report when they've been signaled. */
94759612Sjasone		states[i].flags = FLAGS_REPORT_WAITCONDVAR;
94859612Sjasone	}
94959612Sjasone
95059612Sjasone	/*
95159612Sjasone	 * Prevent the threads from continuing their loop after we
95259612Sjasone	 * signal them.
95359612Sjasone	 */
95459612Sjasone	assert (pthread_mutex_lock (&waiter_mutex) == 0);
95559612Sjasone
95659612Sjasone
95759612Sjasone	log ("  Queueing order on a condition variable - ");
95859612Sjasone	/*
95959612Sjasone	 * Signal one thread to run and see that the highest priority
96059612Sjasone	 * thread executes.
96159612Sjasone	 */
96259612Sjasone	assert (pthread_mutex_lock (&cond_mutex) == 0);
96359612Sjasone	assert (pthread_cond_signal (&cond_var) == 0);
96459612Sjasone	assert (pthread_mutex_unlock (&cond_mutex) == 0);
96559612Sjasone	sleep (1);
96659612Sjasone	if (states[NUM_THREADS - 1].status != STAT_WAITMUTEX)
96759612Sjasone		log_error ("highest priority thread does not run.\n");
96859612Sjasone
96959612Sjasone	/* Signal the remaining threads. */
97059612Sjasone	assert (pthread_mutex_lock (&cond_mutex) == 0);
97159612Sjasone	assert (pthread_cond_broadcast (&cond_var) == 0);
97259612Sjasone	assert (pthread_mutex_unlock (&cond_mutex) == 0);
97359612Sjasone	sleep (1);
97459612Sjasone
97559612Sjasone	check_run_order ("9,8,7,6,5,4,3,2,1,0");
97659612Sjasone	for (i = 0; i < NUM_THREADS; i = i + 1) {
97759612Sjasone		/* Tell the threads not to report anything. */
97859612Sjasone		states[i].flags = 0;
97959612Sjasone	}
98059612Sjasone
98159612Sjasone	/* Use the thread unique condition variable next time. */
98259612Sjasone	use_global_condvar = 0;
98359612Sjasone
98459612Sjasone	/* Allow the threads to continue their loop. */
98559612Sjasone	assert (pthread_mutex_unlock (&waiter_mutex) == 0);
98659612Sjasone	sleep (1);
98759612Sjasone}
98859612Sjasone
98959612Sjasone
99059612Sjasonestatic void
99159612Sjasonemutex_prioceiling_test (void)
99259612Sjasone{
99359612Sjasone	const int test_thread_id = 0;	/* ID of test thread */
99459612Sjasone	pthread_mutexattr_t mattr;
99559612Sjasone	struct sched_param param;
99659612Sjasone	pthread_mutex_t	m[3];
99759612Sjasone	mutex_kind_t	mkind;
99859612Sjasone	int		i, ret, policy, my_prio, old_ceiling;
99959612Sjasone
100059612Sjasone	log ("Testing priority ceilings\n");
100159612Sjasone	log ("-------------------------\n");
100259612Sjasone	for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
100359612Sjasone
100459612Sjasone		log ("  Protype PTHREAD_PRIO_PROTECT, Type %s\n",
100559612Sjasone		    mutextype_strs[mkind]);
100659612Sjasone
100759612Sjasone		/*
100859612Sjasone		 * Initialize and create a mutex.
100959612Sjasone		 */
101059612Sjasone		assert (pthread_mutexattr_init (&mattr) == 0);
101159612Sjasone
101259612Sjasone		/* Get this threads current priority. */
101359612Sjasone		assert (pthread_getschedparam (pthread_self(), &policy,
101459612Sjasone		    &param) == 0);
101559612Sjasone		my_prio = param.sched_priority;	/* save for later use */
101659612Sjasone		log_trace ("Current scheduling policy %d, priority %d\n",
101759612Sjasone		    policy, my_prio);
101859612Sjasone
101959612Sjasone		/*
102059612Sjasone		 * Initialize and create 3 priority protection mutexes with
102159612Sjasone		 * default (max priority) ceilings.
102259612Sjasone		 */
102359612Sjasone		assert (pthread_mutexattr_setprotocol(&mattr,
102459612Sjasone		    PTHREAD_PRIO_PROTECT) == 0);
102559612Sjasone
102659612Sjasone		/*
102759612Sjasone		 * Ensure that the first mutex type is a POSIX
102859612Sjasone		 * compliant mutex.
102959612Sjasone		 */
103059612Sjasone		if (mkind != M_POSIX) {
103159612Sjasone			assert (pthread_mutexattr_settype (&mattr,
103259612Sjasone			    mutex_types[mkind]) == 0);
103359612Sjasone		}
103459612Sjasone
103559612Sjasone		for (i = 0; i < 3; i++)
103659612Sjasone			assert (pthread_mutex_init (&m[i], &mattr) == 0);
103759612Sjasone
103859612Sjasone		/*
103959612Sjasone		 * Set the ceiling priorities for the 3 priority protection
104059612Sjasone		 * mutexes to, 5 less than, equal to, and 5 greater than,
104159612Sjasone		 * this threads current priority.
104259612Sjasone		 */
104359612Sjasone		for (i = 0; i < 3; i++)
104459612Sjasone			assert (pthread_mutex_setprioceiling (&m[i],
104559612Sjasone			    my_prio - 5 + 5*i, &old_ceiling) == 0);
104659612Sjasone
104759612Sjasone		/*
104859612Sjasone		 * Check that if we attempt to take a mutex whose priority
104959612Sjasone		 * ceiling is lower than our priority, we get an error.
105059612Sjasone		 */
105159612Sjasone		log ("    Lock with ceiling priority < thread priority - ");
105259612Sjasone		ret = pthread_mutex_lock (&m[0]);
105359612Sjasone		check_result (/* expected */ EINVAL, ret);
105459612Sjasone		if (ret == 0)
105559612Sjasone			pthread_mutex_unlock (&m[0]);
105659612Sjasone
105759612Sjasone		/*
105859612Sjasone		 * Check that we can take a mutex whose priority ceiling
105959612Sjasone		 * is equal to our priority.
106059612Sjasone		 */
106159612Sjasone		log ("    Lock with ceiling priority = thread priority - ");
106259612Sjasone		ret = pthread_mutex_lock (&m[1]);
106359612Sjasone		check_result (/* expected */ 0, ret);
106459612Sjasone		if (ret == 0)
106559612Sjasone			pthread_mutex_unlock (&m[1]);
106659612Sjasone
106759612Sjasone		/*
106859612Sjasone		 * Check that we can take a mutex whose priority ceiling
106959612Sjasone		 * is higher than our priority.
107059612Sjasone		 */
107159612Sjasone		log ("    Lock with ceiling priority > thread priority - ");
107259612Sjasone		ret = pthread_mutex_lock (&m[2]);
107359612Sjasone		check_result (/* expected */ 0, ret);
107459612Sjasone		if (ret == 0)
107559612Sjasone			pthread_mutex_unlock (&m[2]);
107659612Sjasone
107759612Sjasone		/*
107859612Sjasone		 * Have the test thread go into a busy loop for 5 seconds
107959612Sjasone		 * and see that it doesn't block this thread (since the
108059612Sjasone		 * priority ceiling of mutex 0 and the priority of the test
108159612Sjasone		 * thread are both less than the priority of this thread).
108259612Sjasone		 */
108359612Sjasone		log ("    Preemption with ceiling priority < thread "
108459612Sjasone		    "priority - ");
108559612Sjasone		/* Have the test thread take mutex 0. */
108659612Sjasone		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[0]);
108759612Sjasone		sleep (1);
108859612Sjasone
108959612Sjasone		log_trace ("Sending busy command.\n");
109059612Sjasone		send_cmd (test_thread_id, CMD_BUSY_LOOP);
109159612Sjasone		log_trace ("Busy sent, yielding\n");
109259612Sjasone		pthread_yield ();
109359612Sjasone		log_trace ("Returned from yield.\n");
109459612Sjasone		if (states[test_thread_id].flags &
109559612Sjasone		    (FLAGS_IS_BUSY | FLAGS_WAS_BUSY))
109659612Sjasone			log_error ("test thread inproperly preempted us.\n");
109759612Sjasone		else {
109859612Sjasone			/* Let the thread finish its busy loop. */
109959612Sjasone			sleep (6);
110059612Sjasone			if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
110159612Sjasone				log_error ("test thread never finished.\n");
110259612Sjasone			else
110359612Sjasone				log_pass ();
110459612Sjasone		}
110559612Sjasone		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
110659612Sjasone
110759612Sjasone		/* Have the test thread release mutex 0. */
110859612Sjasone		send_cmd (test_thread_id, CMD_RELEASE_ALL);
110959612Sjasone		sleep (1);
111059612Sjasone
111159612Sjasone		/*
111259612Sjasone		 * Have the test thread go into a busy loop for 5 seconds
111359612Sjasone		 * and see that it preempts this thread (since the priority
111459612Sjasone		 * ceiling of mutex 1 is the same as the priority of this
111559612Sjasone		 * thread).  The test thread should not run to completion
111659612Sjasone		 * as its time quantum should expire before the 5 seconds
111759612Sjasone		 * are up.
111859612Sjasone		 */
111959612Sjasone		log ("    Preemption with ceiling priority = thread "
112059612Sjasone		    "priority - ");
112159612Sjasone
112259612Sjasone		/* Have the test thread take mutex 1. */
112359612Sjasone		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
112459612Sjasone		sleep (1);
112559612Sjasone
112659612Sjasone		log_trace ("Sending busy\n");
112759612Sjasone		send_cmd (test_thread_id, CMD_BUSY_LOOP);
112859612Sjasone		log_trace ("Busy sent, yielding\n");
112959612Sjasone		pthread_yield ();
113059612Sjasone		log_trace ("Returned from yield.\n");
113159612Sjasone		if ((states[test_thread_id].flags & FLAGS_IS_BUSY) == 0)
113259612Sjasone			log_error ("test thread did not switch in on yield.\n");
113359612Sjasone		else if (states[test_thread_id].flags & FLAGS_WAS_BUSY)
113459612Sjasone			log_error ("test thread ran to completion.\n");
113559612Sjasone		else {
113659612Sjasone			/* Let the thread finish its busy loop. */
113759612Sjasone			sleep (6);
113859612Sjasone			if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
113959612Sjasone				log_error ("test thread never finished.\n");
114059612Sjasone			else
114159612Sjasone				log_pass ();
114259612Sjasone		}
114359612Sjasone		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
114459612Sjasone
114559612Sjasone		/* Have the test thread release mutex 1. */
114659612Sjasone		send_cmd (test_thread_id, CMD_RELEASE_ALL);
114759612Sjasone		sleep (1);
114859612Sjasone
114959612Sjasone		/*
115059612Sjasone		 * Set the scheduling policy of the test thread to SCHED_FIFO
115159612Sjasone		 * and have it go into a busy loop for 5 seconds.  This
115259612Sjasone		 * thread is SCHED_RR, and since the priority ceiling of
115359612Sjasone		 * mutex 1 is the same as the priority of this thread, the
115459612Sjasone		 * test thread should run to completion once it is switched
115559612Sjasone		 * in.
115659612Sjasone		 */
115759612Sjasone		log ("    SCHED_FIFO scheduling and ceiling priority = "
115859612Sjasone		    "thread priority - ");
115959612Sjasone		param.sched_priority = states[test_thread_id].priority;
116059612Sjasone		assert (pthread_setschedparam (states[test_thread_id].tid,
116159612Sjasone		    SCHED_FIFO, &param) == 0);
116259612Sjasone
116359612Sjasone		/* Have the test thread take mutex 1. */
116459612Sjasone		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
116559612Sjasone		sleep (1);
116659612Sjasone
116759612Sjasone		log_trace ("Sending busy\n");
116859612Sjasone		send_cmd (test_thread_id, CMD_BUSY_LOOP);
116959612Sjasone		log_trace ("Busy sent, yielding\n");
117059612Sjasone		pthread_yield ();
117159612Sjasone		log_trace ("Returned from yield.\n");
117259612Sjasone		if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) {
117359612Sjasone			log_error ("test thread did not run to completion.\n");
117459612Sjasone			/* Let the thread finish it's busy loop. */
117559612Sjasone			sleep (6);
117659612Sjasone		}
117759612Sjasone		else
117859612Sjasone			log_pass ();
117959612Sjasone		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
118059612Sjasone
118159612Sjasone		/* Restore the test thread scheduling parameters. */
118259612Sjasone		param.sched_priority = states[test_thread_id].priority;
118359612Sjasone		assert (pthread_setschedparam (states[test_thread_id].tid,
118459612Sjasone		    SCHED_RR, &param) == 0);
118559612Sjasone
118659612Sjasone		/* Have the test thread release mutex 1. */
118759612Sjasone		send_cmd (test_thread_id, CMD_RELEASE_ALL);
118859612Sjasone		sleep (1);
118959612Sjasone
119059612Sjasone		/*
119159612Sjasone		 * Have the test thread go into a busy loop for 5 seconds
119259612Sjasone		 * and see that it preempts this thread (since the priority
119359612Sjasone		 * ceiling of mutex 2 is the greater than the priority of
119459612Sjasone		 * this thread).  The test thread should run to completion
119559612Sjasone		 * and block this thread because its active priority is
119659612Sjasone		 * higher.
119759612Sjasone		 */
119859612Sjasone		log ("    SCHED_FIFO scheduling and ceiling priority > "
119959612Sjasone		    "thread priority - ");
120059612Sjasone		/* Have the test thread take mutex 2. */
120159612Sjasone		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[2]);
120259612Sjasone		sleep (1);
120359612Sjasone
120459612Sjasone		log_trace ("Sending busy\n");
120559612Sjasone		send_cmd (test_thread_id, CMD_BUSY_LOOP);
120659612Sjasone		log_trace ("Busy sent, yielding\n");
120759612Sjasone		pthread_yield ();
120859612Sjasone		log_trace ("Returned from yield.\n");
120959612Sjasone		if ((states[test_thread_id].flags & FLAGS_IS_BUSY) != 0) {
121059612Sjasone			log_error ("test thread did not run to completion.\n");
121159612Sjasone			/* Let the thread finish it's busy loop. */
121259612Sjasone			sleep (6);
121359612Sjasone		}
121459612Sjasone		else if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
121559612Sjasone			log_error ("test thread never finished.\n");
121659612Sjasone		else
121759612Sjasone			log_pass ();
121859612Sjasone		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
121959612Sjasone
122059612Sjasone		/* Have the test thread release mutex 2. */
122159612Sjasone		send_cmd (test_thread_id, CMD_RELEASE_ALL);
122259612Sjasone		sleep (1);
122359612Sjasone
122459612Sjasone		/* Destroy the mutexes. */
122559612Sjasone		for (i = 0; i < 3; i++)
122659612Sjasone			assert (pthread_mutex_destroy (&m[i]) == 0);
122759612Sjasone	}
122859612Sjasone}
122959612Sjasone
123059612Sjasone
123159612Sjasonestatic void
123259612Sjasonemutex_prioinherit_test (void)
123359612Sjasone{
123459612Sjasone	pthread_mutexattr_t mattr;
123559612Sjasone	struct sched_param param;
123659612Sjasone	pthread_mutex_t	m[3];
123759612Sjasone	mutex_kind_t	mkind;
123859612Sjasone	int		i, policy, my_prio;
123959612Sjasone
124059612Sjasone	/* Get this threads current priority. */
124159612Sjasone	assert (pthread_getschedparam (pthread_self(), &policy,
124259612Sjasone	    &param) == 0);
124359612Sjasone	my_prio = param.sched_priority;	/* save for later use */
124459612Sjasone	log_trace ("Current scheduling policy %d, priority %d\n",
124559612Sjasone	    policy, my_prio);
124659612Sjasone
124759612Sjasone	log ("Testing priority inheritence\n");
124859612Sjasone	log ("----------------------------\n");
124959612Sjasone	for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
125059612Sjasone
125159612Sjasone		log ("  Protype PTHREAD_PRIO_INHERIT, Type %s\n",
125259612Sjasone		    mutextype_strs[mkind]);
125359612Sjasone
125459612Sjasone		/*
125559612Sjasone		 * Initialize and create a mutex.
125659612Sjasone		 */
125759612Sjasone		assert (pthread_mutexattr_init (&mattr) == 0);
125859612Sjasone
125959612Sjasone		/*
126059612Sjasone		 * Initialize and create 3 priority inheritence mutexes with
126159612Sjasone		 * default (max priority) ceilings.
126259612Sjasone		 */
126359612Sjasone		assert (pthread_mutexattr_setprotocol(&mattr,
126459612Sjasone		    PTHREAD_PRIO_INHERIT) == 0);
126559612Sjasone
126659612Sjasone		/*
126759612Sjasone		 * Ensure that the first mutex type is a POSIX
126859612Sjasone		 * compliant mutex.
126959612Sjasone		 */
127059612Sjasone		if (mkind != M_POSIX) {
127159612Sjasone			assert (pthread_mutexattr_settype (&mattr,
127259612Sjasone			    mutex_types[mkind]) == 0);
127359612Sjasone		}
127459612Sjasone
127559612Sjasone		for (i = 0; i < 3; i++)
127659612Sjasone			assert (pthread_mutex_init (&m[i], &mattr) == 0);
127759612Sjasone
127859612Sjasone		/*
127959612Sjasone		 * Test setup:
128059612Sjasone		 *   Thread 4 - take mutex 0, 1
128159612Sjasone		 *   Thread 2 - enter protected busy loop with mutex 0
128259612Sjasone		 *   Thread 3 - enter protected busy loop with mutex 1
128359612Sjasone		 *   Thread 4 - enter protected busy loop with mutex 2
128459612Sjasone		 *   Thread 5 - enter busy loop
128559612Sjasone		 *   Thread 6 - enter protected busy loop with mutex 0
128659612Sjasone		 *   Thread 4 - releases mutexes 1 and 0.
128759612Sjasone		 *
128859612Sjasone		 * Expected results:
128959612Sjasone		 *   Threads complete in order 4, 6, 5, 3, 2
129059612Sjasone		 */
129159612Sjasone		log ("    Simple inheritence test - ");
129259612Sjasone
129359612Sjasone		/*
129459612Sjasone		 * Command thread 4 to take mutexes 0 and 1.
129559612Sjasone		 */
129659612Sjasone		send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
129759612Sjasone		sleep (1);	/* Allow command to be received. */
129859612Sjasone		send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[1]);
129959612Sjasone		sleep (1);
130059612Sjasone
130159612Sjasone		/*
130259612Sjasone		 * Tell the threads to report themselves when they are
130359612Sjasone		 * at the bottom of their loop (waiting on wait_mutex).
130459612Sjasone		 */
130559612Sjasone		for (i = 0; i < NUM_THREADS; i++)
130659612Sjasone			states[i].flags |= FLAGS_REPORT_WAITMUTEX;
130759612Sjasone
130859612Sjasone		/*
130959612Sjasone		 * Command thread 2 to take mutex 0 and thread 3 to take
131059612Sjasone		 * mutex 1, both via a protected operation command.  Since
131159612Sjasone		 * thread 4 owns mutexes 0 and 1, both threads 2 and 3
131259612Sjasone		 * will block until the mutexes are released by thread 4.
131359612Sjasone		 */
131459612Sjasone		log_trace ("Commanding protected operation to thread 2.\n");
131559612Sjasone		send_mutex_cmd (2, CMD_PROTECTED_OP, &m[0]);
131659612Sjasone		log_trace ("Commanding protected operation to thread 3.\n");
131759612Sjasone		send_mutex_cmd (3, CMD_PROTECTED_OP, &m[1]);
131859612Sjasone		sleep (1);
131959612Sjasone
132059612Sjasone		/*
132159612Sjasone		 * Command thread 4 to take mutex 2 via a protected operation
132259612Sjasone		 * and thread 5 to enter a busy loop for 5 seconds.  Since
132359612Sjasone		 * thread 5 has higher priority than thread 4, thread 5 will
132459612Sjasone		 * enter the busy loop before thread 4 is activated.
132559612Sjasone		 */
132659612Sjasone		log_trace ("Commanding protected operation to thread 4.\n");
132759612Sjasone		send_mutex_cmd (4, CMD_PROTECTED_OP, &m[2]);
132859612Sjasone		log_trace ("Commanding busy loop to thread 5.\n");
132959612Sjasone		send_cmd (5, CMD_BUSY_LOOP);
133059612Sjasone		sleep (1);
133159612Sjasone		if ((states[5].flags & FLAGS_IS_BUSY) == 0)
133259612Sjasone			log_error ("thread 5 is not running.\n");
133359612Sjasone		log_trace ("Commanding protected operation thread 6.\n");
133459612Sjasone		send_mutex_cmd (6, CMD_PROTECTED_OP, &m[0]);
133559612Sjasone		sleep (1);
133659612Sjasone		if ((states[4].flags & FLAGS_WAS_BUSY) == 0)
133759612Sjasone			log_error ("thread 4 failed to inherit priority.\n");
133859612Sjasone		states[4].flags = 0;
133959612Sjasone		send_cmd (4, CMD_RELEASE_ALL);
134059612Sjasone		sleep (5);
134159612Sjasone		check_run_order ("4,6,5,3,2");
134259612Sjasone
134359612Sjasone		/*
134459612Sjasone		 * Clear the flags.
134559612Sjasone		 */
134659612Sjasone		for (i = 0; i < NUM_THREADS; i++)
134759612Sjasone			states[i].flags = 0;
134859612Sjasone
134959612Sjasone		/*
135059612Sjasone		 * Test setup:
135159612Sjasone		 *   Thread 2 - enter busy loop (SCHED_FIFO)
135259612Sjasone		 *   Thread 4 - take mutex 0
135359612Sjasone		 *   Thread 4 - priority change to same priority as thread 2
135459612Sjasone		 *   Thread 4 - release mutex 0
135559612Sjasone		 *
135659612Sjasone		 * Expected results:
135759612Sjasone		 *   Since thread 4 owns a priority mutex, it should be
135859612Sjasone		 *   placed at the front of the run queue (for its new
135959612Sjasone		 *   priority slot) when its priority is lowered to the
136059612Sjasone		 *   same priority as thread 2.  If thread 4 did not own
136159612Sjasone		 *   a priority mutex, then it would have been added to
136259612Sjasone		 *   the end of the run queue and thread 2 would have
136359612Sjasone		 *   executed until it blocked (because it's scheduling
136459612Sjasone		 *   policy is SCHED_FIFO).
136559612Sjasone		 *
136659612Sjasone		 */
136759612Sjasone		log ("    Inheritence test with change of priority - ");
136859612Sjasone
136959612Sjasone		/*
137059612Sjasone		 * Change threads 2 and 4 scheduling policies to be
137159612Sjasone		 * SCHED_FIFO.
137259612Sjasone		 */
137359612Sjasone		param.sched_priority = states[2].priority;
137459612Sjasone		assert (pthread_setschedparam (states[2].tid, SCHED_FIFO,
137559612Sjasone		    &param) == 0);
137659612Sjasone		param.sched_priority = states[4].priority;
137759612Sjasone		assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
137859612Sjasone		    &param) == 0);
137959612Sjasone
138059612Sjasone		/*
138159612Sjasone		 * Command thread 4 to take mutex 0.
138259612Sjasone		 */
138359612Sjasone		send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
138459612Sjasone		sleep (1);
138559612Sjasone
138659612Sjasone		/*
138759612Sjasone		 * Command thread 2 to enter busy loop.
138859612Sjasone		 */
138959612Sjasone		send_cmd (2, CMD_BUSY_LOOP);
139059612Sjasone		sleep (1);	/* Allow command to be received. */
139159612Sjasone
139259612Sjasone		/*
139359612Sjasone		 * Command thread 4 to enter busy loop.
139459612Sjasone		 */
139559612Sjasone		send_cmd (4, CMD_BUSY_LOOP);
139659612Sjasone		sleep (1);	/* Allow command to be received. */
139759612Sjasone
139859612Sjasone		/* Have threads 2 and 4 report themselves. */
139959612Sjasone		states[2].flags = FLAGS_REPORT_WAITMUTEX;
140059612Sjasone		states[4].flags = FLAGS_REPORT_WAITMUTEX;
140159612Sjasone
140259612Sjasone		/* Change the priority of thread 4. */
140359612Sjasone		param.sched_priority = states[2].priority;
140459612Sjasone		assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
140559612Sjasone		    &param) == 0);
140659612Sjasone		sleep (5);
140759612Sjasone		check_run_order ("4,2");
140859612Sjasone
140959612Sjasone		/* Clear the flags */
141059612Sjasone		states[2].flags = 0;
141159612Sjasone		states[4].flags = 0;
141259612Sjasone
141359612Sjasone		/* Reset the policies. */
141459612Sjasone		param.sched_priority = states[2].priority;
141559612Sjasone		assert (pthread_setschedparam (states[2].tid, SCHED_RR,
141659612Sjasone		    &param) == 0);
141759612Sjasone		param.sched_priority = states[4].priority;
141859612Sjasone		assert (pthread_setschedparam (states[4].tid, SCHED_RR,
141959612Sjasone		    &param) == 0);
142059612Sjasone
142159612Sjasone		send_cmd (4, CMD_RELEASE_MUTEX);
142259612Sjasone		sleep (1);
142359612Sjasone
142459612Sjasone		/* Destroy the mutexes. */
142559612Sjasone		for (i = 0; i < 3; i++)
142659612Sjasone			assert (pthread_mutex_destroy (&m[i]) == 0);
142759612Sjasone	}
142859612Sjasone}
142959612Sjasone
143059612Sjasone
143159612Sjasoneint main (int argc, char *argv[])
143259612Sjasone{
143359612Sjasone	pthread_mutexattr_t mattr;
143459612Sjasone	pthread_condattr_t cattr;
143559612Sjasone	pthread_attr_t	pattr;
143659612Sjasone	int		i, policy, main_prio;
143759612Sjasone	void *		exit_status;
143859612Sjasone	sigset_t	mask;
143959612Sjasone	struct sigaction act;
144059612Sjasone	struct sched_param param;
144159612Sjasone
144299239Sdeischen	logfile = stdout;
144399239Sdeischen
144459612Sjasone	assert (pthread_getschedparam (pthread_self (), &policy, &param) == 0);
144559612Sjasone	main_prio = param.sched_priority;
144659612Sjasone
144759612Sjasone	/* Setupt our signal mask. */
144859612Sjasone	sigfillset (&mask);
144959612Sjasone	sigdelset (&mask, SIGINT);
145059612Sjasone	sigprocmask (SIG_SETMASK, &mask, NULL);
145159612Sjasone
145259612Sjasone	/* Install a signal handler for SIGINT */
145359612Sjasone	sigemptyset (&act.sa_mask);
145459612Sjasone	sigaddset (&act.sa_mask, SIGINT);
145559612Sjasone	act.sa_handler = sighandler;
145659612Sjasone	act.sa_flags = SA_RESTART;
145759612Sjasone	sigaction (SIGINT, &act, NULL);
145859612Sjasone
1459121266Sdeischen	/* This test relies on the concurrency level being 1. */
1460121266Sdeischen	pthread_setconcurrency(1);
1461121266Sdeischen
146259612Sjasone	/*
146359612Sjasone	 * Initialize the thread attribute.
146459612Sjasone	 */
146559612Sjasone	assert (pthread_attr_init (&pattr) == 0);
146659612Sjasone	assert (pthread_attr_setdetachstate (&pattr,
146759612Sjasone	    PTHREAD_CREATE_JOINABLE) == 0);
146859612Sjasone
146959612Sjasone	/*
147059612Sjasone	 * Initialize and create the waiter and condvar mutexes.
147159612Sjasone	 */
147259612Sjasone	assert (pthread_mutexattr_init (&mattr) == 0);
147359612Sjasone	assert (pthread_mutex_init (&waiter_mutex, &mattr) == 0);
147459612Sjasone	assert (pthread_mutex_init (&cond_mutex, &mattr) == 0);
147559612Sjasone
147659612Sjasone	/*
147759612Sjasone	 * Initialize and create a condition variable.
147859612Sjasone	 */
147959612Sjasone	assert (pthread_condattr_init (&cattr) == 0);
148059612Sjasone	assert (pthread_cond_init (&cond_var, &cattr) == 0);
148159612Sjasone
148259612Sjasone	/* Create a pipe to catch the results of thread wakeups. */
148359612Sjasone	assert (pipe (pipefd) == 0);
148459612Sjasone
1485152599Smarcel#if defined(_LIBC_R_) && defined(DEBUG)
148659612Sjasone	assert (pthread_switch_add_np (kern_switch) == 0);
148759612Sjasone#endif
148859612Sjasone
148959612Sjasone	/*
149059612Sjasone	 * Create the waiting threads.
149159612Sjasone	 */
149259612Sjasone	for (i = 0; i < NUM_THREADS; i++) {
149359612Sjasone		assert (pthread_cond_init (&states[i].cond_var, &cattr) == 0);
149459612Sjasone		states[i].id = (u_int8_t) i;  /* NUM_THREADS must be <= 256 */
149559612Sjasone		states[i].status = 0;
149659612Sjasone		states[i].cmd.cmd_id = CMD_NONE;
149759612Sjasone		states[i].flags = 0;	/* No flags yet. */
149859612Sjasone		assert (pthread_create (&states[i].tid, &pattr, waiter,
149959612Sjasone		    (void *) &states[i]) == 0);
150059612Sjasone		param.sched_priority = main_prio - 10 + i;
150159612Sjasone		states[i].priority = param.sched_priority;
150259612Sjasone		assert (pthread_setschedparam (states[i].tid, SCHED_OTHER,
150359612Sjasone		    &param) == 0);
150459612Sjasone#if defined(_LIBC_R_)
150559612Sjasone		{
150659612Sjasone			char buf[30];
150759612Sjasone
150859612Sjasone			snprintf (buf, sizeof(buf), "waiter_%d", i);
150959612Sjasone			pthread_set_name_np (states[i].tid, buf);
151059612Sjasone		}
151159612Sjasone#endif
151259612Sjasone	}
151359612Sjasone
151459612Sjasone	/* Allow the threads to start. */
151559612Sjasone	sleep (1);
151659612Sjasone	log_trace ("Done creating threads.\n");
151759612Sjasone
151859612Sjasone	log ("\n");
151959612Sjasone	mutex_init_test ();
152059612Sjasone	log ("\n");
152159612Sjasone	mutex_destroy_test ();
152259612Sjasone	log ("\n");
152359612Sjasone	mutex_lock_test ();
152459612Sjasone	log ("\n");
152559612Sjasone	mutex_unlock_test ();
152659612Sjasone	log ("\n");
152759612Sjasone	queueing_order_test ();
152859612Sjasone	log ("\n");
152959612Sjasone	mutex_prioinherit_test ();
153059612Sjasone	log ("\n");
153159612Sjasone	mutex_prioceiling_test ();
153259612Sjasone	log ("\n");
153359612Sjasone
153459612Sjasone	log ("Total tests %d, passed %d, failed %d\n",
153559612Sjasone	    total, pass_count, error_count);
153659612Sjasone
153759612Sjasone	/* Set the done flag and signal the threads to exit. */
153859612Sjasone	log_trace ("Setting done flag.\n");
153959612Sjasone	done = 1;
154059612Sjasone
154159612Sjasone	/*
154259612Sjasone	 * Wait for the threads to finish.
154359612Sjasone	 */
154459612Sjasone	log_trace ("Trying to join threads.\n");
154559612Sjasone	for (i = 0; i < NUM_THREADS; i++) {
154659612Sjasone		send_cmd (i, CMD_NONE);
154759612Sjasone		assert (pthread_join (states[i].tid, &exit_status) == 0);
154859612Sjasone	}
154959612Sjasone
155059612Sjasone	/* Clean up after ourselves. */
155159612Sjasone	close (pipefd[0]);
155259612Sjasone	close (pipefd[1]);
155359612Sjasone
155459612Sjasone	if (error_count != 0)
155559612Sjasone		exit (EX_OSERR);	/* any better ideas??? */
155659612Sjasone	else
155759612Sjasone		exit (EX_OK);
155859612Sjasone}
1559