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