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 ¶m) == 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, ¶m) == 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, ¶m) == 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 ¶m) == 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 ¶m) == 0);
1376 param.sched_priority = states[4].priority;
1377 assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
1378 ¶m) == 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 ¶m) == 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 ¶m) == 0);
1417 param.sched_priority = states[4].priority;
1418 assert (pthread_setschedparam (states[4].tid, SCHED_RR,
1419 ¶m) == 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, ¶m) == 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 ¶m) == 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