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: stable/10/lib/libkse/test/mutex_d.c 172491 2007-10-09 13:42:34Z obrien $
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 
63 static void log_error(const char *, ...) __printflike(1, 2);
64 static void log_trace (const char *, ...) __printflike(1, 2);
65 static void log (const char *, ...) __printflike(1, 2);
66 
67 /*------------------------------------------------------------
68  * Types
69  *----------------------------------------------------------*/
70 
71 typedef 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 
77 typedef 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 
86 typedef 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 
96 typedef struct {
97 	thread_cmd_id_t	cmd_id;
98 	pthread_mutex_t	*mutex;
99 	pthread_cond_t	*cond;
100 } thread_cmd_t;
101 
102 typedef 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 
113 typedef 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 
126 const char *protocol_strs[] = {
127 	"PTHREAD_PRIO_NONE",
128 	"PTHREAD_PRIO_INHERIT",
129 	"PTHREAD_PRIO_PROTECT"
130 };
131 
132 const int protocols[] = {
133 	PTHREAD_PRIO_NONE,
134 	PTHREAD_PRIO_INHERIT,
135 	PTHREAD_PRIO_PROTECT
136 };
137 
138 const 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 
146 const 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 
159 static int		done = 0;
160 static int		trace_enabled = 0;
161 static int		use_global_condvar = 0;
162 static thread_state_t	states[NUM_THREADS];
163 static int		pipefd[2];
164 
165 static pthread_mutex_t	waiter_mutex;
166 static pthread_mutex_t	cond_mutex;
167 static pthread_cond_t	cond_var;
168 
169 static FILE *logfile;
170 static int error_count = 0, pass_count = 0, total = 0;
171 
172 
173 /*------------------------------------------------------------
174  * Prototypes
175  *----------------------------------------------------------*/
176 extern char *strtok_r(char *str, const char *sep, char **last);
177 
178 
179 /*------------------------------------------------------------
180  * Functions
181  *----------------------------------------------------------*/
182 
183 #if defined(_LIBC_R_) && defined(DEBUG)
184 static void
kern_switch(pthread_t pthread_out,pthread_t pthread_in)185 kern_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 
200 static void
log_error(const char * fmt,...)201 log_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 
213 static void
log_pass(void)214 log_pass (void)
215 {
216 	fprintf (logfile, "PASS\n");
217 	pass_count = pass_count + 1;
218 	total = total + 1;
219 }
220 
221 
222 static void
log_trace(const char * fmt,...)223 log_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 
234 static void
log(const char * fmt,...)235 log (const char *fmt, ...)
236 {
237 	va_list ap;
238 
239 	va_start (ap, fmt);
240 	vfprintf (logfile, fmt, ap);
241 }
242 
243 
244 static void
check_result(int expected,int actual)245 check_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  */
257 static void
check_run_order(char * order)258 check_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 
310 static void *
waiter(void * arg)311 waiter (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 
476 static void *
lock_twice(void * arg)477 lock_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 
523 static void
sighandler(int signo)524 sighandler (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 
534 static void
send_cmd(int id,thread_cmd_id_t cmd)535 send_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 
549 static void
send_mutex_cmd(int id,thread_cmd_id_t cmd,pthread_mutex_t * m)550 send_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 
564 static void
send_mutex_cv_cmd(int id,thread_cmd_id_t cmd,pthread_mutex_t * m,pthread_cond_t * cv)565 send_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 
580 static void
mutex_init_test(void)581 mutex_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 
641 static void
mutex_destroy_test(void)642 mutex_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 
733 static void
mutex_lock_test(void)734 mutex_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 
828 static void
mutex_unlock_test(void)829 mutex_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 
915 static void
queueing_order_test(void)916 queueing_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 
990 static void
mutex_prioceiling_test(void)991 mutex_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 
1231 static void
mutex_prioinherit_test(void)1232 mutex_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 
main(int argc,char * argv[])1431 int 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