8823a14b07b381a655cc53f7ef7e4cefbf9b8d0e
[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  * $DragonFly: src/lib/libc_r/test/mutex_d.c,v 1.2 2003/06/17 04:26:48 dillon Exp $
34  */
35 #include <stdlib.h>
36 #include <unistd.h>
37
38 #include <sys/ioctl.h>
39 #include <assert.h>
40 #include <errno.h>
41 #include "pthread.h"
42 #include <sched.h>
43 #include <signal.h>
44 #include <stdarg.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <sysexits.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 #ifdef DEBUG
184 static void
185 kern_switch (pthread_t pthread_out, pthread_t pthread_in)
186 {
187         if (pthread_out != NULL)
188                 printf ("Swapping out thread 0x%x, ", (int) pthread_out);
189         else
190                 printf ("Swapping out kernel thread, ");
191
192         if (pthread_in != NULL)
193                 printf ("swapping in thread 0x%x\n", (int) pthread_in);
194         else
195                 printf ("swapping in kernel thread.\n");
196 }
197 #endif
198
199
200 static void
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
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
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
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
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
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 *
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 %d: Exiting thread 0x%x\n", (int) statep->id,
470             (int) pthread_self());
471         pthread_exit (arg);
472         return (NULL);
473 }
474
475
476 static void *
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 %d: Exiting thread 0x%x\n", (int) statep->id,
517             (int) pthread_self());
518         pthread_exit (arg);
519         return (NULL);
520 }
521
522
523 static void
524 sighandler (int signo)
525 {
526         log ("Signal handler caught signal %d, thread id 0x%x\n",
527             signo, (int) pthread_self());
528
529         if (signo == SIGINT)
530                 done = 1;
531 }
532
533
534 static void
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
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
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
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
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
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
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
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
991 mutex_prioceiling_test (void)
992 {
993         const int test_thread_id = 0;   /* ID of test thread */
994         pthread_mutexattr_t mattr;
995         struct sched_param param;
996         pthread_mutex_t m[3];
997         mutex_kind_t    mkind;
998         int             i, ret, policy, my_prio, old_ceiling;
999
1000         log ("Testing priority ceilings\n");
1001         log ("-------------------------\n");
1002         for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
1003
1004                 log ("  Protype PTHREAD_PRIO_PROTECT, Type %s\n",
1005                     mutextype_strs[mkind]);
1006
1007                 /*
1008                  * Initialize and create a mutex.
1009                  */
1010                 assert (pthread_mutexattr_init (&mattr) == 0);
1011
1012                 /* Get this threads current priority. */
1013                 assert (pthread_getschedparam (pthread_self(), &policy,
1014                     &param) == 0);
1015                 my_prio = param.sched_priority; /* save for later use */
1016                 log_trace ("Current scheduling policy %d, priority %d\n",
1017                     policy, my_prio);
1018
1019                 /*
1020                  * Initialize and create 3 priority protection mutexes with
1021                  * default (max priority) ceilings.
1022                  */
1023                 assert (pthread_mutexattr_setprotocol(&mattr,
1024                     PTHREAD_PRIO_PROTECT) == 0);
1025
1026                 /*
1027                  * Ensure that the first mutex type is a POSIX
1028                  * compliant mutex.
1029                  */
1030                 if (mkind != M_POSIX) {
1031                         assert (pthread_mutexattr_settype (&mattr,
1032                             mutex_types[mkind]) == 0);
1033                 }
1034
1035                 for (i = 0; i < 3; i++)
1036                         assert (pthread_mutex_init (&m[i], &mattr) == 0);
1037
1038                 /*
1039                  * Set the ceiling priorities for the 3 priority protection
1040                  * mutexes to, 5 less than, equal to, and 5 greater than,
1041                  * this threads current priority.
1042                  */
1043                 for (i = 0; i < 3; i++)
1044                         assert (pthread_mutex_setprioceiling (&m[i],
1045                             my_prio - 5 + 5*i, &old_ceiling) == 0);
1046
1047                 /*
1048                  * Check that if we attempt to take a mutex whose priority
1049                  * ceiling is lower than our priority, we get an error.
1050                  */
1051                 log ("    Lock with ceiling priority < thread priority - ");
1052                 ret = pthread_mutex_lock (&m[0]);
1053                 check_result (/* expected */ EINVAL, ret);
1054                 if (ret == 0)
1055                         pthread_mutex_unlock (&m[0]);
1056
1057                 /*
1058                  * Check that we can take a mutex whose priority ceiling
1059                  * is equal to our priority.
1060                  */
1061                 log ("    Lock with ceiling priority = thread priority - ");
1062                 ret = pthread_mutex_lock (&m[1]);
1063                 check_result (/* expected */ 0, ret);
1064                 if (ret == 0)
1065                         pthread_mutex_unlock (&m[1]);
1066
1067                 /*
1068                  * Check that we can take a mutex whose priority ceiling
1069                  * is higher than our priority.
1070                  */
1071                 log ("    Lock with ceiling priority > thread priority - ");
1072                 ret = pthread_mutex_lock (&m[2]);
1073                 check_result (/* expected */ 0, ret);
1074                 if (ret == 0)
1075                         pthread_mutex_unlock (&m[2]);
1076
1077                 /*
1078                  * Have the test thread go into a busy loop for 5 seconds
1079                  * and see that it doesn't block this thread (since the
1080                  * priority ceiling of mutex 0 and the priority of the test
1081                  * thread are both less than the priority of this thread).
1082                  */
1083                 log ("    Preemption with ceiling priority < thread "
1084                     "priority - ");
1085                 /* Have the test thread take mutex 0. */
1086                 send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[0]);
1087                 sleep (1);
1088
1089                 log_trace ("Sending busy command.\n");
1090                 send_cmd (test_thread_id, CMD_BUSY_LOOP);
1091                 log_trace ("Busy sent, yielding\n");
1092                 pthread_yield ();
1093                 log_trace ("Returned from yield.\n");
1094                 if (states[test_thread_id].flags &
1095                     (FLAGS_IS_BUSY | FLAGS_WAS_BUSY))
1096                         log_error ("test thread inproperly preempted us.\n");
1097                 else {
1098                         /* Let the thread finish its busy loop. */
1099                         sleep (6);
1100                         if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
1101                                 log_error ("test thread never finished.\n");
1102                         else
1103                                 log_pass ();
1104                 }
1105                 states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
1106
1107                 /* Have the test thread release mutex 0. */
1108                 send_cmd (test_thread_id, CMD_RELEASE_ALL);
1109                 sleep (1);
1110
1111                 /*
1112                  * Have the test thread go into a busy loop for 5 seconds
1113                  * and see that it preempts this thread (since the priority
1114                  * ceiling of mutex 1 is the same as the priority of this
1115                  * thread).  The test thread should not run to completion
1116                  * as its time quantum should expire before the 5 seconds
1117                  * are up.
1118                  */
1119                 log ("    Preemption with ceiling priority = thread "
1120                     "priority - ");
1121
1122                 /* Have the test thread take mutex 1. */
1123                 send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
1124                 sleep (1);
1125
1126                 log_trace ("Sending busy\n");
1127                 send_cmd (test_thread_id, CMD_BUSY_LOOP);
1128                 log_trace ("Busy sent, yielding\n");
1129                 pthread_yield ();
1130                 log_trace ("Returned from yield.\n");
1131                 if ((states[test_thread_id].flags & FLAGS_IS_BUSY) == 0)
1132                         log_error ("test thread did not switch in on yield.\n");
1133                 else if (states[test_thread_id].flags & FLAGS_WAS_BUSY)
1134                         log_error ("test thread ran to completion.\n");
1135                 else {
1136                         /* Let the thread finish its busy loop. */
1137                         sleep (6);
1138                         if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
1139                                 log_error ("test thread never finished.\n");
1140                         else
1141                                 log_pass ();
1142                 }
1143                 states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
1144
1145                 /* Have the test thread release mutex 1. */
1146                 send_cmd (test_thread_id, CMD_RELEASE_ALL);
1147                 sleep (1);
1148
1149                 /*
1150                  * Set the scheduling policy of the test thread to SCHED_FIFO
1151                  * and have it go into a busy loop for 5 seconds.  This
1152                  * thread is SCHED_RR, and since the priority ceiling of
1153                  * mutex 1 is the same as the priority of this thread, the
1154                  * test thread should run to completion once it is switched
1155                  * in.
1156                  */
1157                 log ("    SCHED_FIFO scheduling and ceiling priority = "
1158                     "thread priority - ");
1159                 param.sched_priority = states[test_thread_id].priority;
1160                 assert (pthread_setschedparam (states[test_thread_id].tid,
1161                     SCHED_FIFO, &param) == 0);
1162
1163                 /* Have the test thread take mutex 1. */
1164                 send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[1]);
1165                 sleep (1);
1166
1167                 log_trace ("Sending busy\n");
1168                 send_cmd (test_thread_id, CMD_BUSY_LOOP);
1169                 log_trace ("Busy sent, yielding\n");
1170                 pthread_yield ();
1171                 log_trace ("Returned from yield.\n");
1172                 if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0) {
1173                         log_error ("test thread did not run to completion.\n");
1174                         /* Let the thread finish it's busy loop. */
1175                         sleep (6);
1176                 }
1177                 else
1178                         log_pass ();
1179                 states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
1180
1181                 /* Restore the test thread scheduling parameters. */
1182                 param.sched_priority = states[test_thread_id].priority;
1183                 assert (pthread_setschedparam (states[test_thread_id].tid,
1184                     SCHED_RR, &param) == 0);
1185
1186                 /* Have the test thread release mutex 1. */
1187                 send_cmd (test_thread_id, CMD_RELEASE_ALL);
1188                 sleep (1);
1189
1190                 /*
1191                  * Have the test thread go into a busy loop for 5 seconds
1192                  * and see that it preempts this thread (since the priority
1193                  * ceiling of mutex 2 is the greater than the priority of
1194                  * this thread).  The test thread should run to completion
1195                  * and block this thread because its active priority is
1196                  * higher.
1197                  */
1198                 log ("    SCHED_FIFO scheduling and ceiling priority > "
1199                     "thread priority - ");
1200                 /* Have the test thread take mutex 2. */
1201                 send_mutex_cmd (test_thread_id, CMD_TAKE_MUTEX, &m[2]);
1202                 sleep (1);
1203
1204                 log_trace ("Sending busy\n");
1205                 send_cmd (test_thread_id, CMD_BUSY_LOOP);
1206                 log_trace ("Busy sent, yielding\n");
1207                 pthread_yield ();
1208                 log_trace ("Returned from yield.\n");
1209                 if ((states[test_thread_id].flags & FLAGS_IS_BUSY) != 0) {
1210                         log_error ("test thread did not run to completion.\n");
1211                         /* Let the thread finish it's busy loop. */
1212                         sleep (6);
1213                 }
1214                 else if ((states[test_thread_id].flags & FLAGS_WAS_BUSY) == 0)
1215                         log_error ("test thread never finished.\n");
1216                 else
1217                         log_pass ();
1218                 states[test_thread_id].flags &= ~FLAGS_WAS_BUSY;
1219
1220                 /* Have the test thread release mutex 2. */
1221                 send_cmd (test_thread_id, CMD_RELEASE_ALL);
1222                 sleep (1);
1223
1224                 /* Destroy the mutexes. */
1225                 for (i = 0; i < 3; i++)
1226                         assert (pthread_mutex_destroy (&m[i]) == 0);
1227         }
1228 }
1229
1230
1231 static void
1232 mutex_prioinherit_test (void)
1233 {
1234         pthread_mutexattr_t mattr;
1235         struct sched_param param;
1236         pthread_mutex_t m[3];
1237         mutex_kind_t    mkind;
1238         int             i, policy, my_prio;
1239
1240         /* Get this threads current priority. */
1241         assert (pthread_getschedparam (pthread_self(), &policy,
1242             &param) == 0);
1243         my_prio = param.sched_priority; /* save for later use */
1244         log_trace ("Current scheduling policy %d, priority %d\n",
1245             policy, my_prio);
1246
1247         log ("Testing priority inheritence\n");
1248         log ("----------------------------\n");
1249         for (mkind = M_POSIX; mkind <= M_SS2_RECURSIVE; mkind++) {
1250
1251                 log ("  Protype PTHREAD_PRIO_INHERIT, Type %s\n",
1252                     mutextype_strs[mkind]);
1253
1254                 /*
1255                  * Initialize and create a mutex.
1256                  */
1257                 assert (pthread_mutexattr_init (&mattr) == 0);
1258
1259                 /*
1260                  * Initialize and create 3 priority inheritence mutexes with
1261                  * default (max priority) ceilings.
1262                  */
1263                 assert (pthread_mutexattr_setprotocol(&mattr,
1264                     PTHREAD_PRIO_INHERIT) == 0);
1265
1266                 /*
1267                  * Ensure that the first mutex type is a POSIX
1268                  * compliant mutex.
1269                  */
1270                 if (mkind != M_POSIX) {
1271                         assert (pthread_mutexattr_settype (&mattr,
1272                             mutex_types[mkind]) == 0);
1273                 }
1274
1275                 for (i = 0; i < 3; i++)
1276                         assert (pthread_mutex_init (&m[i], &mattr) == 0);
1277
1278                 /*
1279                  * Test setup:
1280                  *   Thread 4 - take mutex 0, 1
1281                  *   Thread 2 - enter protected busy loop with mutex 0
1282                  *   Thread 3 - enter protected busy loop with mutex 1
1283                  *   Thread 4 - enter protected busy loop with mutex 2
1284                  *   Thread 5 - enter busy loop
1285                  *   Thread 6 - enter protected busy loop with mutex 0
1286                  *   Thread 4 - releases mutexes 1 and 0.
1287                  *
1288                  * Expected results:
1289                  *   Threads complete in order 4, 6, 5, 3, 2
1290                  */
1291                 log ("    Simple inheritence test - ");
1292
1293                 /*
1294                  * Command thread 4 to take mutexes 0 and 1.
1295                  */
1296                 send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
1297                 sleep (1);      /* Allow command to be received. */
1298                 send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[1]);
1299                 sleep (1);
1300
1301                 /*
1302                  * Tell the threads to report themselves when they are
1303                  * at the bottom of their loop (waiting on wait_mutex).
1304                  */
1305                 for (i = 0; i < NUM_THREADS; i++)
1306                         states[i].flags |= FLAGS_REPORT_WAITMUTEX;
1307
1308                 /*
1309                  * Command thread 2 to take mutex 0 and thread 3 to take
1310                  * mutex 1, both via a protected operation command.  Since
1311                  * thread 4 owns mutexes 0 and 1, both threads 2 and 3
1312                  * will block until the mutexes are released by thread 4.
1313                  */
1314                 log_trace ("Commanding protected operation to thread 2.\n");
1315                 send_mutex_cmd (2, CMD_PROTECTED_OP, &m[0]);
1316                 log_trace ("Commanding protected operation to thread 3.\n");
1317                 send_mutex_cmd (3, CMD_PROTECTED_OP, &m[1]);
1318                 sleep (1);
1319
1320                 /*
1321                  * Command thread 4 to take mutex 2 via a protected operation
1322                  * and thread 5 to enter a busy loop for 5 seconds.  Since
1323                  * thread 5 has higher priority than thread 4, thread 5 will
1324                  * enter the busy loop before thread 4 is activated.
1325                  */
1326                 log_trace ("Commanding protected operation to thread 4.\n");
1327                 send_mutex_cmd (4, CMD_PROTECTED_OP, &m[2]);
1328                 log_trace ("Commanding busy loop to thread 5.\n");
1329                 send_cmd (5, CMD_BUSY_LOOP);
1330                 sleep (1);
1331                 if ((states[5].flags & FLAGS_IS_BUSY) == 0)
1332                         log_error ("thread 5 is not running.\n");
1333                 log_trace ("Commanding protected operation thread 6.\n");
1334                 send_mutex_cmd (6, CMD_PROTECTED_OP, &m[0]);
1335                 sleep (1);
1336                 if ((states[4].flags & FLAGS_WAS_BUSY) == 0)
1337                         log_error ("thread 4 failed to inherit priority.\n");
1338                 states[4].flags = 0;
1339                 send_cmd (4, CMD_RELEASE_ALL);
1340                 sleep (5);
1341                 check_run_order ("4,6,5,3,2");
1342
1343                 /*
1344                  * Clear the flags.
1345                  */
1346                 for (i = 0; i < NUM_THREADS; i++)
1347                         states[i].flags = 0;
1348
1349                 /*
1350                  * Test setup:
1351                  *   Thread 2 - enter busy loop (SCHED_FIFO)
1352                  *   Thread 4 - take mutex 0
1353                  *   Thread 4 - priority change to same priority as thread 2
1354                  *   Thread 4 - release mutex 0
1355                  *
1356                  * Expected results:
1357                  *   Since thread 4 owns a priority mutex, it should be
1358                  *   placed at the front of the run queue (for its new
1359                  *   priority slot) when its priority is lowered to the
1360                  *   same priority as thread 2.  If thread 4 did not own
1361                  *   a priority mutex, then it would have been added to
1362                  *   the end of the run queue and thread 2 would have
1363                  *   executed until it blocked (because it's scheduling
1364                  *   policy is SCHED_FIFO).
1365                  *   
1366                  */
1367                 log ("    Inheritence test with change of priority - ");
1368
1369                 /*
1370                  * Change threads 2 and 4 scheduling policies to be
1371                  * SCHED_FIFO.
1372                  */
1373                 param.sched_priority = states[2].priority;
1374                 assert (pthread_setschedparam (states[2].tid, SCHED_FIFO,
1375                     &param) == 0);
1376                 param.sched_priority = states[4].priority;
1377                 assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
1378                     &param) == 0);
1379
1380                 /*
1381                  * Command thread 4 to take mutex 0.
1382                  */
1383                 send_mutex_cmd (4, CMD_TAKE_MUTEX, &m[0]);
1384                 sleep (1);
1385
1386                 /*
1387                  * Command thread 2 to enter busy loop.
1388                  */
1389                 send_cmd (2, CMD_BUSY_LOOP);
1390                 sleep (1);      /* Allow command to be received. */
1391
1392                 /*
1393                  * Command thread 4 to enter busy loop.
1394                  */
1395                 send_cmd (4, CMD_BUSY_LOOP);
1396                 sleep (1);      /* Allow command to be received. */
1397
1398                 /* Have threads 2 and 4 report themselves. */
1399                 states[2].flags = FLAGS_REPORT_WAITMUTEX;
1400                 states[4].flags = FLAGS_REPORT_WAITMUTEX;
1401
1402                 /* Change the priority of thread 4. */
1403                 param.sched_priority = states[2].priority;
1404                 assert (pthread_setschedparam (states[4].tid, SCHED_FIFO,
1405                     &param) == 0);
1406                 sleep (5);
1407                 check_run_order ("4,2");
1408
1409                 /* Clear the flags */
1410                 states[2].flags = 0;
1411                 states[4].flags = 0;
1412
1413                 /* Reset the policies. */
1414                 param.sched_priority = states[2].priority;
1415                 assert (pthread_setschedparam (states[2].tid, SCHED_RR,
1416                     &param) == 0);
1417                 param.sched_priority = states[4].priority;
1418                 assert (pthread_setschedparam (states[4].tid, SCHED_RR,
1419                     &param) == 0);
1420
1421                 send_cmd (4, CMD_RELEASE_MUTEX);
1422                 sleep (1);
1423
1424                 /* Destroy the mutexes. */
1425                 for (i = 0; i < 3; i++)
1426                         assert (pthread_mutex_destroy (&m[i]) == 0);
1427         }
1428 }
1429
1430
1431 int main (int argc, char *argv[])
1432 {
1433         pthread_mutexattr_t mattr;
1434         pthread_condattr_t cattr;
1435         pthread_attr_t  pattr;
1436         int             i, policy, main_prio;
1437         void *          exit_status;
1438         sigset_t        mask;
1439         struct sigaction act;
1440         struct sched_param param;
1441
1442         logfile = stdout;
1443  
1444         assert (pthread_getschedparam (pthread_self (), &policy, &param) == 0);
1445         main_prio = param.sched_priority;
1446
1447         /* Setupt our signal mask. */
1448         sigfillset (&mask);
1449         sigdelset (&mask, SIGINT);
1450         sigprocmask (SIG_SETMASK, &mask, NULL);
1451
1452         /* Install a signal handler for SIGINT */
1453         sigemptyset (&act.sa_mask);
1454         sigaddset (&act.sa_mask, SIGINT);
1455         act.sa_handler = sighandler;
1456         act.sa_flags = SA_RESTART;
1457         sigaction (SIGINT, &act, NULL);
1458
1459         /*
1460          * Initialize the thread attribute.
1461          */
1462         assert (pthread_attr_init (&pattr) == 0);
1463         assert (pthread_attr_setdetachstate (&pattr,
1464             PTHREAD_CREATE_JOINABLE) == 0);
1465
1466         /*
1467          * Initialize and create the waiter and condvar mutexes.
1468          */
1469         assert (pthread_mutexattr_init (&mattr) == 0);
1470         assert (pthread_mutex_init (&waiter_mutex, &mattr) == 0);
1471         assert (pthread_mutex_init (&cond_mutex, &mattr) == 0);
1472
1473         /*
1474          * Initialize and create a condition variable.
1475          */
1476         assert (pthread_condattr_init (&cattr) == 0);
1477         assert (pthread_cond_init (&cond_var, &cattr) == 0);
1478
1479         /* Create a pipe to catch the results of thread wakeups. */
1480         assert (pipe (pipefd) == 0);
1481
1482 #ifdef DEBUG
1483         assert (pthread_switch_add_np (kern_switch) == 0);
1484 #endif
1485
1486         /*
1487          * Create the waiting threads.
1488          */
1489         for (i = 0; i < NUM_THREADS; i++) {
1490                 assert (pthread_cond_init (&states[i].cond_var, &cattr) == 0);
1491                 states[i].id = (u_int8_t) i;  /* NUM_THREADS must be <= 256 */
1492                 states[i].status = 0;
1493                 states[i].cmd.cmd_id = CMD_NONE;
1494                 states[i].flags = 0;    /* No flags yet. */
1495                 assert (pthread_create (&states[i].tid, &pattr, waiter,
1496                     (void *) &states[i]) == 0);
1497                 param.sched_priority = main_prio - 10 + i;
1498                 states[i].priority = param.sched_priority;
1499                 assert (pthread_setschedparam (states[i].tid, SCHED_OTHER,
1500                     &param) == 0);
1501 #if defined(_LIBC_R_)
1502                 {
1503                         char buf[30];
1504
1505                         snprintf (buf, sizeof(buf), "waiter_%d", i);
1506                         pthread_set_name_np (states[i].tid, buf);
1507                 }
1508 #endif
1509         }
1510
1511         /* Allow the threads to start. */
1512         sleep (1);
1513         log_trace ("Done creating threads.\n");
1514
1515         log ("\n");
1516         mutex_init_test ();
1517         log ("\n");
1518         mutex_destroy_test ();
1519         log ("\n");
1520         mutex_lock_test ();
1521         log ("\n");
1522         mutex_unlock_test ();
1523         log ("\n");
1524         queueing_order_test ();
1525         log ("\n");
1526         mutex_prioinherit_test ();
1527         log ("\n");
1528         mutex_prioceiling_test ();
1529         log ("\n");
1530
1531         log ("Total tests %d, passed %d, failed %d\n",
1532             total, pass_count, error_count);
1533
1534         /* Set the done flag and signal the threads to exit. */
1535         log_trace ("Setting done flag.\n");
1536         done = 1;
1537
1538         /*
1539          * Wait for the threads to finish.
1540          */
1541         log_trace ("Trying to join threads.\n");
1542         for (i = 0; i < NUM_THREADS; i++) {
1543                 send_cmd (i, CMD_NONE);
1544                 assert (pthread_join (states[i].tid, &exit_status) == 0);
1545         }
1546
1547         /* Clean up after ourselves. */
1548         close (pipefd[0]);
1549         close (pipefd[1]);
1550
1551         if (error_count != 0)
1552                 exit (EX_OSERR);        /* any better ideas??? */
1553         else
1554                 exit (EX_OK);
1555 }