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