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