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