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