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