xref: /dragonfly/test/libpthread/mutex_d.c (revision 62481538)
1e5a92d33SSascha Wildner /*
2e5a92d33SSascha Wildner  * Copyright (c) 1998 Daniel M. Eischen <eischen@vigrid.com>
3e5a92d33SSascha Wildner  * All rights reserved.
4e5a92d33SSascha Wildner  *
5e5a92d33SSascha Wildner  * Redistribution and use in source and binary forms, with or without
6e5a92d33SSascha Wildner  * modification, are permitted provided that the following conditions
7e5a92d33SSascha Wildner  * are met:
8e5a92d33SSascha Wildner  * 1. Redistributions of source code must retain the above copyright
9e5a92d33SSascha Wildner  *    notice, this list of conditions and the following disclaimer.
10e5a92d33SSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
11e5a92d33SSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
12e5a92d33SSascha Wildner  *    documentation and/or other materials provided with the distribution.
13e5a92d33SSascha Wildner  * 3. All advertising materials mentioning features or use of this software
14e5a92d33SSascha Wildner  *    must display the following acknowledgement:
15e5a92d33SSascha Wildner  *	This product includes software developed by Daniel M. Eischen.
16e5a92d33SSascha Wildner  * 4. Neither the name of the author nor the names of any co-contributors
17e5a92d33SSascha Wildner  *    may be used to endorse or promote products derived from this software
18e5a92d33SSascha Wildner  *    without specific prior written permission.
19e5a92d33SSascha Wildner  *
20e5a92d33SSascha Wildner  * THIS SOFTWARE IS PROVIDED BY DANIEL M. EISCHEN AND CONTRIBUTORS ``AS IS''
21e5a92d33SSascha Wildner  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22e5a92d33SSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23e5a92d33SSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24e5a92d33SSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25e5a92d33SSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26e5a92d33SSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27e5a92d33SSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28e5a92d33SSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29e5a92d33SSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30e5a92d33SSascha Wildner  * SUCH DAMAGE.
31e5a92d33SSascha Wildner  *
32e5a92d33SSascha Wildner  * $FreeBSD: src/lib/libc_r/test/mutex_d.c,v 1.1.2.2 2003/01/05 19:59:39 semenu Exp $
33e5a92d33SSascha Wildner  */
34e5a92d33SSascha Wildner #include <stdlib.h>
35e5a92d33SSascha Wildner #include <unistd.h>
36e5a92d33SSascha Wildner 
37e5a92d33SSascha Wildner #include <sys/ioctl.h>
38e5a92d33SSascha Wildner #include <assert.h>
39e5a92d33SSascha Wildner #include <errno.h>
40*62481538SSascha Wildner #include <pthread.h>
41*62481538SSascha Wildner #include <pthread_np.h>
42e5a92d33SSascha Wildner #include <sys/sched.h>
43e5a92d33SSascha Wildner #include <signal.h>
44e5a92d33SSascha Wildner #include <stdarg.h>
45e5a92d33SSascha Wildner #include <stdio.h>
46e5a92d33SSascha Wildner #include <string.h>
47e5a92d33SSascha Wildner #include <sysexits.h>
48*62481538SSascha Wildner #include <sys/time.h>
49e5a92d33SSascha Wildner 
50e5a92d33SSascha Wildner #ifndef NELEMENTS
51e5a92d33SSascha Wildner #define NELEMENTS(arr)	(sizeof (arr) / sizeof (arr[0]))
52e5a92d33SSascha Wildner #endif
53e5a92d33SSascha Wildner 
54e5a92d33SSascha Wildner #ifndef NUM_THREADS
55e5a92d33SSascha Wildner #define NUM_THREADS	10
56e5a92d33SSascha Wildner #endif
57e5a92d33SSascha Wildner 
58e5a92d33SSascha Wildner #define MAX_THREAD_CMDS	10
59e5a92d33SSascha Wildner 
60e5a92d33SSascha Wildner static void log_error(const char *, ...) __printflike(1, 2);
61e5a92d33SSascha Wildner static void log_trace (const char *, ...) __printflike(1, 2);
62*62481538SSascha Wildner static void log_info (const char *, ...) __printflike(1, 2);
63e5a92d33SSascha Wildner 
64e5a92d33SSascha Wildner /*------------------------------------------------------------
65e5a92d33SSascha Wildner  * Types
66e5a92d33SSascha Wildner  *----------------------------------------------------------*/
67e5a92d33SSascha Wildner 
68e5a92d33SSascha Wildner typedef enum {
69e5a92d33SSascha Wildner 	STAT_INITIAL,		/* initial state */
70e5a92d33SSascha Wildner 	STAT_WAITCONDVAR,	/* waiting for condition variable signal */
71e5a92d33SSascha Wildner 	STAT_WAITMUTEX		/* waiting for mutex lock */
72e5a92d33SSascha Wildner } thread_status_t;
73e5a92d33SSascha Wildner 
74e5a92d33SSascha Wildner typedef enum {
75e5a92d33SSascha Wildner 	FLAGS_REPORT_WAITCONDMUTEX	= 0x01,
76e5a92d33SSascha Wildner 	FLAGS_REPORT_WAITCONDVAR	= 0x02,
77e5a92d33SSascha Wildner 	FLAGS_REPORT_WAITMUTEX		= 0x04,
78e5a92d33SSascha Wildner 	FLAGS_REPORT_BUSY_LOOP		= 0x08,
79e5a92d33SSascha Wildner 	FLAGS_IS_BUSY			= 0x10,
80e5a92d33SSascha Wildner 	FLAGS_WAS_BUSY			= 0x20
81e5a92d33SSascha Wildner } thread_flags_t;
82e5a92d33SSascha Wildner 
83e5a92d33SSascha Wildner typedef enum {
84e5a92d33SSascha Wildner 	CMD_NONE,
85e5a92d33SSascha Wildner 	CMD_TAKE_MUTEX,
86e5a92d33SSascha Wildner 	CMD_RELEASE_MUTEX,
87e5a92d33SSascha Wildner 	CMD_WAIT_FOR_SIGNAL,
88e5a92d33SSascha Wildner 	CMD_BUSY_LOOP,
89e5a92d33SSascha Wildner 	CMD_PROTECTED_OP,
90e5a92d33SSascha Wildner 	CMD_RELEASE_ALL
91e5a92d33SSascha Wildner } thread_cmd_id_t;
92e5a92d33SSascha Wildner 
93e5a92d33SSascha Wildner typedef struct {
94e5a92d33SSascha Wildner 	thread_cmd_id_t	cmd_id;
95e5a92d33SSascha Wildner 	pthread_mutex_t	*mutex;
96e5a92d33SSascha Wildner 	pthread_cond_t	*cond;
97e5a92d33SSascha Wildner } thread_cmd_t;
98e5a92d33SSascha Wildner 
99e5a92d33SSascha Wildner typedef struct {
100e5a92d33SSascha Wildner 	pthread_cond_t	cond_var;
101e5a92d33SSascha Wildner 	thread_status_t	status;
102e5a92d33SSascha Wildner 	thread_cmd_t	cmd;
103e5a92d33SSascha Wildner 	int		flags;
104e5a92d33SSascha Wildner 	int		priority;
105e5a92d33SSascha Wildner 	int		ret;
106e5a92d33SSascha Wildner 	pthread_t	tid;
107e5a92d33SSascha Wildner 	u_int8_t	id;
108e5a92d33SSascha Wildner } thread_state_t;
109e5a92d33SSascha Wildner 
110e5a92d33SSascha Wildner typedef enum {
111e5a92d33SSascha Wildner 	M_POSIX,
112e5a92d33SSascha Wildner 	M_SS2_DEFAULT,
113e5a92d33SSascha Wildner 	M_SS2_ERRORCHECK,
114e5a92d33SSascha Wildner 	M_SS2_NORMAL,
115e5a92d33SSascha Wildner 	M_SS2_RECURSIVE
116e5a92d33SSascha Wildner } mutex_kind_t;
117e5a92d33SSascha Wildner 
118e5a92d33SSascha Wildner 
119e5a92d33SSascha Wildner /*------------------------------------------------------------
120e5a92d33SSascha Wildner  * Constants
121e5a92d33SSascha Wildner  *----------------------------------------------------------*/
122e5a92d33SSascha Wildner 
123e5a92d33SSascha Wildner const char *protocol_strs[] = {
124e5a92d33SSascha Wildner 	"PTHREAD_PRIO_NONE",
125e5a92d33SSascha Wildner 	"PTHREAD_PRIO_INHERIT",
126e5a92d33SSascha Wildner 	"PTHREAD_PRIO_PROTECT"
127e5a92d33SSascha Wildner };
128e5a92d33SSascha Wildner 
129e5a92d33SSascha Wildner const int protocols[] = {
130e5a92d33SSascha Wildner 	PTHREAD_PRIO_NONE,
131e5a92d33SSascha Wildner 	PTHREAD_PRIO_INHERIT,
132e5a92d33SSascha Wildner 	PTHREAD_PRIO_PROTECT
133e5a92d33SSascha Wildner };
134e5a92d33SSascha Wildner 
135e5a92d33SSascha Wildner const char *mutextype_strs[] = {
136e5a92d33SSascha Wildner 	"POSIX (type not specified)",
137e5a92d33SSascha Wildner 	"SS2 PTHREAD_MUTEX_DEFAULT",
138e5a92d33SSascha Wildner 	"SS2 PTHREAD_MUTEX_ERRORCHECK",
139e5a92d33SSascha Wildner 	"SS2 PTHREAD_MUTEX_NORMAL",
140e5a92d33SSascha Wildner 	"SS2 PTHREAD_MUTEX_RECURSIVE"
141e5a92d33SSascha Wildner };
142e5a92d33SSascha Wildner 
143e5a92d33SSascha Wildner const int mutex_types[] = {
144e5a92d33SSascha Wildner 	0,				/* M_POSIX		*/
145e5a92d33SSascha Wildner 	PTHREAD_MUTEX_DEFAULT,		/* M_SS2_DEFAULT	*/
146e5a92d33SSascha Wildner 	PTHREAD_MUTEX_ERRORCHECK,	/* M_SS2_ERRORCHECK	*/
147e5a92d33SSascha Wildner 	PTHREAD_MUTEX_NORMAL,		/* M_SS2_NORMAL		*/
148e5a92d33SSascha Wildner 	PTHREAD_MUTEX_RECURSIVE		/* M_SS2_RECURSIVE	*/
149e5a92d33SSascha Wildner };
150e5a92d33SSascha Wildner 
151e5a92d33SSascha Wildner 
152e5a92d33SSascha Wildner /*------------------------------------------------------------
153e5a92d33SSascha Wildner  * Objects
154e5a92d33SSascha Wildner  *----------------------------------------------------------*/
155e5a92d33SSascha Wildner 
156e5a92d33SSascha Wildner static int		done = 0;
157e5a92d33SSascha Wildner static int		trace_enabled = 0;
158e5a92d33SSascha Wildner static int		use_global_condvar = 0;
159e5a92d33SSascha Wildner static thread_state_t	states[NUM_THREADS];
160e5a92d33SSascha Wildner static int		pipefd[2];
161e5a92d33SSascha Wildner 
162e5a92d33SSascha Wildner static pthread_mutex_t	waiter_mutex;
163e5a92d33SSascha Wildner static pthread_mutex_t	cond_mutex;
164e5a92d33SSascha Wildner static pthread_cond_t	cond_var;
165e5a92d33SSascha Wildner 
166e5a92d33SSascha Wildner static FILE *logfile;
167e5a92d33SSascha Wildner static int error_count = 0, pass_count = 0, total = 0;
168e5a92d33SSascha Wildner 
169e5a92d33SSascha Wildner 
170e5a92d33SSascha Wildner /*------------------------------------------------------------
171e5a92d33SSascha Wildner  * Prototypes
172e5a92d33SSascha Wildner  *----------------------------------------------------------*/
173e5a92d33SSascha Wildner extern char *strtok_r(char *str, const char *sep, char **last);
174e5a92d33SSascha Wildner 
175e5a92d33SSascha Wildner 
176e5a92d33SSascha Wildner /*------------------------------------------------------------
177e5a92d33SSascha Wildner  * Functions
178e5a92d33SSascha Wildner  *----------------------------------------------------------*/
179e5a92d33SSascha Wildner 
180e5a92d33SSascha Wildner #ifdef DEBUG
181e5a92d33SSascha Wildner static void
kern_switch(pthread_t pthread_out,pthread_t pthread_in)182e5a92d33SSascha Wildner kern_switch (pthread_t pthread_out, pthread_t pthread_in)
183e5a92d33SSascha Wildner {
184e5a92d33SSascha Wildner 	if (pthread_out != NULL)
185e5a92d33SSascha Wildner 		printf ("Swapping out thread 0x%x, ", (int) pthread_out);
186e5a92d33SSascha Wildner 	else
187e5a92d33SSascha Wildner 		printf ("Swapping out kernel thread, ");
188e5a92d33SSascha Wildner 
189e5a92d33SSascha Wildner 	if (pthread_in != NULL)
190e5a92d33SSascha Wildner 		printf ("swapping in thread 0x%x\n", (int) pthread_in);
191e5a92d33SSascha Wildner 	else
192e5a92d33SSascha Wildner 		printf ("swapping in kernel thread.\n");
193e5a92d33SSascha Wildner }
194e5a92d33SSascha Wildner #endif
195e5a92d33SSascha Wildner 
196e5a92d33SSascha Wildner 
197e5a92d33SSascha Wildner static void
log_error(const char * fmt,...)198e5a92d33SSascha Wildner log_error (const char *fmt, ...)
199e5a92d33SSascha Wildner {
200e5a92d33SSascha Wildner 	va_list ap;
201e5a92d33SSascha Wildner 
202e5a92d33SSascha Wildner 	va_start (ap, fmt);
203e5a92d33SSascha Wildner 	fprintf (logfile, "FAIL: ");
204e5a92d33SSascha Wildner 	vfprintf (logfile, fmt, ap);
205e5a92d33SSascha Wildner 	error_count = error_count + 1;
206e5a92d33SSascha Wildner 	total = total + 1;
207e5a92d33SSascha Wildner }
208e5a92d33SSascha Wildner 
209e5a92d33SSascha Wildner 
210e5a92d33SSascha Wildner static void
log_pass(void)211e5a92d33SSascha Wildner log_pass (void)
212e5a92d33SSascha Wildner {
213e5a92d33SSascha Wildner 	fprintf (logfile, "PASS\n");
214e5a92d33SSascha Wildner 	pass_count = pass_count + 1;
215e5a92d33SSascha Wildner 	total = total + 1;
216e5a92d33SSascha Wildner }
217e5a92d33SSascha Wildner 
218e5a92d33SSascha Wildner 
219e5a92d33SSascha Wildner static void
log_trace(const char * fmt,...)220e5a92d33SSascha Wildner log_trace (const char *fmt, ...)
221e5a92d33SSascha Wildner {
222e5a92d33SSascha Wildner 	va_list ap;
223e5a92d33SSascha Wildner 
224e5a92d33SSascha Wildner 	if (trace_enabled) {
225e5a92d33SSascha Wildner 		va_start (ap, fmt);
226e5a92d33SSascha Wildner 		vfprintf (logfile, fmt, ap);
227e5a92d33SSascha Wildner 	}
228e5a92d33SSascha Wildner }
229e5a92d33SSascha Wildner 
230e5a92d33SSascha Wildner 
231e5a92d33SSascha Wildner static void
log_info(const char * fmt,...)232*62481538SSascha Wildner log_info (const char *fmt, ...)
233e5a92d33SSascha Wildner {
234e5a92d33SSascha Wildner 	va_list ap;
235e5a92d33SSascha Wildner 
236e5a92d33SSascha Wildner 	va_start (ap, fmt);
237e5a92d33SSascha Wildner 	vfprintf (logfile, fmt, ap);
238e5a92d33SSascha Wildner }
239e5a92d33SSascha Wildner 
240e5a92d33SSascha Wildner 
241e5a92d33SSascha Wildner static void
check_result(int expected,int actual)242e5a92d33SSascha Wildner check_result (int expected, int actual)
243e5a92d33SSascha Wildner {
244e5a92d33SSascha Wildner 	if (expected != actual)
245e5a92d33SSascha Wildner 		log_error ("expected %d, returned %d\n", expected, actual);
246e5a92d33SSascha Wildner 	else
247e5a92d33SSascha Wildner 		log_pass ();
248e5a92d33SSascha Wildner }
249e5a92d33SSascha Wildner 
250e5a92d33SSascha Wildner 
251e5a92d33SSascha Wildner /*
252e5a92d33SSascha Wildner  * Check to see that the threads ran in the specified order.
253e5a92d33SSascha Wildner  */
254e5a92d33SSascha Wildner static void
check_run_order(char * order)255e5a92d33SSascha Wildner check_run_order (char *order)
256e5a92d33SSascha Wildner {
257e5a92d33SSascha Wildner 	const char *sep = ":,";
258e5a92d33SSascha Wildner 	char *tok, *last, *idstr, *endptr;
259e5a92d33SSascha Wildner 	int expected_id, bytes, count = 0, errors = 0;
260e5a92d33SSascha Wildner 	u_int8_t id;
261e5a92d33SSascha Wildner 
262e5a92d33SSascha Wildner 	assert ((tok = (char *) malloc (strlen(order) + 1)) != NULL);
263e5a92d33SSascha Wildner 	strcpy (tok, order);	/* tok has to be larger than order */
264e5a92d33SSascha Wildner 	assert (ioctl (pipefd[0], FIONREAD, &bytes) == 0);
265e5a92d33SSascha Wildner 	log_trace ("%d bytes read from FIFO.\n", bytes);
266e5a92d33SSascha Wildner 
267e5a92d33SSascha Wildner 	for (idstr = strtok_r (tok, sep, &last);
268e5a92d33SSascha Wildner 	     (idstr != NULL) && (count < bytes);
269e5a92d33SSascha Wildner 	     idstr = strtok_r (NULL, sep, &last)) {
270e5a92d33SSascha Wildner 
271e5a92d33SSascha Wildner 		/* Get the expected id: */
272e5a92d33SSascha Wildner 		expected_id = (int) strtol (idstr, &endptr, 10);
273e5a92d33SSascha Wildner 		assert ((endptr != NULL) && (*endptr == '\0'));
274e5a92d33SSascha Wildner 
275e5a92d33SSascha Wildner 		/* Read the actual id from the pipe: */
276e5a92d33SSascha Wildner 		assert (read (pipefd[0], &id, sizeof (id)) == sizeof (id));
277e5a92d33SSascha Wildner 		count = count + sizeof (id);
278e5a92d33SSascha Wildner 
279e5a92d33SSascha Wildner 		if (id != expected_id) {
280e5a92d33SSascha Wildner 			log_trace ("Thread %d ran out of order.\n", id);
281e5a92d33SSascha Wildner 			errors = errors + 1;
282e5a92d33SSascha Wildner 		}
283e5a92d33SSascha Wildner 		else {
284e5a92d33SSascha Wildner 			log_trace ("Thread %d at priority %d reporting.\n",
285e5a92d33SSascha Wildner 			    (int) id, states[id].priority);
286e5a92d33SSascha Wildner 		}
287e5a92d33SSascha Wildner 	}
288e5a92d33SSascha Wildner 
289e5a92d33SSascha Wildner 	if (count < bytes) {
290e5a92d33SSascha Wildner 		/* Clear the pipe: */
291e5a92d33SSascha Wildner 		while (count < bytes) {
292e5a92d33SSascha Wildner 			read (pipefd[0], &id, sizeof (id));
293e5a92d33SSascha Wildner 			count = count + 1;
294e5a92d33SSascha Wildner 			errors = errors + 1;
295e5a92d33SSascha Wildner 		}
296e5a92d33SSascha Wildner 	}
297e5a92d33SSascha Wildner 	else if (bytes < count)
298e5a92d33SSascha Wildner 		errors = errors + count - bytes;
299e5a92d33SSascha Wildner 
300e5a92d33SSascha Wildner 	if (errors == 0)
301e5a92d33SSascha Wildner 		log_pass ();
302e5a92d33SSascha Wildner 	else
303*62481538SSascha Wildner 		log_error ("%d threads ran out of order\n", errors);
304e5a92d33SSascha Wildner }
305e5a92d33SSascha Wildner 
306e5a92d33SSascha Wildner 
307e5a92d33SSascha Wildner static void *
waiter(void * arg)308e5a92d33SSascha Wildner waiter (void *arg)
309e5a92d33SSascha Wildner {
310e5a92d33SSascha Wildner 	thread_state_t	*statep = (thread_state_t *) arg;
311e5a92d33SSascha Wildner 	pthread_mutex_t	*held_mutex[MAX_THREAD_CMDS];
312e5a92d33SSascha Wildner 	int 		held_mutex_owned[MAX_THREAD_CMDS];
313e5a92d33SSascha Wildner 	sigset_t	mask;
314e5a92d33SSascha Wildner 	struct timeval	tv1, tv2;
315e5a92d33SSascha Wildner 	thread_cmd_t	cmd;
316e5a92d33SSascha Wildner 	int 		i, mutex_count = 0;
317e5a92d33SSascha Wildner 
318e5a92d33SSascha Wildner 	statep->status = STAT_INITIAL;
319e5a92d33SSascha Wildner 
320e5a92d33SSascha Wildner 	/* Block all signals except for interrupt.*/
321e5a92d33SSascha Wildner 	sigfillset (&mask);
322e5a92d33SSascha Wildner 	sigdelset (&mask, SIGINT);
323e5a92d33SSascha Wildner 	sigprocmask (SIG_BLOCK, &mask, NULL);
324e5a92d33SSascha Wildner 
325e5a92d33SSascha Wildner 	while (done == 0) {
326e5a92d33SSascha Wildner 		/* Wait for signal from the main thread to continue. */
327e5a92d33SSascha Wildner 		statep->status = STAT_WAITMUTEX;
328e5a92d33SSascha Wildner 		log_trace ("Thread %d: locking cond_mutex.\n",
329e5a92d33SSascha Wildner 		    (int) statep->id);
330e5a92d33SSascha Wildner 		pthread_mutex_lock (&cond_mutex);
331e5a92d33SSascha Wildner 
332e5a92d33SSascha Wildner 		/* Do we report our status. */
333e5a92d33SSascha Wildner 		if (statep->flags & FLAGS_REPORT_WAITCONDMUTEX)
334e5a92d33SSascha Wildner 			write (pipefd[1], &statep->id, sizeof (statep->id));
335e5a92d33SSascha Wildner 		log_trace ("Thread %d: waiting for cond_var.\n",
336e5a92d33SSascha Wildner 		    (int) statep->id);
337e5a92d33SSascha Wildner 
338e5a92d33SSascha Wildner 		/* Wait for a command. */
339e5a92d33SSascha Wildner 		statep->status = STAT_WAITCONDVAR;
340e5a92d33SSascha Wildner 
341e5a92d33SSascha Wildner 		/*
342e5a92d33SSascha Wildner 		 * The threads are allowed commanded to wait either on
343e5a92d33SSascha Wildner 		 * their own unique condition variable (so they may be
344e5a92d33SSascha Wildner 		 * separately signaled) or on one global condition variable
345e5a92d33SSascha Wildner 		 * (so they may be signaled together).
346e5a92d33SSascha Wildner 		 */
347e5a92d33SSascha Wildner 		if (use_global_condvar != 0)
348e5a92d33SSascha Wildner 			pthread_cond_wait (&cond_var, &cond_mutex);
349e5a92d33SSascha Wildner 		else
350e5a92d33SSascha Wildner 			pthread_cond_wait (&statep->cond_var, &cond_mutex);
351e5a92d33SSascha Wildner 
352e5a92d33SSascha Wildner 		/* Do we report our status? */
353e5a92d33SSascha Wildner 		if (statep->flags & FLAGS_REPORT_WAITCONDVAR) {
354e5a92d33SSascha Wildner 			write (pipefd[1], &statep->id, sizeof (statep->id));
355e5a92d33SSascha Wildner 			log_trace ("Thread %d: wrote to pipe.\n",
356e5a92d33SSascha Wildner 			    (int) statep->id);
357e5a92d33SSascha Wildner 		}
358e5a92d33SSascha Wildner 		log_trace ("Thread %d: received cond_var signal.\n",
359e5a92d33SSascha Wildner 		    (int) statep->id);
360e5a92d33SSascha Wildner 
361e5a92d33SSascha Wildner 		/* Get a copy of the command before releasing the mutex. */
362e5a92d33SSascha Wildner 		cmd = statep->cmd;
363e5a92d33SSascha Wildner 
364e5a92d33SSascha Wildner 		/* Clear the command after copying it. */
365e5a92d33SSascha Wildner 		statep->cmd.cmd_id = CMD_NONE;
366e5a92d33SSascha Wildner 
367e5a92d33SSascha Wildner 		/* Unlock the condition variable mutex. */
368e5a92d33SSascha Wildner 		assert (pthread_mutex_unlock (&cond_mutex) == 0);
369e5a92d33SSascha Wildner 
370e5a92d33SSascha Wildner 		/* Peform the command.*/
371e5a92d33SSascha Wildner 		switch (cmd.cmd_id) {
372e5a92d33SSascha Wildner 		case CMD_TAKE_MUTEX:
373e5a92d33SSascha Wildner 			statep->ret = pthread_mutex_lock (cmd.mutex);
374e5a92d33SSascha Wildner 			if (statep->ret == 0) {
375e5a92d33SSascha Wildner 				assert (mutex_count < sizeof (held_mutex));
376e5a92d33SSascha Wildner 				held_mutex[mutex_count] = cmd.mutex;
377e5a92d33SSascha Wildner 				held_mutex_owned[mutex_count] = 1;
378e5a92d33SSascha Wildner 				mutex_count++;
379e5a92d33SSascha Wildner 			}
380e5a92d33SSascha Wildner 			else {
381e5a92d33SSascha Wildner 				held_mutex_owned[mutex_count] = 0;
382e5a92d33SSascha Wildner 				log_trace ("Thread id %d unable to lock mutex, "
383e5a92d33SSascha Wildner 				    "error = %d\n", (int) statep->id,
384e5a92d33SSascha Wildner 				    statep->ret);
385e5a92d33SSascha Wildner 			}
386e5a92d33SSascha Wildner 			break;
387e5a92d33SSascha Wildner 
388e5a92d33SSascha Wildner 		case CMD_RELEASE_MUTEX:
389e5a92d33SSascha Wildner 			assert ((mutex_count <= sizeof (held_mutex)) &&
390e5a92d33SSascha Wildner 			    (mutex_count > 0));
391e5a92d33SSascha Wildner 			mutex_count--;
392e5a92d33SSascha Wildner 			if (held_mutex_owned[mutex_count] != 0)
393e5a92d33SSascha Wildner 				assert (pthread_mutex_unlock
394e5a92d33SSascha Wildner 				    (held_mutex[mutex_count]) == 0);
395e5a92d33SSascha Wildner 			break;
396e5a92d33SSascha Wildner 
397e5a92d33SSascha Wildner 		case CMD_WAIT_FOR_SIGNAL:
398e5a92d33SSascha Wildner 			assert (pthread_mutex_lock (cmd.mutex) == 0);
399e5a92d33SSascha Wildner 			assert (pthread_cond_wait (cmd.cond, cmd.mutex) == 0);
400e5a92d33SSascha Wildner 			assert (pthread_mutex_unlock (cmd.mutex) == 0);
401e5a92d33SSascha Wildner 			break;
402e5a92d33SSascha Wildner 
403e5a92d33SSascha Wildner 		case CMD_BUSY_LOOP:
404e5a92d33SSascha Wildner 			log_trace ("Thread %d: Entering busy loop.\n",
405e5a92d33SSascha Wildner 			    (int) statep->id);
406e5a92d33SSascha Wildner 			/* Spin for 15 seconds. */
407e5a92d33SSascha Wildner 			assert (gettimeofday (&tv2, NULL) == 0);
408e5a92d33SSascha Wildner 			tv1.tv_sec = tv2.tv_sec + 5;
409e5a92d33SSascha Wildner 			tv1.tv_usec = tv2.tv_usec;
410e5a92d33SSascha Wildner 			statep->flags |= FLAGS_IS_BUSY;
411e5a92d33SSascha Wildner 			while (timercmp (&tv2, &tv1,<)) {
412e5a92d33SSascha Wildner 				assert (gettimeofday (&tv2, NULL) == 0);
413e5a92d33SSascha Wildner 			}
414e5a92d33SSascha Wildner 			statep->flags &= ~FLAGS_IS_BUSY;
415e5a92d33SSascha Wildner 			statep->flags |= FLAGS_WAS_BUSY;
416e5a92d33SSascha Wildner 
417e5a92d33SSascha Wildner 			/* Do we report our status? */
418e5a92d33SSascha Wildner 			if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
419e5a92d33SSascha Wildner 				write (pipefd[1], &statep->id,
420e5a92d33SSascha Wildner 				    sizeof (statep->id));
421e5a92d33SSascha Wildner 
422e5a92d33SSascha Wildner 			log_trace ("Thread %d: Leaving busy loop.\n",
423e5a92d33SSascha Wildner 			    (int) statep->id);
424e5a92d33SSascha Wildner 			break;
425e5a92d33SSascha Wildner 
426e5a92d33SSascha Wildner 		case CMD_PROTECTED_OP:
427e5a92d33SSascha Wildner 			assert (pthread_mutex_lock (cmd.mutex) == 0);
428e5a92d33SSascha Wildner 			statep->flags |= FLAGS_WAS_BUSY;
429e5a92d33SSascha Wildner 			/* Do we report our status? */
430e5a92d33SSascha Wildner 			if (statep->flags & FLAGS_REPORT_BUSY_LOOP)
431e5a92d33SSascha Wildner 				write (pipefd[1], &statep->id,
432e5a92d33SSascha Wildner 				    sizeof (statep->id));
433e5a92d33SSascha Wildner 
434e5a92d33SSascha Wildner 			assert (pthread_mutex_unlock (cmd.mutex) == 0);
435e5a92d33SSascha Wildner 			break;
436e5a92d33SSascha Wildner 
437e5a92d33SSascha Wildner 		case CMD_RELEASE_ALL:
438e5a92d33SSascha Wildner 			assert ((mutex_count <= sizeof (held_mutex)) &&
439e5a92d33SSascha Wildner 			    (mutex_count > 0));
440e5a92d33SSascha Wildner 			for (i = mutex_count - 1; i >= 0; i--) {
441e5a92d33SSascha Wildner 				if (held_mutex_owned[i] != 0)
442e5a92d33SSascha Wildner 					assert (pthread_mutex_unlock
443e5a92d33SSascha Wildner 					    (held_mutex[i]) == 0);
444e5a92d33SSascha Wildner 			}
445e5a92d33SSascha Wildner 			mutex_count = 0;
446e5a92d33SSascha Wildner 			break;
447e5a92d33SSascha Wildner 
448e5a92d33SSascha Wildner 		case CMD_NONE:
449e5a92d33SSascha Wildner 		default:
450e5a92d33SSascha Wildner 			break;
451e5a92d33SSascha Wildner 		}
452e5a92d33SSascha Wildner 
453e5a92d33SSascha Wildner 		/* Wait for the big giant waiter lock. */
454e5a92d33SSascha Wildner 		statep->status = STAT_WAITMUTEX;
455e5a92d33SSascha Wildner 		log_trace ("Thread %d: waiting for big giant lock.\n",
456e5a92d33SSascha Wildner 		    (int) statep->id);
457e5a92d33SSascha Wildner 		pthread_mutex_lock (&waiter_mutex);
458e5a92d33SSascha Wildner 		if (statep->flags & FLAGS_REPORT_WAITMUTEX)
459e5a92d33SSascha Wildner 			write (pipefd[1], &statep->id, sizeof (statep->id));
460e5a92d33SSascha Wildner 		log_trace ("Thread %d: got big giant lock.\n",
461e5a92d33SSascha Wildner 		    (int) statep->id);
462e5a92d33SSascha Wildner 		statep->status = STAT_INITIAL;
463e5a92d33SSascha Wildner 		pthread_mutex_unlock (&waiter_mutex);
464e5a92d33SSascha Wildner 	}
465e5a92d33SSascha Wildner 
466*62481538SSascha Wildner 	log_trace ("Thread %d: Exiting thread 0x%p\n", (int) statep->id,
467*62481538SSascha Wildner 	    pthread_self());
468e5a92d33SSascha Wildner 	pthread_exit (arg);
469e5a92d33SSascha Wildner 	return (NULL);
470e5a92d33SSascha Wildner }
471e5a92d33SSascha Wildner 
472e5a92d33SSascha Wildner 
473e5a92d33SSascha Wildner static void *
lock_twice(void * arg)474e5a92d33SSascha Wildner lock_twice (void *arg)
475e5a92d33SSascha Wildner {
476e5a92d33SSascha Wildner 	thread_state_t	*statep = (thread_state_t *) arg;
477e5a92d33SSascha Wildner 	sigset_t	mask;
478e5a92d33SSascha Wildner 
479e5a92d33SSascha Wildner 	statep->status = STAT_INITIAL;
480e5a92d33SSascha Wildner 
481e5a92d33SSascha Wildner 	/* Block all signals except for interrupt.*/
482e5a92d33SSascha Wildner 	sigfillset (&mask);
483e5a92d33SSascha Wildner 	sigdelset (&mask, SIGINT);
484e5a92d33SSascha Wildner 	sigprocmask (SIG_BLOCK, &mask, NULL);
485e5a92d33SSascha Wildner 
486e5a92d33SSascha Wildner 	/* Wait for a signal to continue. */
487e5a92d33SSascha Wildner 	log_trace ("Thread %d: locking cond_mutex.\n", (int) statep->id);
488e5a92d33SSascha Wildner 	pthread_mutex_lock (&cond_mutex);
489e5a92d33SSascha Wildner 
490e5a92d33SSascha Wildner 	log_trace ("Thread %d: waiting for cond_var.\n", (int) statep->id);
491e5a92d33SSascha Wildner 	statep->status = STAT_WAITCONDVAR;
492e5a92d33SSascha Wildner 	pthread_cond_wait (&cond_var, &cond_mutex);
493e5a92d33SSascha Wildner 
494e5a92d33SSascha Wildner 	log_trace ("Thread %d: received cond_var signal.\n", (int) statep->id);
495e5a92d33SSascha Wildner 
496e5a92d33SSascha Wildner 	/* Unlock the condition variable mutex. */
497e5a92d33SSascha Wildner 	assert (pthread_mutex_unlock (&cond_mutex) == 0);
498e5a92d33SSascha Wildner 
499e5a92d33SSascha Wildner 	statep->status = STAT_WAITMUTEX;
500e5a92d33SSascha Wildner 	/* Lock the mutex once. */
501e5a92d33SSascha Wildner 	assert (pthread_mutex_lock (statep->cmd.mutex) == 0);
502e5a92d33SSascha Wildner 
503e5a92d33SSascha Wildner 	/* Lock it again and capture the error. */
504e5a92d33SSascha Wildner 	statep->ret = pthread_mutex_lock (statep->cmd.mutex);
505e5a92d33SSascha Wildner 	statep->status = 0;
506e5a92d33SSascha Wildner 
507e5a92d33SSascha Wildner 	assert (pthread_mutex_unlock (statep->cmd.mutex) == 0);
508e5a92d33SSascha Wildner 
509e5a92d33SSascha Wildner 	/* Unlock it again if it is locked recursively. */
510e5a92d33SSascha Wildner 	if (statep->ret == 0)
511e5a92d33SSascha Wildner 		pthread_mutex_unlock (statep->cmd.mutex);
512e5a92d33SSascha Wildner 
513*62481538SSascha Wildner 	log_trace ("Thread %d: Exiting thread 0x%p\n", (int) statep->id,
514*62481538SSascha Wildner 	    pthread_self());
515e5a92d33SSascha Wildner 	pthread_exit (arg);
516e5a92d33SSascha Wildner 	return (NULL);
517e5a92d33SSascha Wildner }
518e5a92d33SSascha Wildner 
519e5a92d33SSascha Wildner 
520e5a92d33SSascha Wildner static void
sighandler(int signo)521e5a92d33SSascha Wildner sighandler (int signo)
522e5a92d33SSascha Wildner {
523*62481538SSascha Wildner 	log_info ("Signal handler caught signal %d, thread id 0x%p\n",
524*62481538SSascha Wildner 	    signo, pthread_self());
525e5a92d33SSascha Wildner 
526e5a92d33SSascha Wildner 	if (signo == SIGINT)
527e5a92d33SSascha Wildner 		done = 1;
528e5a92d33SSascha Wildner }
529e5a92d33SSascha Wildner 
530e5a92d33SSascha Wildner 
531e5a92d33SSascha Wildner static void
send_cmd(int id,thread_cmd_id_t cmd)532e5a92d33SSascha Wildner send_cmd (int id, thread_cmd_id_t cmd)
533e5a92d33SSascha Wildner {
534e5a92d33SSascha Wildner 	assert (pthread_mutex_lock (&cond_mutex) == 0);
535e5a92d33SSascha Wildner 	assert (states[id].status == STAT_WAITCONDVAR);
536e5a92d33SSascha Wildner 	states[id].cmd.cmd_id = cmd;
537e5a92d33SSascha Wildner 	states[id].cmd.mutex = NULL;
538e5a92d33SSascha Wildner 	states[id].cmd.cond = NULL;
539e5a92d33SSascha Wildner 	/* Clear the busy flags. */
540e5a92d33SSascha Wildner 	states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
541e5a92d33SSascha Wildner 	assert (pthread_cond_signal (&states[id].cond_var) == 0);
542e5a92d33SSascha Wildner 	assert (pthread_mutex_unlock (&cond_mutex) == 0);
543e5a92d33SSascha Wildner }
544e5a92d33SSascha Wildner 
545e5a92d33SSascha Wildner 
546e5a92d33SSascha Wildner static void
send_mutex_cmd(int id,thread_cmd_id_t cmd,pthread_mutex_t * m)547e5a92d33SSascha Wildner send_mutex_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m)
548e5a92d33SSascha Wildner {
549e5a92d33SSascha Wildner 	assert (pthread_mutex_lock (&cond_mutex) == 0);
550e5a92d33SSascha Wildner 	assert (states[id].status == STAT_WAITCONDVAR);
551e5a92d33SSascha Wildner 	states[id].cmd.cmd_id = cmd;
552e5a92d33SSascha Wildner 	states[id].cmd.mutex = m;
553e5a92d33SSascha Wildner 	states[id].cmd.cond = NULL;
554e5a92d33SSascha Wildner 	/* Clear the busy flags. */
555e5a92d33SSascha Wildner 	states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
556e5a92d33SSascha Wildner 	assert (pthread_cond_signal (&states[id].cond_var) == 0);
557e5a92d33SSascha Wildner 	assert (pthread_mutex_unlock (&cond_mutex) == 0);
558e5a92d33SSascha Wildner }
559e5a92d33SSascha Wildner 
560e5a92d33SSascha Wildner 
561e5a92d33SSascha Wildner static void
send_mutex_cv_cmd(int id,thread_cmd_id_t cmd,pthread_mutex_t * m,pthread_cond_t * cv)562e5a92d33SSascha Wildner send_mutex_cv_cmd (int id, thread_cmd_id_t cmd, pthread_mutex_t *m,
563e5a92d33SSascha Wildner     pthread_cond_t *cv)
564e5a92d33SSascha Wildner {
565e5a92d33SSascha Wildner 	assert (pthread_mutex_lock (&cond_mutex) == 0);
566e5a92d33SSascha Wildner 	assert (states[id].status == STAT_WAITCONDVAR);
567e5a92d33SSascha Wildner 	states[id].cmd.cmd_id = cmd;
568e5a92d33SSascha Wildner 	states[id].cmd.mutex = m;
569e5a92d33SSascha Wildner 	states[id].cmd.cond = cv;
570e5a92d33SSascha Wildner 	/* Clear the busy flags. */
571e5a92d33SSascha Wildner 	states[id].flags &= ~(FLAGS_WAS_BUSY | FLAGS_IS_BUSY);
572e5a92d33SSascha Wildner 	assert (pthread_cond_signal (&states[id].cond_var) == 0);
573e5a92d33SSascha Wildner 	assert (pthread_mutex_unlock (&cond_mutex) == 0);
574e5a92d33SSascha Wildner }
575e5a92d33SSascha Wildner 
576e5a92d33SSascha Wildner 
577e5a92d33SSascha Wildner static void
mutex_init_test(void)578e5a92d33SSascha Wildner mutex_init_test (void)
579e5a92d33SSascha Wildner {
580e5a92d33SSascha Wildner 	pthread_mutexattr_t mattr;
581e5a92d33SSascha Wildner 	pthread_mutex_t	mutex;
582e5a92d33SSascha Wildner 	mutex_kind_t mkind;
583e5a92d33SSascha Wildner 	int mproto, ret;
584e5a92d33SSascha Wildner 
585e5a92d33SSascha Wildner 	/*
586e5a92d33SSascha Wildner 	 * Initialize a mutex attribute.
587e5a92d33SSascha Wildner 	 *
588e5a92d33SSascha Wildner 	 * pthread_mutexattr_init not tested for: ENOMEM
589e5a92d33SSascha Wildner 	 */
590e5a92d33SSascha Wildner 	assert (pthread_mutexattr_init (&mattr) == 0);
591e5a92d33SSascha Wildner 
592e5a92d33SSascha Wildner 	/*
593e5a92d33SSascha Wildner 	 * Initialize a mutex.
594e5a92d33SSascha Wildner 	 *
595e5a92d33SSascha Wildner 	 * pthread_mutex_init not tested for: EAGAIN ENOMEM EPERM EBUSY
596e5a92d33SSascha Wildner 	 */
597*62481538SSascha Wildner 	log_info ("Testing pthread_mutex_init\n");
598*62481538SSascha Wildner 	log_info ("--------------------------\n");
599e5a92d33SSascha Wildner 
600e5a92d33SSascha Wildner 	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
601e5a92d33SSascha Wildner 		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
602e5a92d33SSascha Wildner 			/* Initialize the mutex attribute. */
603e5a92d33SSascha Wildner 			assert (pthread_mutexattr_init (&mattr) == 0);
604e5a92d33SSascha Wildner 			assert (pthread_mutexattr_setprotocol (&mattr,
605e5a92d33SSascha Wildner 			    protocols[mproto]) == 0);
606e5a92d33SSascha Wildner 
607e5a92d33SSascha Wildner 			/*
608e5a92d33SSascha Wildner 			 * Ensure that the first mutex type is a POSIX
609e5a92d33SSascha Wildner 			 * compliant mutex.
610e5a92d33SSascha Wildner 			 */
611e5a92d33SSascha Wildner 			if (mkind != M_POSIX) {
612e5a92d33SSascha Wildner 				assert (pthread_mutexattr_settype (&mattr,
613e5a92d33SSascha Wildner 				    mutex_types[mkind]) == 0);
614e5a92d33SSascha Wildner 			}
615e5a92d33SSascha Wildner 
616*62481538SSascha Wildner 			log_info ("  Protocol %s, Type %s - ",
617e5a92d33SSascha Wildner 			    protocol_strs[mproto], mutextype_strs[mkind]);
618e5a92d33SSascha Wildner 			ret = pthread_mutex_init (&mutex, &mattr);
619e5a92d33SSascha Wildner 			check_result (/* expected */ 0, ret);
620e5a92d33SSascha Wildner 			assert (pthread_mutex_destroy (&mutex) == 0);
621e5a92d33SSascha Wildner 
622e5a92d33SSascha Wildner 			/*
623e5a92d33SSascha Wildner 			 * Destroy a mutex attribute.
624e5a92d33SSascha Wildner 			 *
625e5a92d33SSascha Wildner 			 * XXX - There should probably be a magic number
626e5a92d33SSascha Wildner 			 *       associated with a mutex attribute so that
627e5a92d33SSascha Wildner 			 *       destroy can be reasonably sure the attribute
628e5a92d33SSascha Wildner 			 *       is valid.
629e5a92d33SSascha Wildner 			 *
630e5a92d33SSascha Wildner 			 * pthread_mutexattr_destroy not tested for: EINVAL
631e5a92d33SSascha Wildner 			 */
632e5a92d33SSascha Wildner 			assert (pthread_mutexattr_destroy (&mattr) == 0);
633e5a92d33SSascha Wildner 		}
634e5a92d33SSascha Wildner 	}
635e5a92d33SSascha Wildner }
636e5a92d33SSascha Wildner 
637e5a92d33SSascha Wildner 
638e5a92d33SSascha Wildner static void
mutex_destroy_test(void)639e5a92d33SSascha Wildner mutex_destroy_test (void)
640e5a92d33SSascha Wildner {
641e5a92d33SSascha Wildner 	pthread_mutexattr_t mattr;
642e5a92d33SSascha Wildner 	pthread_mutex_t	mutex;
643e5a92d33SSascha Wildner 	pthread_condattr_t cattr;
644e5a92d33SSascha Wildner 	pthread_cond_t	cv;
645e5a92d33SSascha Wildner 	pthread_attr_t pattr;
646e5a92d33SSascha Wildner 	int mproto, ret;
647e5a92d33SSascha Wildner 	mutex_kind_t mkind;
648*62481538SSascha Wildner #if 0
649e5a92d33SSascha Wildner 	thread_state_t state;
650*62481538SSascha Wildner #endif
651e5a92d33SSascha Wildner 
652e5a92d33SSascha Wildner 	/*
653e5a92d33SSascha Wildner 	 * Destroy a mutex.
654e5a92d33SSascha Wildner 	 *
655e5a92d33SSascha Wildner 	 * XXX - There should probably be a magic number associated
656e5a92d33SSascha Wildner 	 *       with a mutex so that destroy can be reasonably sure
657e5a92d33SSascha Wildner 	 *       the mutex is valid.
658e5a92d33SSascha Wildner 	 *
659e5a92d33SSascha Wildner 	 * pthread_mutex_destroy not tested for:
660e5a92d33SSascha Wildner 	 */
661*62481538SSascha Wildner 	log_info ("Testing pthread_mutex_destroy\n");
662*62481538SSascha Wildner 	log_info ("-----------------------------\n");
663e5a92d33SSascha Wildner 
664e5a92d33SSascha Wildner 	assert (pthread_attr_init (&pattr) == 0);
665e5a92d33SSascha Wildner 	assert (pthread_attr_setdetachstate (&pattr,
666e5a92d33SSascha Wildner 	    PTHREAD_CREATE_DETACHED) == 0);
667*62481538SSascha Wildner #if 0
668e5a92d33SSascha Wildner 	state.flags = 0;	/* No flags yet. */
669*62481538SSascha Wildner #endif
670e5a92d33SSascha Wildner 
671e5a92d33SSascha Wildner 	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
672e5a92d33SSascha Wildner 		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
673e5a92d33SSascha Wildner 			/* Initialize the mutex attribute. */
674e5a92d33SSascha Wildner 			assert (pthread_mutexattr_init (&mattr) == 0);
675e5a92d33SSascha Wildner 			assert (pthread_mutexattr_setprotocol (&mattr,
676e5a92d33SSascha Wildner 			    protocols[mproto]) == 0);
677e5a92d33SSascha Wildner 
678e5a92d33SSascha Wildner 			/*
679e5a92d33SSascha Wildner 			 * Ensure that the first mutex type is a POSIX
680e5a92d33SSascha Wildner 			 * compliant mutex.
681e5a92d33SSascha Wildner 			 */
682e5a92d33SSascha Wildner 			if (mkind != M_POSIX) {
683e5a92d33SSascha Wildner 				assert (pthread_mutexattr_settype (&mattr,
684e5a92d33SSascha Wildner 				    mutex_types[mkind]) == 0);
685e5a92d33SSascha Wildner 			}
686e5a92d33SSascha Wildner 
687e5a92d33SSascha Wildner 			/* Create the mutex. */
688e5a92d33SSascha Wildner 			assert (pthread_mutex_init (&mutex, &mattr) == 0);
689e5a92d33SSascha Wildner 
690*62481538SSascha Wildner 			log_info ("  Protocol %s, Type %s\n",
691e5a92d33SSascha Wildner 			    protocol_strs[mproto], mutextype_strs[mkind]);
692e5a92d33SSascha Wildner 
693*62481538SSascha Wildner 			log_info ("    Destruction of unused mutex - ");
694e5a92d33SSascha Wildner 			assert (pthread_mutex_init (&mutex, &mattr) == 0);
695e5a92d33SSascha Wildner 			ret = pthread_mutex_destroy (&mutex);
696e5a92d33SSascha Wildner 			check_result (/* expected */ 0, ret);
697e5a92d33SSascha Wildner 
698*62481538SSascha Wildner 			log_info ("    Destruction of mutex locked by self - ");
699e5a92d33SSascha Wildner 			assert (pthread_mutex_init (&mutex, &mattr) == 0);
700e5a92d33SSascha Wildner 			assert (pthread_mutex_lock (&mutex) == 0);
701e5a92d33SSascha Wildner 			ret = pthread_mutex_destroy (&mutex);
702e5a92d33SSascha Wildner 			check_result (/* expected */ EBUSY, ret);
703e5a92d33SSascha Wildner 			assert (pthread_mutex_unlock (&mutex) == 0);
704e5a92d33SSascha Wildner 			assert (pthread_mutex_destroy (&mutex) == 0);
705e5a92d33SSascha Wildner 
706*62481538SSascha Wildner 			log_info ("    Destruction of mutex locked by another "
707e5a92d33SSascha Wildner 			    "thread - ");
708e5a92d33SSascha Wildner 			assert (pthread_mutex_init (&mutex, &mattr) == 0);
709e5a92d33SSascha Wildner 			send_mutex_cmd (0, CMD_TAKE_MUTEX, &mutex);
710e5a92d33SSascha Wildner 			sleep (1);
711e5a92d33SSascha Wildner 			ret = pthread_mutex_destroy (&mutex);
712e5a92d33SSascha Wildner 			check_result (/* expected */ EBUSY, ret);
713e5a92d33SSascha Wildner 			send_cmd (0, CMD_RELEASE_ALL);
714e5a92d33SSascha Wildner 			sleep (1);
715e5a92d33SSascha Wildner 			assert (pthread_mutex_destroy (&mutex) == 0);
716e5a92d33SSascha Wildner 
717*62481538SSascha Wildner 			log_info ("    Destruction of mutex while being used in "
718e5a92d33SSascha Wildner 			    "cond_wait - ");
719e5a92d33SSascha Wildner 			assert (pthread_mutex_init (&mutex, &mattr) == 0);
720e5a92d33SSascha Wildner 			assert (pthread_condattr_init (&cattr) == 0);
721e5a92d33SSascha Wildner 			assert (pthread_cond_init (&cv, &cattr) == 0);
722e5a92d33SSascha Wildner 			send_mutex_cv_cmd (0, CMD_WAIT_FOR_SIGNAL, &mutex, &cv);
723e5a92d33SSascha Wildner 			sleep (1);
724e5a92d33SSascha Wildner 			ret = pthread_mutex_destroy (&mutex);
725e5a92d33SSascha Wildner 			check_result (/* expected */ EBUSY, ret);
726e5a92d33SSascha Wildner 			pthread_cond_signal (&cv);
727e5a92d33SSascha Wildner 			sleep (1);
728e5a92d33SSascha Wildner 			assert (pthread_mutex_destroy (&mutex) == 0);
729e5a92d33SSascha Wildner 		}
730e5a92d33SSascha Wildner 	}
731e5a92d33SSascha Wildner }
732e5a92d33SSascha Wildner 
733e5a92d33SSascha Wildner 
734e5a92d33SSascha Wildner static void
mutex_lock_test(void)735e5a92d33SSascha Wildner mutex_lock_test (void)
736e5a92d33SSascha Wildner {
737e5a92d33SSascha Wildner 	pthread_mutexattr_t mattr;
738e5a92d33SSascha Wildner 	pthread_mutex_t	mutex;
739e5a92d33SSascha Wildner 	pthread_attr_t pattr;
740e5a92d33SSascha Wildner 	int mproto, ret;
741e5a92d33SSascha Wildner 	mutex_kind_t mkind;
742e5a92d33SSascha Wildner 	thread_state_t state;
743e5a92d33SSascha Wildner 
744e5a92d33SSascha Wildner 	/*
745e5a92d33SSascha Wildner 	 * Lock a mutex.
746e5a92d33SSascha Wildner 	 *
747e5a92d33SSascha Wildner 	 * pthread_lock not tested for:
748e5a92d33SSascha Wildner 	 */
749*62481538SSascha Wildner 	log_info ("Testing pthread_mutex_lock\n");
750*62481538SSascha Wildner 	log_info ("--------------------------\n");
751e5a92d33SSascha Wildner 
752e5a92d33SSascha Wildner 	assert (pthread_attr_init (&pattr) == 0);
753e5a92d33SSascha Wildner 	assert (pthread_attr_setdetachstate (&pattr,
754e5a92d33SSascha Wildner 	    PTHREAD_CREATE_DETACHED) == 0);
755e5a92d33SSascha Wildner 	state.flags = 0;	/* No flags yet. */
756e5a92d33SSascha Wildner 
757e5a92d33SSascha Wildner 	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
758e5a92d33SSascha Wildner 		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
759e5a92d33SSascha Wildner 			/* Initialize the mutex attribute. */
760e5a92d33SSascha Wildner 			assert (pthread_mutexattr_init (&mattr) == 0);
761e5a92d33SSascha Wildner 			assert (pthread_mutexattr_setprotocol (&mattr,
762e5a92d33SSascha Wildner 			    protocols[mproto]) == 0);
763e5a92d33SSascha Wildner 
764e5a92d33SSascha Wildner 			/*
765e5a92d33SSascha Wildner 			 * Ensure that the first mutex type is a POSIX
766e5a92d33SSascha Wildner 			 * compliant mutex.
767e5a92d33SSascha Wildner 			 */
768e5a92d33SSascha Wildner 			if (mkind != M_POSIX) {
769e5a92d33SSascha Wildner 				assert (pthread_mutexattr_settype (&mattr,
770e5a92d33SSascha Wildner 				    mutex_types[mkind]) == 0);
771e5a92d33SSascha Wildner 			}
772e5a92d33SSascha Wildner 
773e5a92d33SSascha Wildner 			/* Create the mutex. */
774e5a92d33SSascha Wildner 			assert (pthread_mutex_init (&mutex, &mattr) == 0);
775e5a92d33SSascha Wildner 
776*62481538SSascha Wildner 			log_info ("  Protocol %s, Type %s\n",
777e5a92d33SSascha Wildner 			    protocol_strs[mproto], mutextype_strs[mkind]);
778e5a92d33SSascha Wildner 
779*62481538SSascha Wildner 			log_info ("    Lock on unlocked mutex - ");
780e5a92d33SSascha Wildner 			ret = pthread_mutex_lock (&mutex);
781e5a92d33SSascha Wildner 			check_result (/* expected */ 0, ret);
782e5a92d33SSascha Wildner 			pthread_mutex_unlock (&mutex);
783e5a92d33SSascha Wildner 
784*62481538SSascha Wildner 			log_info ("    Lock on invalid mutex - ");
785e5a92d33SSascha Wildner 			ret = pthread_mutex_lock (NULL);
786e5a92d33SSascha Wildner 			check_result (/* expected */ EINVAL, ret);
787e5a92d33SSascha Wildner 
788*62481538SSascha Wildner 			log_info ("    Lock on mutex held by self - ");
789e5a92d33SSascha Wildner 			assert (pthread_create (&state.tid, &pattr, lock_twice,
790e5a92d33SSascha Wildner 			    (void *) &state) == 0);
791e5a92d33SSascha Wildner 			/* Let the thread start. */
792e5a92d33SSascha Wildner 			sleep (1);
793e5a92d33SSascha Wildner 			state.cmd.mutex = &mutex;
794e5a92d33SSascha Wildner 			state.ret = 0xdeadbeef;
795e5a92d33SSascha Wildner 			assert (pthread_mutex_lock (&cond_mutex) == 0);
796e5a92d33SSascha Wildner 			assert (pthread_cond_signal (&cond_var) == 0);
797e5a92d33SSascha Wildner 			assert (pthread_mutex_unlock (&cond_mutex) == 0);
798e5a92d33SSascha Wildner 			/* Let the thread receive and process the command. */
799e5a92d33SSascha Wildner 			sleep (1);
800e5a92d33SSascha Wildner 
801e5a92d33SSascha Wildner 			switch (mkind) {
802e5a92d33SSascha Wildner 			case M_POSIX:
803e5a92d33SSascha Wildner 				check_result (/* expected */ EDEADLK,
804e5a92d33SSascha Wildner 				    state.ret);
805e5a92d33SSascha Wildner 				break;
806e5a92d33SSascha Wildner 			case M_SS2_DEFAULT:
807e5a92d33SSascha Wildner 				check_result (/* expected */ EDEADLK,
808e5a92d33SSascha Wildner 				    state.ret);
809e5a92d33SSascha Wildner 				break;
810e5a92d33SSascha Wildner 			case M_SS2_ERRORCHECK:
811e5a92d33SSascha Wildner 				check_result (/* expected */ EDEADLK,
812e5a92d33SSascha Wildner 				    state.ret);
813e5a92d33SSascha Wildner 				break;
814e5a92d33SSascha Wildner 			case M_SS2_NORMAL:
815e5a92d33SSascha Wildner 				check_result (/* expected */ 0xdeadbeef,
816e5a92d33SSascha Wildner 				    state.ret);
817e5a92d33SSascha Wildner 				break;
818e5a92d33SSascha Wildner 			case M_SS2_RECURSIVE:
819e5a92d33SSascha Wildner 				check_result (/* expected */ 0, state.ret);
820e5a92d33SSascha Wildner 				break;
821e5a92d33SSascha Wildner 			}
822e5a92d33SSascha Wildner 			pthread_mutex_destroy (&mutex);
823e5a92d33SSascha Wildner 			pthread_mutexattr_destroy (&mattr);
824e5a92d33SSascha Wildner 		}
825e5a92d33SSascha Wildner 	}
826e5a92d33SSascha Wildner }
827e5a92d33SSascha Wildner 
828e5a92d33SSascha Wildner 
829e5a92d33SSascha Wildner static void
mutex_unlock_test(void)830e5a92d33SSascha Wildner mutex_unlock_test (void)
831e5a92d33SSascha Wildner {
832e5a92d33SSascha Wildner 	const int test_thread_id = 0;	/* ID of test thread */
833e5a92d33SSascha Wildner 	pthread_mutexattr_t mattr;
834e5a92d33SSascha Wildner 	pthread_mutex_t	mutex;
835e5a92d33SSascha Wildner 	int mproto, ret;
836e5a92d33SSascha Wildner 	mutex_kind_t mkind;
837e5a92d33SSascha Wildner 
838e5a92d33SSascha Wildner 	/*
839e5a92d33SSascha Wildner 	 * Unlock a mutex.
840e5a92d33SSascha Wildner 	 *
841e5a92d33SSascha Wildner 	 * pthread_unlock not tested for:
842e5a92d33SSascha Wildner 	 */
843*62481538SSascha Wildner 	log_info ("Testing pthread_mutex_unlock\n");
844*62481538SSascha Wildner 	log_info ("----------------------------\n");
845e5a92d33SSascha Wildner 
846e5a92d33SSascha Wildner 	for (mproto = 0; mproto < NELEMENTS(protocols); mproto++) {
847e5a92d33SSascha Wildner 		for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
848e5a92d33SSascha Wildner 			/* Initialize the mutex attribute. */
849e5a92d33SSascha Wildner 			assert (pthread_mutexattr_init (&mattr) == 0);
850e5a92d33SSascha Wildner 			assert (pthread_mutexattr_setprotocol (&mattr,
851e5a92d33SSascha Wildner 			    protocols[mproto]) == 0);
852e5a92d33SSascha Wildner 
853e5a92d33SSascha Wildner 			/*
854e5a92d33SSascha Wildner 			 * Ensure that the first mutex type is a POSIX
855e5a92d33SSascha Wildner 			 * compliant mutex.
856e5a92d33SSascha Wildner 			 */
857e5a92d33SSascha Wildner 			if (mkind != M_POSIX) {
858e5a92d33SSascha Wildner 				assert (pthread_mutexattr_settype (&mattr,
859e5a92d33SSascha Wildner 				    mutex_types[mkind]) == 0);
860e5a92d33SSascha Wildner 			}
861e5a92d33SSascha Wildner 
862e5a92d33SSascha Wildner 			/* Create the mutex. */
863e5a92d33SSascha Wildner 			assert (pthread_mutex_init (&mutex, &mattr) == 0);
864e5a92d33SSascha Wildner 
865*62481538SSascha Wildner 			log_info ("  Protocol %s, Type %s\n",
866e5a92d33SSascha Wildner 			    protocol_strs[mproto], mutextype_strs[mkind]);
867e5a92d33SSascha Wildner 
868*62481538SSascha Wildner 			log_info ("    Unlock on mutex held by self - ");
869e5a92d33SSascha Wildner 			assert (pthread_mutex_lock (&mutex) == 0);
870e5a92d33SSascha Wildner 			ret = pthread_mutex_unlock (&mutex);
871e5a92d33SSascha Wildner 			check_result (/* expected */ 0, ret);
872e5a92d33SSascha Wildner 
873*62481538SSascha Wildner 			log_info ("    Unlock on invalid mutex - ");
874e5a92d33SSascha Wildner 			ret = pthread_mutex_unlock (NULL);
875e5a92d33SSascha Wildner 			check_result (/* expected */ EINVAL, ret);
876e5a92d33SSascha Wildner 
877*62481538SSascha Wildner 			log_info ("    Unlock on mutex locked by another thread - ");
878e5a92d33SSascha Wildner 			send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &mutex);
879e5a92d33SSascha Wildner 			sleep (1);
880e5a92d33SSascha Wildner 			ret = pthread_mutex_unlock (&mutex);
881e5a92d33SSascha Wildner 			switch (mkind) {
882e5a92d33SSascha Wildner 			case M_POSIX:
883e5a92d33SSascha Wildner 				check_result (/* expected */ EPERM, ret);
884e5a92d33SSascha Wildner 				break;
885e5a92d33SSascha Wildner 			case M_SS2_DEFAULT:
886e5a92d33SSascha Wildner 				check_result (/* expected */ EPERM, ret);
887e5a92d33SSascha Wildner 				break;
888e5a92d33SSascha Wildner 			case M_SS2_ERRORCHECK:
889e5a92d33SSascha Wildner 				check_result (/* expected */ EPERM, ret);
890e5a92d33SSascha Wildner 				break;
891e5a92d33SSascha Wildner 			case M_SS2_NORMAL:
892e5a92d33SSascha Wildner 				check_result (/* expected */ EPERM, ret);
893e5a92d33SSascha Wildner 				break;
894e5a92d33SSascha Wildner 			case M_SS2_RECURSIVE:
895e5a92d33SSascha Wildner 				check_result (/* expected */ EPERM, ret);
896e5a92d33SSascha Wildner 				break;
897e5a92d33SSascha Wildner 			}
898e5a92d33SSascha Wildner 			if (ret == 0) {
899e5a92d33SSascha Wildner 				/*
900e5a92d33SSascha Wildner 				 * If for some reason we were able to unlock
901e5a92d33SSascha Wildner 				 * the mutex, relock it so that the test
902e5a92d33SSascha Wildner 				 * thread has no problems releasing the mutex.
903e5a92d33SSascha Wildner 				 */
904e5a92d33SSascha Wildner 				pthread_mutex_lock (&mutex);
905e5a92d33SSascha Wildner 			}
906e5a92d33SSascha Wildner 			send_cmd (test_thread_id, CMD_RELEASE_ALL);
907e5a92d33SSascha Wildner 			sleep (1);
908e5a92d33SSascha Wildner 
909e5a92d33SSascha Wildner 			pthread_mutex_destroy (&mutex);
910e5a92d33SSascha Wildner 			pthread_mutexattr_destroy (&mattr);
911e5a92d33SSascha Wildner 		}
912e5a92d33SSascha Wildner 	}
913e5a92d33SSascha Wildner }
914e5a92d33SSascha Wildner 
915e5a92d33SSascha Wildner 
916e5a92d33SSascha Wildner static void
queueing_order_test(void)917e5a92d33SSascha Wildner queueing_order_test (void)
918e5a92d33SSascha Wildner {
919e5a92d33SSascha Wildner 	int i;
920e5a92d33SSascha Wildner 
921*62481538SSascha Wildner 	log_info ("Testing queueing order\n");
922*62481538SSascha Wildner 	log_info ("----------------------\n");
923e5a92d33SSascha Wildner 	assert (pthread_mutex_lock (&waiter_mutex) == 0);
924e5a92d33SSascha Wildner 	/*
925e5a92d33SSascha Wildner 	 * Tell the threads to report when they take the waiters mutex.
926e5a92d33SSascha Wildner 	 */
927e5a92d33SSascha Wildner 	assert (pthread_mutex_lock (&cond_mutex) == 0);
928e5a92d33SSascha Wildner 	for (i = 0; i < NUM_THREADS; i++) {
929e5a92d33SSascha Wildner 		states[i].flags = FLAGS_REPORT_WAITMUTEX;
930e5a92d33SSascha Wildner 		assert (pthread_cond_signal (&states[i].cond_var) == 0);
931e5a92d33SSascha Wildner 	}
932e5a92d33SSascha Wildner 	assert (pthread_mutex_unlock (&cond_mutex) == 0);
933e5a92d33SSascha Wildner 
934e5a92d33SSascha Wildner 	/* Signal the threads to continue. */
935e5a92d33SSascha Wildner 	sleep (1);
936e5a92d33SSascha Wildner 
937e5a92d33SSascha Wildner 	/* Use the global condition variable next time. */
938e5a92d33SSascha Wildner 	use_global_condvar = 1;
939e5a92d33SSascha Wildner 
940e5a92d33SSascha Wildner 	/* Release the waiting threads and allow them to run again. */
941e5a92d33SSascha Wildner 	assert (pthread_mutex_unlock (&waiter_mutex) == 0);
942e5a92d33SSascha Wildner 	sleep (1);
943e5a92d33SSascha Wildner 
944*62481538SSascha Wildner 	log_info ("  Queueing order on a mutex - ");
945e5a92d33SSascha Wildner 	check_run_order ("9,8,7,6,5,4,3,2,1,0");
946e5a92d33SSascha Wildner 	for (i = 0; i < NUM_THREADS; i = i + 1) {
947e5a92d33SSascha Wildner 		/* Tell the threads to report when they've been signaled. */
948e5a92d33SSascha Wildner 		states[i].flags = FLAGS_REPORT_WAITCONDVAR;
949e5a92d33SSascha Wildner 	}
950e5a92d33SSascha Wildner 
951e5a92d33SSascha Wildner 	/*
952e5a92d33SSascha Wildner 	 * Prevent the threads from continuing their loop after we
953e5a92d33SSascha Wildner 	 * signal them.
954e5a92d33SSascha Wildner 	 */
955e5a92d33SSascha Wildner 	assert (pthread_mutex_lock (&waiter_mutex) == 0);
956e5a92d33SSascha Wildner 
957e5a92d33SSascha Wildner 
958*62481538SSascha Wildner 	log_info ("  Queueing order on a condition variable - ");
959e5a92d33SSascha Wildner 	/*
960e5a92d33SSascha Wildner 	 * Signal one thread to run and see that the highest priority
961e5a92d33SSascha Wildner 	 * thread executes.
962e5a92d33SSascha Wildner 	 */
963e5a92d33SSascha Wildner 	assert (pthread_mutex_lock (&cond_mutex) == 0);
964e5a92d33SSascha Wildner 	assert (pthread_cond_signal (&cond_var) == 0);
965e5a92d33SSascha Wildner 	assert (pthread_mutex_unlock (&cond_mutex) == 0);
966e5a92d33SSascha Wildner 	sleep (1);
967e5a92d33SSascha Wildner 	if (states[NUM_THREADS - 1].status != STAT_WAITMUTEX)
968e5a92d33SSascha Wildner 		log_error ("highest priority thread does not run.\n");
969e5a92d33SSascha Wildner 
970e5a92d33SSascha Wildner 	/* Signal the remaining threads. */
971e5a92d33SSascha Wildner 	assert (pthread_mutex_lock (&cond_mutex) == 0);
972e5a92d33SSascha Wildner 	assert (pthread_cond_broadcast (&cond_var) == 0);
973e5a92d33SSascha Wildner 	assert (pthread_mutex_unlock (&cond_mutex) == 0);
974e5a92d33SSascha Wildner 	sleep (1);
975e5a92d33SSascha Wildner 
976e5a92d33SSascha Wildner 	check_run_order ("9,8,7,6,5,4,3,2,1,0");
977e5a92d33SSascha Wildner 	for (i = 0; i < NUM_THREADS; i = i + 1) {
978e5a92d33SSascha Wildner 		/* Tell the threads not to report anything. */
979e5a92d33SSascha Wildner 		states[i].flags = 0;
980e5a92d33SSascha Wildner 	}
981e5a92d33SSascha Wildner 
982e5a92d33SSascha Wildner 	/* Use the thread unique condition variable next time. */
983e5a92d33SSascha Wildner 	use_global_condvar = 0;
984e5a92d33SSascha Wildner 
985e5a92d33SSascha Wildner 	/* Allow the threads to continue their loop. */
986e5a92d33SSascha Wildner 	assert (pthread_mutex_unlock (&waiter_mutex) == 0);
987e5a92d33SSascha Wildner 	sleep (1);
988e5a92d33SSascha Wildner }
989e5a92d33SSascha Wildner 
990e5a92d33SSascha Wildner 
991e5a92d33SSascha Wildner static void
mutex_prioceiling_test(void)992e5a92d33SSascha Wildner mutex_prioceiling_test (void)
993e5a92d33SSascha Wildner {
994e5a92d33SSascha Wildner 	const int test_thread_id = 0;	/* ID of test thread */
995e5a92d33SSascha Wildner 	pthread_mutexattr_t mattr;
996e5a92d33SSascha Wildner 	struct sched_param param;
997e5a92d33SSascha Wildner 	pthread_mutex_t	m[3];
998e5a92d33SSascha Wildner 	mutex_kind_t	mkind;
999e5a92d33SSascha Wildner 	int		i, ret, policy, my_prio, old_ceiling;
1000e5a92d33SSascha Wildner 
1001*62481538SSascha Wildner 	log_info ("Testing priority ceilings\n");
1002*62481538SSascha Wildner 	log_info ("-------------------------\n");
1003e5a92d33SSascha Wildner 	for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
1004e5a92d33SSascha Wildner 
1005*62481538SSascha Wildner 		log_info ("  Protype PTHREAD_PRIO_PROTECT, Type %s\n",
1006e5a92d33SSascha Wildner 		    mutextype_strs[mkind]);
1007e5a92d33SSascha Wildner 
1008e5a92d33SSascha Wildner 		/*
1009e5a92d33SSascha Wildner 		 * Initialize and create a mutex.
1010e5a92d33SSascha Wildner 		 */
1011e5a92d33SSascha Wildner 		assert (pthread_mutexattr_init (&mattr) == 0);
1012e5a92d33SSascha Wildner 
1013e5a92d33SSascha Wildner 		/* Get this threads current priority. */
1014e5a92d33SSascha Wildner 		assert (pthread_getschedparam (pthread_self(), &policy,
1015e5a92d33SSascha Wildner 		    &param) == 0);
1016e5a92d33SSascha Wildner 		my_prio = param.sched_priority;	/* save for later use */
1017e5a92d33SSascha Wildner 		log_trace ("Current scheduling policy %d, priority %d\n",
1018e5a92d33SSascha Wildner 		    policy, my_prio);
1019e5a92d33SSascha Wildner 
1020e5a92d33SSascha Wildner 		/*
1021e5a92d33SSascha Wildner 		 * Initialize and create 3 priority protection mutexes with
1022e5a92d33SSascha Wildner 		 * default (max priority) ceilings.
1023e5a92d33SSascha Wildner 		 */
1024e5a92d33SSascha Wildner 		assert (pthread_mutexattr_setprotocol(&mattr,
1025e5a92d33SSascha Wildner 		    PTHREAD_PRIO_PROTECT) == 0);
1026e5a92d33SSascha Wildner 
1027e5a92d33SSascha Wildner 		/*
1028e5a92d33SSascha Wildner 		 * Ensure that the first mutex type is a POSIX
1029e5a92d33SSascha Wildner 		 * compliant mutex.
1030e5a92d33SSascha Wildner 		 */
1031e5a92d33SSascha Wildner 		if (mkind != M_POSIX) {
1032e5a92d33SSascha Wildner 			assert (pthread_mutexattr_settype (&mattr,
1033e5a92d33SSascha Wildner 			    mutex_types[mkind]) == 0);
1034e5a92d33SSascha Wildner 		}
1035e5a92d33SSascha Wildner 
1036e5a92d33SSascha Wildner 		for (i = 0; i < 3; i++)
1037e5a92d33SSascha Wildner 			assert (pthread_mutex_init (&m[i], &mattr) == 0);
1038e5a92d33SSascha Wildner 
1039e5a92d33SSascha Wildner 		/*
1040e5a92d33SSascha Wildner 		 * Set the ceiling priorities for the 3 priority protection
1041e5a92d33SSascha Wildner 		 * mutexes to, 5 less than, equal to, and 5 greater than,
1042e5a92d33SSascha Wildner 		 * this threads current priority.
1043e5a92d33SSascha Wildner 		 */
1044e5a92d33SSascha Wildner 		for (i = 0; i < 3; i++)
1045e5a92d33SSascha Wildner 			assert (pthread_mutex_setprioceiling (&m[i],
1046e5a92d33SSascha Wildner 			    my_prio - 5 + 5*i, &old_ceiling) == 0);
1047e5a92d33SSascha Wildner 
1048e5a92d33SSascha Wildner 		/*
1049e5a92d33SSascha Wildner 		 * Check that if we attempt to take a mutex whose priority
1050e5a92d33SSascha Wildner 		 * ceiling is lower than our priority, we get an error.
1051e5a92d33SSascha Wildner 		 */
1052*62481538SSascha Wildner 		log_info ("    Lock with ceiling priority < thread priority - ");
1053e5a92d33SSascha Wildner 		ret = pthread_mutex_lock (&m[0]);
1054e5a92d33SSascha Wildner 		check_result (/* expected */ EINVAL, ret);
1055e5a92d33SSascha Wildner 		if (ret == 0)
1056e5a92d33SSascha Wildner 			pthread_mutex_unlock (&m[0]);
1057e5a92d33SSascha Wildner 
1058e5a92d33SSascha Wildner 		/*
1059e5a92d33SSascha Wildner 		 * Check that we can take a mutex whose priority ceiling
1060e5a92d33SSascha Wildner 		 * is equal to our priority.
1061e5a92d33SSascha Wildner 		 */
1062*62481538SSascha Wildner 		log_info ("    Lock with ceiling priority = thread priority - ");
1063e5a92d33SSascha Wildner 		ret = pthread_mutex_lock (&m[1]);
1064e5a92d33SSascha Wildner 		check_result (/* expected */ 0, ret);
1065e5a92d33SSascha Wildner 		if (ret == 0)
1066e5a92d33SSascha Wildner 			pthread_mutex_unlock (&m[1]);
1067e5a92d33SSascha Wildner 
1068e5a92d33SSascha Wildner 		/*
1069e5a92d33SSascha Wildner 		 * Check that we can take a mutex whose priority ceiling
1070e5a92d33SSascha Wildner 		 * is higher than our priority.
1071e5a92d33SSascha Wildner 		 */
1072*62481538SSascha Wildner 		log_info ("    Lock with ceiling priority > thread priority - ");
1073e5a92d33SSascha Wildner 		ret = pthread_mutex_lock (&m[2]);
1074e5a92d33SSascha Wildner 		check_result (/* expected */ 0, ret);
1075e5a92d33SSascha Wildner 		if (ret == 0)
1076e5a92d33SSascha Wildner 			pthread_mutex_unlock (&m[2]);
1077e5a92d33SSascha Wildner 
1078e5a92d33SSascha Wildner 		/*
1079e5a92d33SSascha Wildner 		 * Have the test thread go into a busy loop for 5 seconds
1080e5a92d33SSascha Wildner 		 * and see that it doesn't block this thread (since the
1081e5a92d33SSascha Wildner 		 * priority ceiling of mutex 0 and the priority of the test
1082e5a92d33SSascha Wildner 		 * thread are both less than the priority of this thread).
1083e5a92d33SSascha Wildner 		 */
1084*62481538SSascha Wildner 		log_info ("    Preemption with ceiling priority < thread "
1085e5a92d33SSascha Wildner 		    "priority - ");
1086e5a92d33SSascha Wildner 		/* Have the test thread take mutex 0. */
1087e5a92d33SSascha Wildner 		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[0]);
1088e5a92d33SSascha Wildner 		sleep (1);
1089e5a92d33SSascha Wildner 
1090e5a92d33SSascha Wildner 		log_trace ("Sending busy command.\n");
1091e5a92d33SSascha Wildner 		send_cmd (test_thread_id, CMD_BUSY_LOOP);
1092e5a92d33SSascha Wildner 		log_trace ("Busy sent, yielding\n");
1093e5a92d33SSascha Wildner 		pthread_yield ();
1094e5a92d33SSascha Wildner 		log_trace ("Returned from yield.\n");
1095e5a92d33SSascha Wildner 		if (states[test_thread_id].flags &
1096e5a92d33SSascha Wildner 		    (FLAGS_IS_BUSY | FLAGS_WAS_BUSY))
1097e5a92d33SSascha Wildner 			log_error ("test thread inproperly preempted us.\n");
1098e5a92d33SSascha Wildner 		else {
1099e5a92d33SSascha Wildner 			/* Let the thread finish its busy loop. */
1100e5a92d33SSascha Wildner 			sleep (6);
1101e5a92d33SSascha Wildner 			if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
1102e5a92d33SSascha Wildner 				log_error ("test thread never finished.\n");
1103e5a92d33SSascha Wildner 			else
1104e5a92d33SSascha Wildner 				log_pass ();
1105e5a92d33SSascha Wildner 		}
1106e5a92d33SSascha Wildner 		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
1107e5a92d33SSascha Wildner 
1108e5a92d33SSascha Wildner 		/* Have the test thread release mutex 0. */
1109e5a92d33SSascha Wildner 		send_cmd (test_thread_id, CMD_RELEASE_ALL);
1110e5a92d33SSascha Wildner 		sleep (1);
1111e5a92d33SSascha Wildner 
1112e5a92d33SSascha Wildner 		/*
1113e5a92d33SSascha Wildner 		 * Have the test thread go into a busy loop for 5 seconds
1114e5a92d33SSascha Wildner 		 * and see that it preempts this thread (since the priority
1115e5a92d33SSascha Wildner 		 * ceiling of mutex 1 is the same as the priority of this
1116e5a92d33SSascha Wildner 		 * thread).  The test thread should not run to completion
1117e5a92d33SSascha Wildner 		 * as its time quantum should expire before the 5 seconds
1118e5a92d33SSascha Wildner 		 * are up.
1119e5a92d33SSascha Wildner 		 */
1120*62481538SSascha Wildner 		log_info ("    Preemption with ceiling priority = thread "
1121e5a92d33SSascha Wildner 		    "priority - ");
1122e5a92d33SSascha Wildner 
1123e5a92d33SSascha Wildner 		/* Have the test thread take mutex 1. */
1124e5a92d33SSascha Wildner 		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
1125e5a92d33SSascha Wildner 		sleep (1);
1126e5a92d33SSascha Wildner 
1127e5a92d33SSascha Wildner 		log_trace ("Sending busy\n");
1128e5a92d33SSascha Wildner 		send_cmd (test_thread_id, CMD_BUSY_LOOP);
1129e5a92d33SSascha Wildner 		log_trace ("Busy sent, yielding\n");
1130e5a92d33SSascha Wildner 		pthread_yield ();
1131e5a92d33SSascha Wildner 		log_trace ("Returned from yield.\n");
1132e5a92d33SSascha Wildner 		if ((states[test_thread_id].flags & FLAGS_IS_BUSY) == 0)
1133e5a92d33SSascha Wildner 			log_error ("test thread did not switch in on yield.\n");
1134e5a92d33SSascha Wildner 		else if (states[test_thread_id].flags & FLAGS_WAS_BUSY)
1135e5a92d33SSascha Wildner 			log_error ("test thread ran to completion.\n");
1136e5a92d33SSascha Wildner 		else {
1137e5a92d33SSascha Wildner 			/* Let the thread finish its busy loop. */
1138e5a92d33SSascha Wildner 			sleep (6);
1139e5a92d33SSascha Wildner 			if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
1140e5a92d33SSascha Wildner 				log_error ("test thread never finished.\n");
1141e5a92d33SSascha Wildner 			else
1142e5a92d33SSascha Wildner 				log_pass ();
1143e5a92d33SSascha Wildner 		}
1144e5a92d33SSascha Wildner 		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
1145e5a92d33SSascha Wildner 
1146e5a92d33SSascha Wildner 		/* Have the test thread release mutex 1. */
1147e5a92d33SSascha Wildner 		send_cmd (test_thread_id, CMD_RELEASE_ALL);
1148e5a92d33SSascha Wildner 		sleep (1);
1149e5a92d33SSascha Wildner 
1150e5a92d33SSascha Wildner 		/*
1151e5a92d33SSascha Wildner 		 * Set the scheduling policy of the test thread to SCHED_FIFO
1152e5a92d33SSascha Wildner 		 * and have it go into a busy loop for 5 seconds.  This
1153e5a92d33SSascha Wildner 		 * thread is SCHED_RR, and since the priority ceiling of
1154e5a92d33SSascha Wildner 		 * mutex 1 is the same as the priority of this thread, the
1155e5a92d33SSascha Wildner 		 * test thread should run to completion once it is switched
1156e5a92d33SSascha Wildner 		 * in.
1157e5a92d33SSascha Wildner 		 */
1158*62481538SSascha Wildner 		log_info ("    SCHED_FIFO scheduling and ceiling priority = "
1159e5a92d33SSascha Wildner 		    "thread priority - ");
1160e5a92d33SSascha Wildner 		param.sched_priority = states[test_thread_id].priority;
1161e5a92d33SSascha Wildner 		assert (pthread_setschedparam (states[test_thread_id].tid,
1162e5a92d33SSascha Wildner 		    SCHED_FIFO, &param) == 0);
1163e5a92d33SSascha Wildner 
1164e5a92d33SSascha Wildner 		/* Have the test thread take mutex 1. */
1165e5a92d33SSascha Wildner 		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
1166e5a92d33SSascha Wildner 		sleep (1);
1167e5a92d33SSascha Wildner 
1168e5a92d33SSascha Wildner 		log_trace ("Sending busy\n");
1169e5a92d33SSascha Wildner 		send_cmd (test_thread_id, CMD_BUSY_LOOP);
1170e5a92d33SSascha Wildner 		log_trace ("Busy sent, yielding\n");
1171e5a92d33SSascha Wildner 		pthread_yield ();
1172e5a92d33SSascha Wildner 		log_trace ("Returned from yield.\n");
1173e5a92d33SSascha Wildner 		if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) {
1174e5a92d33SSascha Wildner 			log_error ("test thread did not run to completion.\n");
1175e5a92d33SSascha Wildner 			/* Let the thread finish it's busy loop. */
1176e5a92d33SSascha Wildner 			sleep (6);
1177e5a92d33SSascha Wildner 		}
1178e5a92d33SSascha Wildner 		else
1179e5a92d33SSascha Wildner 			log_pass ();
1180e5a92d33SSascha Wildner 		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
1181e5a92d33SSascha Wildner 
1182e5a92d33SSascha Wildner 		/* Restore the test thread scheduling parameters. */
1183e5a92d33SSascha Wildner 		param.sched_priority = states[test_thread_id].priority;
1184e5a92d33SSascha Wildner 		assert (pthread_setschedparam (states[test_thread_id].tid,
1185e5a92d33SSascha Wildner 		    SCHED_RR, &param) == 0);
1186e5a92d33SSascha Wildner 
1187e5a92d33SSascha Wildner 		/* Have the test thread release mutex 1. */
1188e5a92d33SSascha Wildner 		send_cmd (test_thread_id, CMD_RELEASE_ALL);
1189e5a92d33SSascha Wildner 		sleep (1);
1190e5a92d33SSascha Wildner 
1191e5a92d33SSascha Wildner 		/*
1192e5a92d33SSascha Wildner 		 * Have the test thread go into a busy loop for 5 seconds
1193e5a92d33SSascha Wildner 		 * and see that it preempts this thread (since the priority
1194e5a92d33SSascha Wildner 		 * ceiling of mutex 2 is the greater than the priority of
1195e5a92d33SSascha Wildner 		 * this thread).  The test thread should run to completion
1196e5a92d33SSascha Wildner 		 * and block this thread because its active priority is
1197e5a92d33SSascha Wildner 		 * higher.
1198e5a92d33SSascha Wildner 		 */
1199*62481538SSascha Wildner 		log_info ("    SCHED_FIFO scheduling and ceiling priority > "
1200e5a92d33SSascha Wildner 		    "thread priority - ");
1201e5a92d33SSascha Wildner 		/* Have the test thread take mutex 2. */
1202e5a92d33SSascha Wildner 		send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[2]);
1203e5a92d33SSascha Wildner 		sleep (1);
1204e5a92d33SSascha Wildner 
1205e5a92d33SSascha Wildner 		log_trace ("Sending busy\n");
1206e5a92d33SSascha Wildner 		send_cmd (test_thread_id, CMD_BUSY_LOOP);
1207e5a92d33SSascha Wildner 		log_trace ("Busy sent, yielding\n");
1208e5a92d33SSascha Wildner 		pthread_yield ();
1209e5a92d33SSascha Wildner 		log_trace ("Returned from yield.\n");
1210e5a92d33SSascha Wildner 		if ((states[test_thread_id].flags & FLAGS_IS_BUSY) != 0) {
1211e5a92d33SSascha Wildner 			log_error ("test thread did not run to completion.\n");
1212e5a92d33SSascha Wildner 			/* Let the thread finish it's busy loop. */
1213e5a92d33SSascha Wildner 			sleep (6);
1214e5a92d33SSascha Wildner 		}
1215e5a92d33SSascha Wildner 		else if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
1216e5a92d33SSascha Wildner 			log_error ("test thread never finished.\n");
1217e5a92d33SSascha Wildner 		else
1218e5a92d33SSascha Wildner 			log_pass ();
1219e5a92d33SSascha Wildner 		states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
1220e5a92d33SSascha Wildner 
1221e5a92d33SSascha Wildner 		/* Have the test thread release mutex 2. */
1222e5a92d33SSascha Wildner 		send_cmd (test_thread_id, CMD_RELEASE_ALL);
1223e5a92d33SSascha Wildner 		sleep (1);
1224e5a92d33SSascha Wildner 
1225e5a92d33SSascha Wildner 		/* Destroy the mutexes. */
1226e5a92d33SSascha Wildner 		for (i = 0; i < 3; i++)
1227e5a92d33SSascha Wildner 			assert (pthread_mutex_destroy (&m[i]) == 0);
1228e5a92d33SSascha Wildner 	}
1229e5a92d33SSascha Wildner }
1230e5a92d33SSascha Wildner 
1231e5a92d33SSascha Wildner 
1232e5a92d33SSascha Wildner static void
mutex_prioinherit_test(void)1233e5a92d33SSascha Wildner mutex_prioinherit_test (void)
1234e5a92d33SSascha Wildner {
1235e5a92d33SSascha Wildner 	pthread_mutexattr_t mattr;
1236e5a92d33SSascha Wildner 	struct sched_param param;
1237e5a92d33SSascha Wildner 	pthread_mutex_t	m[3];
1238e5a92d33SSascha Wildner 	mutex_kind_t	mkind;
1239e5a92d33SSascha Wildner 	int		i, policy, my_prio;
1240e5a92d33SSascha Wildner 
1241e5a92d33SSascha Wildner 	/* Get this threads current priority. */
1242e5a92d33SSascha Wildner 	assert (pthread_getschedparam (pthread_self(), &policy,
1243e5a92d33SSascha Wildner 	    &param) == 0);
1244e5a92d33SSascha Wildner 	my_prio = param.sched_priority;	/* save for later use */
1245e5a92d33SSascha Wildner 	log_trace ("Current scheduling policy %d, priority %d\n",
1246e5a92d33SSascha Wildner 	    policy, my_prio);
1247e5a92d33SSascha Wildner 
1248*62481538SSascha Wildner 	log_info ("Testing priority inheritance\n");
1249*62481538SSascha Wildner 	log_info ("----------------------------\n");
1250e5a92d33SSascha Wildner 	for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
1251e5a92d33SSascha Wildner 
1252*62481538SSascha Wildner 		log_info ("  Protype PTHREAD_PRIO_INHERIT, Type %s\n",
1253e5a92d33SSascha Wildner 		    mutextype_strs[mkind]);
1254e5a92d33SSascha Wildner 
1255e5a92d33SSascha Wildner 		/*
1256e5a92d33SSascha Wildner 		 * Initialize and create a mutex.
1257e5a92d33SSascha Wildner 		 */
1258e5a92d33SSascha Wildner 		assert (pthread_mutexattr_init (&mattr) == 0);
1259e5a92d33SSascha Wildner 
1260e5a92d33SSascha Wildner 		/*
1261e5a92d33SSascha Wildner 		 * Initialize and create 3 priority inheritance mutexes with
1262e5a92d33SSascha Wildner 		 * default (max priority) ceilings.
1263e5a92d33SSascha Wildner 		 */
1264e5a92d33SSascha Wildner 		assert (pthread_mutexattr_setprotocol(&mattr,
1265e5a92d33SSascha Wildner 		    PTHREAD_PRIO_INHERIT) == 0);
1266e5a92d33SSascha Wildner 
1267e5a92d33SSascha Wildner 		/*
1268e5a92d33SSascha Wildner 		 * Ensure that the first mutex type is a POSIX
1269e5a92d33SSascha Wildner 		 * compliant mutex.
1270e5a92d33SSascha Wildner 		 */
1271e5a92d33SSascha Wildner 		if (mkind != M_POSIX) {
1272e5a92d33SSascha Wildner 			assert (pthread_mutexattr_settype (&mattr,
1273e5a92d33SSascha Wildner 			    mutex_types[mkind]) == 0);
1274e5a92d33SSascha Wildner 		}
1275e5a92d33SSascha Wildner 
1276e5a92d33SSascha Wildner 		for (i = 0; i < 3; i++)
1277e5a92d33SSascha Wildner 			assert (pthread_mutex_init (&m[i], &mattr) == 0);
1278e5a92d33SSascha Wildner 
1279e5a92d33SSascha Wildner 		/*
1280e5a92d33SSascha Wildner 		 * Test setup:
1281e5a92d33SSascha Wildner 		 *   Thread 4 - take mutex 0, 1
1282e5a92d33SSascha Wildner 		 *   Thread 2 - enter protected busy loop with mutex 0
1283e5a92d33SSascha Wildner 		 *   Thread 3 - enter protected busy loop with mutex 1
1284e5a92d33SSascha Wildner 		 *   Thread 4 - enter protected busy loop with mutex 2
1285e5a92d33SSascha Wildner 		 *   Thread 5 - enter busy loop
1286e5a92d33SSascha Wildner 		 *   Thread 6 - enter protected busy loop with mutex 0
1287e5a92d33SSascha Wildner 		 *   Thread 4 - releases mutexes 1 and 0.
1288e5a92d33SSascha Wildner 		 *
1289e5a92d33SSascha Wildner 		 * Expected results:
1290e5a92d33SSascha Wildner 		 *   Threads complete in order 4, 6, 5, 3, 2
1291e5a92d33SSascha Wildner 		 */
1292*62481538SSascha Wildner 		log_info ("    Simple inheritance test - ");
1293e5a92d33SSascha Wildner 
1294e5a92d33SSascha Wildner 		/*
1295e5a92d33SSascha Wildner 		 * Command thread 4 to take mutexes 0 and 1.
1296e5a92d33SSascha Wildner 		 */
1297e5a92d33SSascha Wildner 		send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
1298e5a92d33SSascha Wildner 		sleep (1);	/* Allow command to be received. */
1299e5a92d33SSascha Wildner 		send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[1]);
1300e5a92d33SSascha Wildner 		sleep (1);
1301e5a92d33SSascha Wildner 
1302e5a92d33SSascha Wildner 		/*
1303e5a92d33SSascha Wildner 		 * Tell the threads to report themselves when they are
1304e5a92d33SSascha Wildner 		 * at the bottom of their loop (waiting on wait_mutex).
1305e5a92d33SSascha Wildner 		 */
1306e5a92d33SSascha Wildner 		for (i = 0; i < NUM_THREADS; i++)
1307e5a92d33SSascha Wildner 			states[i].flags |= FLAGS_REPORT_WAITMUTEX;
1308e5a92d33SSascha Wildner 
1309e5a92d33SSascha Wildner 		/*
1310e5a92d33SSascha Wildner 		 * Command thread 2 to take mutex 0 and thread 3 to take
1311e5a92d33SSascha Wildner 		 * mutex 1, both via a protected operation command.  Since
1312e5a92d33SSascha Wildner 		 * thread 4 owns mutexes 0 and 1, both threads 2 and 3
1313e5a92d33SSascha Wildner 		 * will block until the mutexes are released by thread 4.
1314e5a92d33SSascha Wildner 		 */
1315e5a92d33SSascha Wildner 		log_trace ("Commanding protected operation to thread 2.\n");
1316e5a92d33SSascha Wildner 		send_mutex_cmd (2, CMD_PROTECTED_OP, &m[0]);
1317e5a92d33SSascha Wildner 		log_trace ("Commanding protected operation to thread 3.\n");
1318e5a92d33SSascha Wildner 		send_mutex_cmd (3, CMD_PROTECTED_OP, &m[1]);
1319e5a92d33SSascha Wildner 		sleep (1);
1320e5a92d33SSascha Wildner 
1321e5a92d33SSascha Wildner 		/*
1322e5a92d33SSascha Wildner 		 * Command thread 4 to take mutex 2 via a protected operation
1323e5a92d33SSascha Wildner 		 * and thread 5 to enter a busy loop for 5 seconds.  Since
1324e5a92d33SSascha Wildner 		 * thread 5 has higher priority than thread 4, thread 5 will
1325e5a92d33SSascha Wildner 		 * enter the busy loop before thread 4 is activated.
1326e5a92d33SSascha Wildner 		 */
1327e5a92d33SSascha Wildner 		log_trace ("Commanding protected operation to thread 4.\n");
1328e5a92d33SSascha Wildner 		send_mutex_cmd (4, CMD_PROTECTED_OP, &m[2]);
1329e5a92d33SSascha Wildner 		log_trace ("Commanding busy loop to thread 5.\n");
1330e5a92d33SSascha Wildner 		send_cmd (5, CMD_BUSY_LOOP);
1331e5a92d33SSascha Wildner 		sleep (1);
1332e5a92d33SSascha Wildner 		if ((states[5].flags & FLAGS_IS_BUSY) == 0)
1333e5a92d33SSascha Wildner 			log_error ("thread 5 is not running.\n");
1334e5a92d33SSascha Wildner 		log_trace ("Commanding protected operation thread 6.\n");
1335e5a92d33SSascha Wildner 		send_mutex_cmd (6, CMD_PROTECTED_OP, &m[0]);
1336e5a92d33SSascha Wildner 		sleep (1);
1337e5a92d33SSascha Wildner 		if ((states[4].flags & FLAGS_WAS_BUSY) == 0)
1338e5a92d33SSascha Wildner 			log_error ("thread 4 failed to inherit priority.\n");
1339e5a92d33SSascha Wildner 		states[4].flags = 0;
1340e5a92d33SSascha Wildner 		send_cmd (4, CMD_RELEASE_ALL);
1341e5a92d33SSascha Wildner 		sleep (5);
1342e5a92d33SSascha Wildner 		check_run_order ("4,6,5,3,2");
1343e5a92d33SSascha Wildner 
1344e5a92d33SSascha Wildner 		/*
1345e5a92d33SSascha Wildner 		 * Clear the flags.
1346e5a92d33SSascha Wildner 		 */
1347e5a92d33SSascha Wildner 		for (i = 0; i < NUM_THREADS; i++)
1348e5a92d33SSascha Wildner 			states[i].flags = 0;
1349e5a92d33SSascha Wildner 
1350e5a92d33SSascha Wildner 		/*
1351e5a92d33SSascha Wildner 		 * Test setup:
1352e5a92d33SSascha Wildner 		 *   Thread 2 - enter busy loop (SCHED_FIFO)
1353e5a92d33SSascha Wildner 		 *   Thread 4 - take mutex 0
1354e5a92d33SSascha Wildner 		 *   Thread 4 - priority change to same priority as thread 2
1355e5a92d33SSascha Wildner 		 *   Thread 4 - release mutex 0
1356e5a92d33SSascha Wildner 		 *
1357e5a92d33SSascha Wildner 		 * Expected results:
1358e5a92d33SSascha Wildner 		 *   Since thread 4 owns a priority mutex, it should be
1359e5a92d33SSascha Wildner 		 *   placed at the front of the run queue (for its new
1360e5a92d33SSascha Wildner 		 *   priority slot) when its priority is lowered to the
1361e5a92d33SSascha Wildner 		 *   same priority as thread 2.  If thread 4 did not own
1362e5a92d33SSascha Wildner 		 *   a priority mutex, then it would have been added to
1363e5a92d33SSascha Wildner 		 *   the end of the run queue and thread 2 would have
1364e5a92d33SSascha Wildner 		 *   executed until it blocked (because it's scheduling
1365e5a92d33SSascha Wildner 		 *   policy is SCHED_FIFO).
1366e5a92d33SSascha Wildner 		 *
1367e5a92d33SSascha Wildner 		 */
1368*62481538SSascha Wildner 		log_info ("    Inheritance test with change of priority - ");
1369e5a92d33SSascha Wildner 
1370e5a92d33SSascha Wildner 		/*
1371e5a92d33SSascha Wildner 		 * Change threads 2 and 4 scheduling policies to be
1372e5a92d33SSascha Wildner 		 * SCHED_FIFO.
1373e5a92d33SSascha Wildner 		 */
1374e5a92d33SSascha Wildner 		param.sched_priority = states[2].priority;
1375e5a92d33SSascha Wildner 		assert (pthread_setschedparam (states[2].tid, SCHED_FIFO,
1376e5a92d33SSascha Wildner 		    &param) == 0);
1377e5a92d33SSascha Wildner 		param.sched_priority = states[4].priority;
1378e5a92d33SSascha Wildner 		assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
1379e5a92d33SSascha Wildner 		    &param) == 0);
1380e5a92d33SSascha Wildner 
1381e5a92d33SSascha Wildner 		/*
1382e5a92d33SSascha Wildner 		 * Command thread 4 to take mutex 0.
1383e5a92d33SSascha Wildner 		 */
1384e5a92d33SSascha Wildner 		send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
1385e5a92d33SSascha Wildner 		sleep (1);
1386e5a92d33SSascha Wildner 
1387e5a92d33SSascha Wildner 		/*
1388e5a92d33SSascha Wildner 		 * Command thread 2 to enter busy loop.
1389e5a92d33SSascha Wildner 		 */
1390e5a92d33SSascha Wildner 		send_cmd (2, CMD_BUSY_LOOP);
1391e5a92d33SSascha Wildner 		sleep (1);	/* Allow command to be received. */
1392e5a92d33SSascha Wildner 
1393e5a92d33SSascha Wildner 		/*
1394e5a92d33SSascha Wildner 		 * Command thread 4 to enter busy loop.
1395e5a92d33SSascha Wildner 		 */
1396e5a92d33SSascha Wildner 		send_cmd (4, CMD_BUSY_LOOP);
1397e5a92d33SSascha Wildner 		sleep (1);	/* Allow command to be received. */
1398e5a92d33SSascha Wildner 
1399e5a92d33SSascha Wildner 		/* Have threads 2 and 4 report themselves. */
1400e5a92d33SSascha Wildner 		states[2].flags = FLAGS_REPORT_WAITMUTEX;
1401e5a92d33SSascha Wildner 		states[4].flags = FLAGS_REPORT_WAITMUTEX;
1402e5a92d33SSascha Wildner 
1403e5a92d33SSascha Wildner 		/* Change the priority of thread 4. */
1404e5a92d33SSascha Wildner 		param.sched_priority = states[2].priority;
1405e5a92d33SSascha Wildner 		assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
1406e5a92d33SSascha Wildner 		    &param) == 0);
1407e5a92d33SSascha Wildner 		sleep (5);
1408e5a92d33SSascha Wildner 		check_run_order ("4,2");
1409e5a92d33SSascha Wildner 
1410e5a92d33SSascha Wildner 		/* Clear the flags */
1411e5a92d33SSascha Wildner 		states[2].flags = 0;
1412e5a92d33SSascha Wildner 		states[4].flags = 0;
1413e5a92d33SSascha Wildner 
1414e5a92d33SSascha Wildner 		/* Reset the policies. */
1415e5a92d33SSascha Wildner 		param.sched_priority = states[2].priority;
1416e5a92d33SSascha Wildner 		assert (pthread_setschedparam (states[2].tid, SCHED_RR,
1417e5a92d33SSascha Wildner 		    &param) == 0);
1418e5a92d33SSascha Wildner 		param.sched_priority = states[4].priority;
1419e5a92d33SSascha Wildner 		assert (pthread_setschedparam (states[4].tid, SCHED_RR,
1420e5a92d33SSascha Wildner 		    &param) == 0);
1421e5a92d33SSascha Wildner 
1422e5a92d33SSascha Wildner 		send_cmd (4, CMD_RELEASE_MUTEX);
1423e5a92d33SSascha Wildner 		sleep (1);
1424e5a92d33SSascha Wildner 
1425e5a92d33SSascha Wildner 		/* Destroy the mutexes. */
1426e5a92d33SSascha Wildner 		for (i = 0; i < 3; i++)
1427e5a92d33SSascha Wildner 			assert (pthread_mutex_destroy (&m[i]) == 0);
1428e5a92d33SSascha Wildner 	}
1429e5a92d33SSascha Wildner }
1430e5a92d33SSascha Wildner 
1431e5a92d33SSascha Wildner 
main(int argc,char * argv[])1432e5a92d33SSascha Wildner int main (int argc, char *argv[])
1433e5a92d33SSascha Wildner {
1434e5a92d33SSascha Wildner 	pthread_mutexattr_t mattr;
1435e5a92d33SSascha Wildner 	pthread_condattr_t cattr;
1436e5a92d33SSascha Wildner 	pthread_attr_t	pattr;
1437e5a92d33SSascha Wildner 	int		i, policy, main_prio;
1438e5a92d33SSascha Wildner 	void *		exit_status;
1439e5a92d33SSascha Wildner 	sigset_t	mask;
1440e5a92d33SSascha Wildner 	struct sigaction act;
1441e5a92d33SSascha Wildner 	struct sched_param param;
1442*62481538SSascha Wildner 	char buf[30];
1443e5a92d33SSascha Wildner 
1444e5a92d33SSascha Wildner 	logfile = stdout;
1445e5a92d33SSascha Wildner 
1446e5a92d33SSascha Wildner 	assert (pthread_getschedparam (pthread_self (), &policy, &param) == 0);
1447e5a92d33SSascha Wildner 	main_prio = param.sched_priority;
1448e5a92d33SSascha Wildner 
1449e5a92d33SSascha Wildner 	/* Setupt our signal mask. */
1450e5a92d33SSascha Wildner 	sigfillset (&mask);
1451e5a92d33SSascha Wildner 	sigdelset (&mask, SIGINT);
1452e5a92d33SSascha Wildner 	sigprocmask (SIG_SETMASK, &mask, NULL);
1453e5a92d33SSascha Wildner 
1454e5a92d33SSascha Wildner 	/* Install a signal handler for SIGINT */
1455e5a92d33SSascha Wildner 	sigemptyset (&act.sa_mask);
1456e5a92d33SSascha Wildner 	sigaddset (&act.sa_mask, SIGINT);
1457e5a92d33SSascha Wildner 	act.sa_handler = sighandler;
1458e5a92d33SSascha Wildner 	act.sa_flags = SA_RESTART;
1459e5a92d33SSascha Wildner 	sigaction (SIGINT, &act, NULL);
1460e5a92d33SSascha Wildner 
1461e5a92d33SSascha Wildner 	/*
1462e5a92d33SSascha Wildner 	 * Initialize the thread attribute.
1463e5a92d33SSascha Wildner 	 */
1464e5a92d33SSascha Wildner 	assert (pthread_attr_init (&pattr) == 0);
1465e5a92d33SSascha Wildner 	assert (pthread_attr_setdetachstate (&pattr,
1466e5a92d33SSascha Wildner 	    PTHREAD_CREATE_JOINABLE) == 0);
1467e5a92d33SSascha Wildner 
1468e5a92d33SSascha Wildner 	/*
1469e5a92d33SSascha Wildner 	 * Initialize and create the waiter and condvar mutexes.
1470e5a92d33SSascha Wildner 	 */
1471e5a92d33SSascha Wildner 	assert (pthread_mutexattr_init (&mattr) == 0);
1472e5a92d33SSascha Wildner 	assert (pthread_mutex_init (&waiter_mutex, &mattr) == 0);
1473e5a92d33SSascha Wildner 	assert (pthread_mutex_init (&cond_mutex, &mattr) == 0);
1474e5a92d33SSascha Wildner 
1475e5a92d33SSascha Wildner 	/*
1476e5a92d33SSascha Wildner 	 * Initialize and create a condition variable.
1477e5a92d33SSascha Wildner 	 */
1478e5a92d33SSascha Wildner 	assert (pthread_condattr_init (&cattr) == 0);
1479e5a92d33SSascha Wildner 	assert (pthread_cond_init (&cond_var, &cattr) == 0);
1480e5a92d33SSascha Wildner 
1481e5a92d33SSascha Wildner 	/* Create a pipe to catch the results of thread wakeups. */
1482e5a92d33SSascha Wildner 	assert (pipe (pipefd) == 0);
1483e5a92d33SSascha Wildner 
1484e5a92d33SSascha Wildner #ifdef DEBUG
1485e5a92d33SSascha Wildner 	assert (pthread_switch_add_np (kern_switch) == 0);
1486e5a92d33SSascha Wildner #endif
1487e5a92d33SSascha Wildner 
1488e5a92d33SSascha Wildner 	/*
1489e5a92d33SSascha Wildner 	 * Create the waiting threads.
1490e5a92d33SSascha Wildner 	 */
1491e5a92d33SSascha Wildner 	for (i = 0; i < NUM_THREADS; i++) {
1492e5a92d33SSascha Wildner 		assert (pthread_cond_init (&states[i].cond_var, &cattr) == 0);
1493e5a92d33SSascha Wildner 		states[i].id = (u_int8_t) i;  /* NUM_THREADS must be <= 256 */
1494e5a92d33SSascha Wildner 		states[i].status = 0;
1495e5a92d33SSascha Wildner 		states[i].cmd.cmd_id = CMD_NONE;
1496e5a92d33SSascha Wildner 		states[i].flags = 0;	/* No flags yet. */
1497e5a92d33SSascha Wildner 		assert (pthread_create (&states[i].tid, &pattr, waiter,
1498e5a92d33SSascha Wildner 		    (void *) &states[i]) == 0);
1499e5a92d33SSascha Wildner 		param.sched_priority = main_prio - 10 + i;
1500e5a92d33SSascha Wildner 		states[i].priority = param.sched_priority;
1501e5a92d33SSascha Wildner 		assert (pthread_setschedparam (states[i].tid, SCHED_OTHER,
1502e5a92d33SSascha Wildner 		    &param) == 0);
1503e5a92d33SSascha Wildner 		snprintf (buf, sizeof(buf), "waiter_%d", i);
1504e5a92d33SSascha Wildner 		pthread_set_name_np (states[i].tid, buf);
1505e5a92d33SSascha Wildner 	}
1506e5a92d33SSascha Wildner 
1507e5a92d33SSascha Wildner 	/* Allow the threads to start. */
1508e5a92d33SSascha Wildner 	sleep (1);
1509e5a92d33SSascha Wildner 	log_trace ("Done creating threads.\n");
1510e5a92d33SSascha Wildner 
1511*62481538SSascha Wildner 	log_info ("\n");
1512e5a92d33SSascha Wildner 	mutex_init_test ();
1513*62481538SSascha Wildner 	log_info ("\n");
1514e5a92d33SSascha Wildner 	mutex_destroy_test ();
1515*62481538SSascha Wildner 	log_info ("\n");
1516e5a92d33SSascha Wildner 	mutex_lock_test ();
1517*62481538SSascha Wildner 	log_info ("\n");
1518e5a92d33SSascha Wildner 	mutex_unlock_test ();
1519*62481538SSascha Wildner 	log_info ("\n");
1520e5a92d33SSascha Wildner 	queueing_order_test ();
1521*62481538SSascha Wildner 	log_info ("\n");
1522e5a92d33SSascha Wildner 	mutex_prioinherit_test ();
1523*62481538SSascha Wildner 	log_info ("\n");
1524e5a92d33SSascha Wildner 	mutex_prioceiling_test ();
1525*62481538SSascha Wildner 	log_info ("\n");
1526e5a92d33SSascha Wildner 
1527*62481538SSascha Wildner 	log_info ("Total tests %d, passed %d, failed %d\n",
1528e5a92d33SSascha Wildner 	    total, pass_count, error_count);
1529e5a92d33SSascha Wildner 
1530e5a92d33SSascha Wildner 	/* Set the done flag and signal the threads to exit. */
1531e5a92d33SSascha Wildner 	log_trace ("Setting done flag.\n");
1532e5a92d33SSascha Wildner 	done = 1;
1533e5a92d33SSascha Wildner 
1534e5a92d33SSascha Wildner 	/*
1535e5a92d33SSascha Wildner 	 * Wait for the threads to finish.
1536e5a92d33SSascha Wildner 	 */
1537e5a92d33SSascha Wildner 	log_trace ("Trying to join threads.\n");
1538e5a92d33SSascha Wildner 	for (i = 0; i < NUM_THREADS; i++) {
1539e5a92d33SSascha Wildner 		send_cmd (i, CMD_NONE);
1540e5a92d33SSascha Wildner 		assert (pthread_join (states[i].tid, &exit_status) == 0);
1541e5a92d33SSascha Wildner 	}
1542e5a92d33SSascha Wildner 
1543e5a92d33SSascha Wildner 	/* Clean up after ourselves. */
1544e5a92d33SSascha Wildner 	close (pipefd[0]);
1545e5a92d33SSascha Wildner 	close (pipefd[1]);
1546e5a92d33SSascha Wildner 
1547e5a92d33SSascha Wildner 	if (error_count != 0)
1548e5a92d33SSascha Wildner 		exit (EX_OSERR);	/* any better ideas??? */
1549e5a92d33SSascha Wildner 	else
1550e5a92d33SSascha Wildner 		exit (EX_OK);
1551e5a92d33SSascha Wildner }
1552