Module: xenomai-3
Branch: next
Commit: 64a91f18fda02b337776884ee72f187c4760063f
URL:    
http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=64a91f18fda02b337776884ee72f187c4760063f

Author: Philippe Gerum <r...@xenomai.org>
Date:   Wed Feb 17 09:21:27 2016 +0100

testsuite/smokey: mutex: simplify, introduce PP tests

At this chance, the lock stealing test is also fixed.

---

 testsuite/smokey/posix-mutex/posix-mutex.c | 1357 ++++++++++++++--------------
 1 file changed, 670 insertions(+), 687 deletions(-)

diff --git a/testsuite/smokey/posix-mutex/posix-mutex.c 
b/testsuite/smokey/posix-mutex/posix-mutex.c
index ac71b31..ae82fc1 100644
--- a/testsuite/smokey/posix-mutex/posix-mutex.c
+++ b/testsuite/smokey/posix-mutex/posix-mutex.c
@@ -4,6 +4,7 @@
  * Copyright (C) Gilles Chanteperdrix  <gilles.chanteperd...@xenomai.org>,
  *               Marion Deveaud <marion.deve...@siemens.com>,
  *               Jan Kiszka <jan.kis...@siemens.com>
+ *               Philippe Gerum <r...@xenomai.org>
  *
  * Released under the terms of GPLv2.
  */
@@ -17,8 +18,6 @@
 #include <signal.h>
 #include <pthread.h>
 #include <cobalt/sys/cobalt.h>
-#include <cobalt/uapi/syscall.h>
-#include "lib/cobalt/current.h"
 #include <smokey/smokey.h>
 
 smokey_test_plugin(posix_mutex,
@@ -26,886 +25,870 @@ smokey_test_plugin(posix_mutex,
                   "Check POSIX mutex services"
 );
 
-#define MUTEX_CREATE           1
-#define MUTEX_LOCK             2
-#define MUTEX_TRYLOCK          3
-#define MUTEX_TIMED_LOCK       4
-#define MUTEX_UNLOCK           5
-#define MUTEX_DESTROY          6
-#define COND_CREATE            7
-#define COND_SIGNAL            8
-#define COND_WAIT              9
-#define COND_DESTROY           10
-#define THREAD_DETACH          11
-#define THREAD_CREATE          12
-#define THREAD_JOIN            13
-#define THREAD_RENICE           14
-
-#define NS_PER_MS      1000000
-
 static const char *reason_str[] = {
-       [SIGDEBUG_UNDEFINED] = "undefined",
+       [SIGDEBUG_UNDEFINED] = "received SIGDEBUG for unknown reason",
        [SIGDEBUG_MIGRATE_SIGNAL] = "received signal",
        [SIGDEBUG_MIGRATE_SYSCALL] = "invoked syscall",
        [SIGDEBUG_MIGRATE_FAULT] = "triggered fault",
        [SIGDEBUG_MIGRATE_PRIOINV] = "affected by priority inversion",
-       [SIGDEBUG_NOMLOCK] = "missing mlockall",
-       [SIGDEBUG_WATCHDOG] = "runaway thread",
+       [SIGDEBUG_NOMLOCK] = "process memory not locked",
+       [SIGDEBUG_WATCHDOG] = "watchdog triggered (period too short?)",
+       [SIGDEBUG_LOCK_BREAK] = "scheduler lock break",
 };
 
 static void sigdebug(int sig, siginfo_t *si, void *context)
 {
+       const char fmt[] = "%s, this is unexpected.\n"
+               "(enabling CONFIG_XENO_OPT_DEBUG_TRACE_RELAX may help)\n";
        unsigned int reason = sigdebug_reason(si);
+       int n __attribute__ ((unused));
+       static char buffer[256];
 
-       smokey_trace("\nSIGDEBUG received, reason %d: %s\n", reason,
-                    reason <= SIGDEBUG_WATCHDOG ? reason_str[reason] : 
"<unknown>");
-}
+       if (reason > SIGDEBUG_WATCHDOG)
+               reason = SIGDEBUG_UNDEFINED;
 
-static inline unsigned long long timer_get_tsc(void)
-{
-       return clockobj_get_tsc();
+       n = snprintf(buffer, sizeof(buffer), fmt, reason_str[reason]);
+       n = write(STDERR_FILENO, buffer, n);
 }
 
-static inline unsigned long long timer_tsc2ns(unsigned long long tsc)
-{
-       return clockobj_tsc_to_ns(tsc);
-}
+#define THREAD_PRIO_WEAK       0
+#define THREAD_PRIO_LOW                1
+#define THREAD_PRIO_MEDIUM     2
+#define THREAD_PRIO_HIGH       3
+#define THREAD_PRIO_VERY_HIGH  4
 
-static void add_timespec(struct timespec *ts, unsigned long long value)
-{
-       ts->tv_sec += value / 1000000000;
-       ts->tv_nsec += value % 1000000000;
-       if (ts->tv_nsec > 1000000000) {
-               ts->tv_sec++;
-               ts->tv_nsec -= 1000000000;
-       }
-}
+#define MAX_100_MS  100000000ULL
+
+struct locker_context {
+       pthread_mutex_t *mutex;
+       struct smokey_barrier *barrier;
+       int lock_acquired;
+};
 
-static void ms_sleep(int time)
+static void sleep_ms(unsigned int ms)  /* < 1000 */
 {
        struct timespec ts;
-
+       
        ts.tv_sec = 0;
-       ts.tv_nsec = time*NS_PER_MS;
-
-       nanosleep(&ts, NULL);
+       ts.tv_nsec = ms * 1000000;
+       clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL);
 }
 
-static void check_current_prio(int expected_prio)
+static int get_effective_prio(void) 
 {
        struct cobalt_threadstat stat;
        int ret;
 
        ret = cobalt_thread_stat(0, &stat);
-       if (ret) {
-               fprintf(stderr,
-                       "FAILURE: cobalt_threadstat (%s)\n", strerror(-ret));
-               exit(EXIT_FAILURE);
-       }
+       if (ret)
+               return ret;
 
-       if (stat.cprio != expected_prio) {
-               fprintf(stderr,
-                       "FAILURE: current prio (%d) != expected prio (%d)\n",
-                       stat.cprio, expected_prio);
-               exit(EXIT_FAILURE);
-       }
+       return stat.cprio;
 }
 
-static void __check_current_mode(const char *file, int line,
-                                int mask, int expected_value)
+static int create_thread(pthread_t *tid, int policy, int prio,
+                        void *(*thread)(void *), void *arg)
 {
-       int current_mode;
+       struct sched_param param;
+       pthread_attr_t thattr;
+       int ret;
 
-       /* This is a unit test, and in this circonstance, we are allowed to
-          call cobalt_get_current_mode. But please do not do that in your
-          own code. */
-       current_mode = cobalt_get_current_mode() & mask;
+       pthread_attr_init(&thattr);
+       param.sched_priority = prio;
+       pthread_attr_setschedpolicy(&thattr, policy);
+       pthread_attr_setschedparam(&thattr, &param);
+       pthread_attr_setinheritsched(&thattr, PTHREAD_EXPLICIT_SCHED);
 
-       if (current_mode != expected_value) {
-               fprintf(stderr,
-                       "FAILURE at %s:%d: current mode (%x) != expected mode 
(%x)\n",
-                       file, line, current_mode, expected_value);
-               exit(EXIT_FAILURE);
-       }
-}
+       if (!__T(ret, pthread_create(tid, &thattr, thread, arg)))
+               return ret;
 
-#define check_current_mode(mask, expected_value)       \
-       __check_current_mode(__FILE__, __LINE__, (mask), (expected_value))
+       return 0;
+}
 
-static int dispatch(const char *service_name,
-                   int service_type, int check, int expected, ...)
+static int do_init_mutexattr(pthread_mutexattr_t *mattr, int type, int 
protocol)
 {
-       unsigned long long timeout;
-       pthread_t *thread;
-       pthread_cond_t *cond;
-       void *handler;
-       va_list ap;
-       int status, protocol, type;
-       pthread_mutex_t *mutex;
-       struct sched_param param;
-       pthread_attr_t threadattr;
-       pthread_mutexattr_t mutexattr;
-       struct timespec ts;
+       int ret;
 
-       va_start(ap, expected);
-       switch (service_type) {
-       case MUTEX_CREATE:
-               mutex = va_arg(ap, pthread_mutex_t *);
-               pthread_mutexattr_init(&mutexattr);
-               protocol = va_arg(ap, int);
-               /* May fail if unsupported, that's ok. */
-               pthread_mutexattr_setprotocol(&mutexattr, protocol);
-               type = va_arg(ap, int);
-               pthread_mutexattr_settype(&mutexattr, type);
-               status = pthread_mutex_init(mutex, &mutexattr);
-               break;
-
-       case MUTEX_LOCK:
-               status = pthread_mutex_lock(va_arg(ap, pthread_mutex_t *));
-               break;
-
-       case MUTEX_TRYLOCK:
-               status = pthread_mutex_trylock(va_arg(ap, pthread_mutex_t *));
-               break;
-
-       case MUTEX_TIMED_LOCK:
-               mutex = va_arg(ap, pthread_mutex_t *);
-               timeout = va_arg(ap, unsigned long long);
-               clock_gettime(CLOCK_REALTIME, &ts);
-               add_timespec(&ts, timeout);
-               status = pthread_mutex_timedlock(mutex, &ts);
-               break;
-
-       case MUTEX_UNLOCK:
-               status = pthread_mutex_unlock(va_arg(ap, pthread_mutex_t *));
-               break;
-
-       case MUTEX_DESTROY:
-               status = pthread_mutex_destroy(va_arg(ap, pthread_mutex_t *));
-               break;
-
-       case COND_CREATE:
-               status = pthread_cond_init(va_arg(ap, pthread_cond_t *), NULL);
-               break;
-
-       case COND_SIGNAL:
-               status = pthread_cond_signal(va_arg(ap, pthread_cond_t *));
-               break;
-
-       case COND_WAIT:
-               cond = va_arg(ap, pthread_cond_t *);
-               status =
-                   pthread_cond_wait(cond, va_arg(ap, pthread_mutex_t *));
-               break;
-
-       case COND_DESTROY:
-               status = pthread_cond_destroy(va_arg(ap, pthread_cond_t *));
-               break;
-
-       case THREAD_DETACH:
-               status = pthread_detach(pthread_self());
-               break;
-
-       case THREAD_CREATE:
-               thread = va_arg(ap, pthread_t *);
-               pthread_attr_init(&threadattr);
-               param.sched_priority = va_arg(ap, int);
-               if (param.sched_priority)
-                       pthread_attr_setschedpolicy(&threadattr, SCHED_FIFO);
-               else
-                       pthread_attr_setschedpolicy(&threadattr, SCHED_OTHER);
-               pthread_attr_setschedparam(&threadattr, &param);
-               pthread_attr_setinheritsched(&threadattr,
-                                            PTHREAD_EXPLICIT_SCHED);
-               handler = va_arg(ap, void *);
-               status = pthread_create(thread, &threadattr, handler,
-                                       va_arg(ap, void *));
-               break;
-
-       case THREAD_JOIN:
-               thread = va_arg(ap, pthread_t *);
-               status = pthread_join(*thread, NULL);
-               break;
-
-       case THREAD_RENICE:
-               param.sched_priority = va_arg(ap, int);
-               if (param.sched_priority)
-                       status = pthread_setschedparam(pthread_self(),
-                                                      SCHED_FIFO, &param);
-               else
-                       status = pthread_setschedparam(pthread_self(),
-                                                      SCHED_OTHER, &param);
-               break;
-
-       default:
-               fprintf(stderr, "Unknown service %i.\n", service_type);
-               exit(EXIT_FAILURE);
-       }
-       va_end(ap);
+       if (!__T(ret, pthread_mutexattr_init(mattr)))
+               return ret;
+       
+       if (!__T(ret, pthread_mutexattr_settype(mattr, type)))
+               return ret;
+       
+       if (!__T(ret, pthread_mutexattr_setprotocol(mattr, protocol)))
+               return ret;
+       
+       if (!__T(ret, pthread_mutexattr_setpshared(mattr, 
PTHREAD_PROCESS_PRIVATE)))
+               return ret;
 
-       if (check && status != expected) {
-               fprintf(stderr, "FAILURE: %s: %i (%s) instead of %i\n",
-                       service_name, status, strerror(status), expected);
-               exit(EXIT_FAILURE);
-       }
-       return status;
+       return 0;
 }
 
-static void *waiter(void *cookie)
+static int do_init_mutex(pthread_mutex_t *mutex, int type, int protocol)
 {
-       pthread_mutex_t *mutex = (pthread_mutex_t *) cookie;
-       unsigned long long start, diff;
+       pthread_mutexattr_t mattr;
+       int ret;
 
-       dispatch("waiter pthread_detach", THREAD_DETACH, 1, 0);
-       start = timer_get_tsc();
-       dispatch("waiter mutex_lock", MUTEX_LOCK, 1, 0, mutex);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
-       if (diff < 10000000) {
-               fprintf(stderr, "FAILURE: waiter, waited %Ld.%03u us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
-       ms_sleep(11);
-       dispatch("waiter mutex_unlock", MUTEX_UNLOCK, 1, 0, mutex);
+       ret = do_init_mutexattr(&mattr, type, protocol);
+       if (ret)
+               return ret;
+       
+       if (!__T(ret, pthread_mutex_init(mutex, &mattr)))
+               return ret;
 
-       return cookie;
+       if (!__T(ret, pthread_mutexattr_destroy(&mattr)))
+               return ret;
+       
+       return 0;
 }
 
-static void autoinit_simple_wait(void)
+static int do_init_mutex_ceiling(pthread_mutex_t *mutex, int type, int prio)
 {
-       unsigned long long start, diff;
-       pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
-       pthread_t waiter_tid;
-
-       smokey_trace("%s", __func__);
-
-       dispatch("simple mutex_lock 1", MUTEX_LOCK, 1, 0, &mutex);
-       dispatch("simple thread_create", THREAD_CREATE, 1, 0, &waiter_tid, 2,
-                waiter, &mutex);
-       ms_sleep(11);
-       dispatch("simple mutex_unlock 1", MUTEX_UNLOCK, 1, 0, &mutex);
-       sched_yield();
-
-       start = timer_get_tsc();
-       dispatch("simple mutex_lock 2", MUTEX_LOCK, 1, 0, &mutex);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
-       if (diff < 10000000) {
-               fprintf(stderr, "FAILURE: main, waited %Ld.%03u us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
+       pthread_mutexattr_t mattr;
+       int ret;
+
+       ret = do_init_mutexattr(&mattr, type, PTHREAD_PRIO_PROTECT);
+       if (ret)
+               return ret;
+       
+       if (!__T(ret, pthread_mutexattr_setprioceiling(&mattr, prio)))
+               return ret;
 
-       dispatch("simple mutex_unlock 2", MUTEX_UNLOCK, 1, 0, &mutex);
-       dispatch("simple mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
+       if (!__T(ret, pthread_mutex_init(mutex, &mattr)))
+               return ret;
+
+       if (!__T(ret, pthread_mutexattr_destroy(&mattr)))
+               return ret;
+       
+       return 0;
 }
 
-static void simple_wait(void)
+static void *mutex_timed_locker(void *arg)
 {
-       unsigned long long start, diff;
-       pthread_mutex_t mutex;
-       pthread_t waiter_tid;
-
-       smokey_trace("%s", __func__);
-
-       dispatch("simple mutex_init", MUTEX_CREATE, 1, 0, &mutex,
-                PTHREAD_PRIO_NONE, PTHREAD_MUTEX_NORMAL);
-       dispatch("simple mutex_lock 1", MUTEX_LOCK, 1, 0, &mutex);
-       dispatch("simple thread_create", THREAD_CREATE, 1, 0, &waiter_tid, 2,
-                waiter, &mutex);
-       ms_sleep(11);
-       dispatch("simple mutex_unlock 1", MUTEX_UNLOCK, 1, 0, &mutex);
-       sched_yield();
-
-       start = timer_get_tsc();
-       dispatch("simple mutex_lock 2", MUTEX_LOCK, 1, 0, &mutex);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
-       if (diff < 10000000) {
-               fprintf(stderr, "FAILURE: main, waited %Ld.%03u us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
+       struct locker_context *p = arg;
+       struct timespec now, ts;
+       int ret;
+
+       clock_gettime(CLOCK_REALTIME, &now);
+       timespec_adds(&ts, &now, 5000000); /* 5ms from now */
+
+       if (p->barrier)
+               smokey_barrier_release(p->barrier);
+       
+       if (__F(ret, pthread_mutex_timedlock(p->mutex, &ts)) &&
+           __Tassert(ret == -ETIMEDOUT))
+               return (void *)1;
 
-       dispatch("simple mutex_unlock 2", MUTEX_UNLOCK, 1, 0, &mutex);
-       dispatch("simple mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
+       return NULL;
 }
 
-static void autoinit_recursive_wait(void)
+static int do_timed_contend(pthread_mutex_t *mutex, int prio)
 {
-       unsigned long long start, diff;
-       pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
-       pthread_t waiter_tid;
+       struct locker_context args = { .barrier = NULL };
+       pthread_t tid;
+       void *status;
+       int ret;
 
-       smokey_trace("%s", __func__);
+       if (!__T(ret, pthread_mutex_lock(mutex)))
+               return ret;
 
-       dispatch("rec mutex_lock 1", MUTEX_LOCK, 1, 0, &mutex);
-       dispatch("rec mutex_lock 2", MUTEX_LOCK, 1, 0, &mutex);
+       args.mutex = mutex;
+       ret = create_thread(&tid, SCHED_FIFO, prio,
+                           mutex_timed_locker, &args);
+       if (ret)
+               return ret;
+       
+       if (!__T(ret, pthread_join(tid, &status)))
+               return ret;
 
-       dispatch("rec thread_create", THREAD_CREATE, 1, 0, &waiter_tid, 2,
-                waiter, &mutex);
+       if (!__T(ret, pthread_mutex_unlock(mutex)))
+               return ret;
 
-       dispatch("rec mutex_unlock 2", MUTEX_UNLOCK, 1, 0, &mutex);
-       ms_sleep(11);
-       dispatch("rec mutex_unlock 1", MUTEX_UNLOCK, 1, 0, &mutex);
-       sched_yield();
+       if (!__Fassert(status == NULL))
+               return -EINVAL;
 
-       start = timer_get_tsc();
-       dispatch("rec mutex_lock 3", MUTEX_LOCK, 1, 0, &mutex);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
+       if (!__T(ret, pthread_mutex_destroy(mutex)))
+               return ret;
 
-       if (diff < 10000000) {
-               fprintf(stderr, "FAILURE: main, waited %Ld.%03u us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
-       dispatch("rec mutex_unlock 3", MUTEX_UNLOCK, 1, 0, &mutex);
-       dispatch("rec mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
+       return 0;
 }
 
-static void recursive_wait(void)
+static void *mutex_locker(void *arg)
 {
-       unsigned long long start, diff;
-       pthread_mutex_t mutex;
-       pthread_t waiter_tid;
-
-       smokey_trace("%s", __func__);
+       struct locker_context *p = arg;
+       int ret;
 
-       dispatch("rec mutex_init", MUTEX_CREATE, 1, 0, &mutex,
-                PTHREAD_PRIO_NONE, PTHREAD_MUTEX_RECURSIVE);
-       dispatch("rec mutex_lock 1", MUTEX_LOCK, 1, 0, &mutex);
-       dispatch("rec mutex_lock 2", MUTEX_LOCK, 1, 0, &mutex);
+       if (!__T(ret, pthread_mutex_lock(p->mutex)))
+               return (void *)(long)ret;
 
-       dispatch("rec thread_create", THREAD_CREATE, 1, 0, &waiter_tid, 2,
-                waiter, &mutex);
+       p->lock_acquired = 1;
 
-       dispatch("rec mutex_unlock 2", MUTEX_UNLOCK, 1, 0, &mutex);
-       ms_sleep(11);
-       dispatch("rec mutex_unlock 1", MUTEX_UNLOCK, 1, 0, &mutex);
-       sched_yield();
+       if (!__T(ret, pthread_mutex_unlock(p->mutex)))
+               return (void *)(long)ret;
 
-       start = timer_get_tsc();
-       dispatch("rec mutex_lock 3", MUTEX_LOCK, 1, 0, &mutex);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
+       smokey_barrier_release(p->barrier);
 
-       if (diff < 10000000) {
-               fprintf(stderr, "FAILURE: main, waited %Ld.%03u us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
-       dispatch("rec mutex_unlock 3", MUTEX_UNLOCK, 1, 0, &mutex);
-       dispatch("rec mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
+       return NULL;
 }
 
-static void autoinit_errorcheck_wait(void)
+static int do_contend(pthread_mutex_t *mutex, int type)
 {
-       unsigned long long start, diff;
-       pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
-       pthread_t waiter_tid;
-       int err;
-
-       smokey_trace("%s", __func__);
+       struct smokey_barrier barrier;
+       struct locker_context args;
+       pthread_t tid;
+       void *status;
+       int ret;
 
-       dispatch("errorcheck mutex_lock 1", MUTEX_LOCK, 1, 0, &mutex);
+       if (!__T(ret, pthread_mutex_lock(mutex)))
+               return ret;
 
-       err = pthread_mutex_lock(&mutex);
-       if (err != EDEADLK) {
-               fprintf(stderr, "FAILURE: errorcheck mutex_lock 2: %s\n",
-                       strerror(err));
-               exit(EXIT_FAILURE);
+       if (type == PTHREAD_MUTEX_RECURSIVE) {
+               if (!__T(ret, pthread_mutex_lock(mutex)))
+                       return ret;
+       } else if (type == PTHREAD_MUTEX_ERRORCHECK) {
+               if (!__F(ret, pthread_mutex_lock(mutex)) ||
+                   !__Tassert(ret == -EDEADLK))
+                       return -EINVAL;
        }
 
-       dispatch("errorcheck thread_create", THREAD_CREATE, 1, 0, &waiter_tid, 
2,
-                waiter, &mutex);
-       ms_sleep(11);
-       dispatch("errorcheck mutex_unlock 1", MUTEX_UNLOCK, 1, 0, &mutex);
-       sched_yield();
-       err = pthread_mutex_unlock(&mutex);
-       if (err != EPERM) {
-               fprintf(stderr, "FAILURE: errorcheck mutex_unlock 2: %s\n",
-                       strerror(err));
-               exit(EXIT_FAILURE);
+       args.mutex = mutex;
+       smokey_barrier_init(&barrier);
+       args.barrier = &barrier;
+       args.lock_acquired = 0;
+       ret = create_thread(&tid, SCHED_FIFO, THREAD_PRIO_MEDIUM,
+                           mutex_locker, &args);
+       if (ret)
+               return ret;
+
+       if (!__T(ret, pthread_mutex_unlock(mutex)))
+               return ret;
+
+       if (type == PTHREAD_MUTEX_RECURSIVE) {
+               if (!__T(ret, pthread_mutex_unlock(mutex)))
+                       return ret;
+       } else if (type == PTHREAD_MUTEX_ERRORCHECK) {
+               if (!__F(ret, pthread_mutex_unlock(mutex)) ||
+                   !__Tassert(ret == -EPERM))
+                       return -EINVAL;
        }
 
-       start = timer_get_tsc();
-       dispatch("errorcheck mutex_lock 3", MUTEX_LOCK, 1, 0, &mutex);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
-       if (diff < 10000000) {
-               fprintf(stderr, "FAILURE: main, waited %Ld.%03u us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
-       dispatch("errorcheck mutex_unlock 3", MUTEX_UNLOCK, 1, 0, &mutex);
-       dispatch("errorcheck mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
+       /* Wait until locker runs through. */
+       if (!__T(ret, smokey_barrier_wait(&barrier)))
+               return ret;
+
+       if (!__T(ret, pthread_mutex_lock(mutex)))
+               return ret;
+
+       if (!__T(ret, pthread_mutex_unlock(mutex)))
+               return ret;
+
+       if (!__T(ret, pthread_mutex_destroy(mutex)))
+               return ret;
+
+       if (!__T(ret, pthread_join(tid, &status)))
+               return ret;
+
+       if (!__Tassert(status == NULL))
+               return -EINVAL;
+
+       return 0;
 }
 
-static void errorcheck_wait(void)
+static int static_init_normal_contend(void)
 {
-       unsigned long long start, diff;
-       pthread_mutex_t mutex;
-       pthread_t waiter_tid;
-       int err;
+       pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
-       smokey_trace("%s", __func__);
+       return do_contend(&mutex, PTHREAD_MUTEX_NORMAL);
+}
 
-       dispatch("errorcheck mutex_init", MUTEX_CREATE, 1, 0, &mutex,
-                PTHREAD_PRIO_NONE, PTHREAD_MUTEX_ERRORCHECK);
-       dispatch("errorcheck mutex_lock 1", MUTEX_LOCK, 1, 0, &mutex);
+static int __dynamic_init_contend(int type)
+{
+       pthread_mutex_t mutex;
+       int ret;
 
-       err = pthread_mutex_lock(&mutex);
-       if (err != EDEADLK) {
-               fprintf(stderr, "FAILURE: errorcheck mutex_lock 2: %s\n",
-                       strerror(err));
-               exit(EXIT_FAILURE);
-       }
+       ret = do_init_mutex(&mutex, type, PTHREAD_PRIO_NONE);
+       if (ret)
+               return ret;
+       
+       return do_contend(&mutex, type);
+}
 
-       dispatch("errorcheck thread_create", THREAD_CREATE, 1, 0, &waiter_tid, 
2,
-                waiter, &mutex);
-       ms_sleep(11);
-       dispatch("errorcheck mutex_unlock 1", MUTEX_UNLOCK, 1, 0, &mutex);
-       sched_yield();
-       err = pthread_mutex_unlock(&mutex);
-       if (err != EPERM) {
-               fprintf(stderr, "FAILURE: errorcheck mutex_unlock 2: %s\n",
-                       strerror(err));
-               exit(EXIT_FAILURE);
-       }
+static int dynamic_init_normal_contend(void)
+{
+       return __dynamic_init_contend(PTHREAD_MUTEX_NORMAL);
+}
 
-       start = timer_get_tsc();
-       dispatch("errorcheck mutex_lock 3", MUTEX_LOCK, 1, 0, &mutex);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
-       if (diff < 10000000) {
-               fprintf(stderr, "FAILURE: main, waited %Ld.%03u us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
-       dispatch("errorcheck mutex_unlock 3", MUTEX_UNLOCK, 1, 0, &mutex);
-       dispatch("errorcheck mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
+static int static_init_recursive_contend(void)
+{
+       pthread_mutex_t mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
+
+       return do_contend(&mutex, PTHREAD_MUTEX_RECURSIVE);
 }
 
-static void *timed_waiter(void *cookie)
+static int dynamic_init_recursive_contend(void)
 {
-       pthread_mutex_t *mutex = (pthread_mutex_t *) cookie;
-       unsigned long long start, diff;
+       return __dynamic_init_contend(PTHREAD_MUTEX_RECURSIVE);
+}
 
-       dispatch("timed_waiter pthread_detach", THREAD_DETACH, 1, 0);
+static int static_init_errorcheck_contend(void)
+{
+       pthread_mutex_t mutex = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP;
 
-       start = timer_get_tsc();
-       dispatch("timed_waiter mutex_timed_lock", MUTEX_TIMED_LOCK, 1,
-                ETIMEDOUT, mutex, 10000000ULL);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
-       if (diff < 10000000) {
-               fprintf(stderr, "FAILURE: timed_waiter, waited %Ld.%03u us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
+       return do_contend(&mutex, PTHREAD_MUTEX_ERRORCHECK);
+}
 
-       return cookie;
+static int dynamic_init_errorcheck_contend(void)
+{
+       return __dynamic_init_contend(PTHREAD_MUTEX_ERRORCHECK);
 }
 
-static void timed_mutex(void)
+static int timed_contend(void)
 {
        pthread_mutex_t mutex;
-       pthread_t waiter_tid;
-
-       smokey_trace("%s", __func__);
+       int ret;
 
-       dispatch("timed_mutex mutex_init", MUTEX_CREATE, 1, 0, &mutex,
-                PTHREAD_PRIO_INHERIT, PTHREAD_MUTEX_NORMAL);
-       dispatch("timed_mutex mutex_lock 1", MUTEX_LOCK, 1, 0, &mutex);
-       dispatch("timed_mutex thread_create", THREAD_CREATE, 1, 0, &waiter_tid,
-                2, timed_waiter, &mutex);
-       ms_sleep(20);
-       dispatch("timed_mutex mutex_unlock 1", MUTEX_UNLOCK, 1, 0, &mutex);
-       ms_sleep(11);
-       dispatch("timed_mutex mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
+       ret = do_init_mutex(&mutex, PTHREAD_MUTEX_NORMAL,
+                           PTHREAD_PRIO_INHERIT);
+       if (ret)
+               return ret;
 
+       return do_timed_contend(&mutex, THREAD_PRIO_MEDIUM);
 }
 
-static void mode_switch(void)
+static int weak_mode_switch(void)
 {
+       struct sched_param old_param, param = { .sched_priority = 0 };
+       int old_policy, ret, mode;
        pthread_mutex_t mutex;
 
-       /* Cause a switch to secondary mode */
-       __real_sched_yield();
+       ret = do_init_mutex(&mutex, PTHREAD_MUTEX_NORMAL,
+                           PTHREAD_PRIO_INHERIT);
+       if (ret)
+               return ret;
 
-       smokey_trace("%s", __func__);
+       /* Save old schedparams, then switch to weak mode. */
 
-       dispatch("switch mutex_init", MUTEX_CREATE, 1, 0, &mutex,
-                PTHREAD_PRIO_INHERIT, PTHREAD_MUTEX_NORMAL);
+       if (!__T(ret, pthread_getschedparam(pthread_self(),
+                                           &old_policy, &old_param)))
+               return ret;
 
-       check_current_mode(XNRELAX, XNRELAX);
+       /* Assume we are running SCHED_FIFO. */
 
-       dispatch("switch mutex_lock", MUTEX_LOCK, 1, 0, &mutex);
+       mode = cobalt_thread_mode();
+       if (!__Fassert(mode & XNWEAK))
+               return -EINVAL;
 
-       check_current_mode(XNRELAX, 0);
+       /* Enter SCHED_WEAK scheduling. */
+       
+       if (!__T(ret, pthread_setschedparam(pthread_self(),
+                                           SCHED_OTHER, &param)))
+               return ret;
 
-       dispatch("switch mutex_unlock", MUTEX_UNLOCK, 1, 0, &mutex);
-       dispatch("switch mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
-}
+       mode = cobalt_thread_mode();
+       if (!__Tassert((mode & (XNWEAK|XNRELAX)) == (XNWEAK|XNRELAX)))
+               return -EINVAL;
 
-static void pi_wait(void)
-{
-       unsigned long long start, diff;
-       pthread_mutex_t mutex;
-       pthread_t waiter_tid;
+       if (!__T(ret, pthread_mutex_lock(&mutex)))
+               return ret;
 
-#ifndef HAVE_PTHREAD_MUTEXATTR_SETPROTOCOL
-       smokey_note("PTHREAD_PRIO_INHERIT not supported");
-       return;
-#endif
-       smokey_trace("%s", __func__);
+       /*
+        * Holding a mutex should have switched us out of relaxed
+        * mode despite being assigned to the SCHED_WEAK class.
+        */
+       mode = cobalt_thread_mode();
+       if (!__Tassert((mode & (XNWEAK|XNRELAX)) == XNWEAK))
+               return -EINVAL;
 
-       dispatch("pi mutex_init", MUTEX_CREATE, 1, 0, &mutex,
-                PTHREAD_PRIO_INHERIT, PTHREAD_MUTEX_NORMAL);
-       dispatch("pi mutex_lock 1", MUTEX_LOCK, 1, 0, &mutex);
+       if (!__T(ret, pthread_mutex_unlock(&mutex)))
+               return ret;
 
-       check_current_prio(2);
+       /* Dropped it, we should have relaxed in the same move. */
+       
+       mode = cobalt_thread_mode();
+       if (!__Tassert((mode & (XNWEAK|XNRELAX)) == (XNWEAK|XNRELAX)))
+               return -EINVAL;
 
-       /* Give waiter a higher priority than main thread */
-       dispatch("pi thread_create", THREAD_CREATE, 1, 0, &waiter_tid, 3, 
waiter,
-                &mutex);
-       ms_sleep(11);
+       if (!__T(ret, pthread_mutex_destroy(&mutex)))
+               return ret;
 
-       check_current_prio(3);
+       /* Leaving the SCHED_WEAK class. */
 
-       dispatch("pi mutex_unlock 1", MUTEX_UNLOCK, 1, 0, &mutex);
+       if (!__T(ret, pthread_setschedparam(pthread_self(),
+                                           old_policy, &old_param)))
+               return ret;
 
-       check_current_prio(2);
+       mode = cobalt_thread_mode();
+       if (!__Fassert(mode & XNWEAK))
+               return -EINVAL;
 
-       start = timer_get_tsc();
-       dispatch("pi mutex_lock 2", MUTEX_LOCK, 1, 0, &mutex);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
-       if (diff < 10000000) {
-               fprintf(stderr, "FAILURE: main, waited %Ld.%03u us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
-       dispatch("pi mutex_unlock 2", MUTEX_UNLOCK, 1, 0, &mutex);
-       dispatch("pi mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
+       return 0;
 }
 
-static void lock_stealing(void)
+static int do_pi_contend(int prio)
 {
+       struct smokey_barrier barrier;
+       struct locker_context args;
        pthread_mutex_t mutex;
-       pthread_t lowprio_tid;
-       int trylock_result;
+       pthread_t tid;
+       void *status;
+       int ret;
 
-       /* Main thread acquires the mutex and starts a waiter with lower
-          priority. Then main thread releases the mutex, but locks it again
-          without giving the waiter a chance to get it beforehand. */
+       ret = do_init_mutex(&mutex, PTHREAD_MUTEX_NORMAL,
+                           PTHREAD_PRIO_INHERIT);
+       if (ret)
+               return ret;
 
-       smokey_trace("%s", __func__);
+       if (!__T(ret, pthread_mutex_lock(&mutex)))
+               return ret;
 
-       dispatch("lock_stealing mutex_init", MUTEX_CREATE, 1, 0, &mutex,
-                PTHREAD_PRIO_INHERIT, PTHREAD_MUTEX_NORMAL);
-       dispatch("lock_stealing mutex_lock 1", MUTEX_LOCK, 1, 0, &mutex);
+       args.mutex = &mutex;
+       smokey_barrier_init(&barrier);
+       args.barrier = &barrier;
+       ret = create_thread(&tid, SCHED_FIFO, prio,
+                           mutex_timed_locker, &args);
+       if (ret)
+               return ret;
 
-       /* Main thread should have higher priority */
-       dispatch("lock_stealing thread_create 1", THREAD_CREATE, 1, 0,
-                &lowprio_tid, 1, waiter, &mutex);
+       if (!__T(ret, smokey_barrier_wait(&barrier)))
+               return ret;
 
-       /* Give lowprio thread 1 more ms to block on the mutex */
-       ms_sleep(6);
+       /*
+        * Back while mutex_timed_locker is waiting. We should have
+        * been boosted by now.
+        */
+       if (!__Tassert(get_effective_prio() == prio))
+               return -EINVAL;
+       
+       if (!__T(ret, pthread_join(tid, &status)))
+               return ret;
 
-       dispatch("lock_stealing mutex_unlock 1", MUTEX_UNLOCK, 1, 0, &mutex);
+       if (!__T(ret, pthread_mutex_unlock(&mutex)))
+               return ret;
 
-       /* Try to stealing the lock from low prio task */
-       trylock_result = dispatch("lock_stealing mutex_trylock",
-                                 MUTEX_TRYLOCK, 0, 0, &mutex);
-       if (trylock_result == 0) {
-               ms_sleep(6);
+       if (!__Fassert(status == NULL))
+               return -EINVAL;
 
-               dispatch("lock_stealing mutex_unlock 2", MUTEX_UNLOCK, 1, 0,
-                        &mutex);
+       if (!__T(ret, pthread_mutex_destroy(&mutex)))
+               return ret;
+
+       return 0;
+}
 
-               /* Let waiter_lowprio a chance to run */
-               ms_sleep(20);
+static int pi_contend(void)
+{
+       return do_pi_contend(THREAD_PRIO_HIGH);
+}
 
-               dispatch("lock_stealing mutex_lock 3", MUTEX_LOCK, 1, 0, 
&mutex);
+static void *mutex_locker_steal(void *arg)
+{
+       struct locker_context *p = arg;
+       int ret;
 
-               /* Restart the waiter */
-               dispatch("lock_stealing thread_create 2", THREAD_CREATE, 1, 0,
-                        &lowprio_tid, 1, waiter, &mutex);
+       smokey_barrier_release(p->barrier);
+       
+       if (!__T(ret, pthread_mutex_lock(p->mutex)))
+               return (void *)(long)ret;
 
-               ms_sleep(6);
+       p->lock_acquired = 1;
 
-               dispatch("lock_stealing mutex_unlock 3", MUTEX_UNLOCK, 1, 0, 
&mutex);
-       } else if (trylock_result != EBUSY) {
-               fprintf(stderr,
-                       "FAILURE: lock_stealing mutex_trylock: %i (%s)\n",
-                       trylock_result, strerror(trylock_result));
-               exit(EXIT_FAILURE);
+       if (!__T(ret, pthread_mutex_unlock(p->mutex)))
+               return (void *)(long)ret;
+
+       return NULL;
+}
+
+static int do_steal(int may_steal)
+{
+       struct smokey_barrier barrier;
+       struct locker_context args;
+       pthread_mutex_t mutex;
+       pthread_t tid;
+       void *status;
+       int ret;
+
+       ret = do_init_mutex(&mutex, PTHREAD_MUTEX_NORMAL,
+                           PTHREAD_PRIO_NONE);
+       if (ret)
+               return ret;
+
+       if (!__T(ret, pthread_mutex_lock(&mutex)))
+               return ret;
+
+       args.mutex = &mutex;
+       smokey_barrier_init(&barrier);
+       args.barrier = &barrier;
+       args.lock_acquired = 0;
+       ret = create_thread(&tid, SCHED_FIFO, THREAD_PRIO_LOW,
+                           mutex_locker_steal, &args);
+       if (ret)
+               return ret;
+
+       /* Make sure the locker thread emerges... */
+       if (!__T(ret, smokey_barrier_wait(&barrier)))
+               return ret;
+
+       /* ...and blocks waiting on the mutex. */
+       sleep_ms(1);
+
+       /*
+        * Back while mutex_locker should be blocking.
+        *
+        * If stealing is exercised, unlock then relock immediately:
+        * we should have kept the ownership of the mutex and the
+        * locker thread should not have grabbed it so far, because of
+        * our higher priority.
+        *
+        * If stealing should not happen, unlock, wait a moment then
+        * observe whether the locker thread was able to grab it as
+        * expected.
+        *
+        * CAUTION: don't use pthread_mutex_trylock() to re-grab the
+        * mutex, this is not going to do what you want, since there
+        * is no stealing from userland, so using a fast op which
+        * never enters the kernel won't help.
+        */
+       if (!__T(ret, pthread_mutex_unlock(&mutex)))
+               return ret;
+
+       if (may_steal) {
+               if (!__T(ret, pthread_mutex_lock(&mutex)))
+                       return ret;
+
+               if (!__Fassert(args.lock_acquired))
+                       return -EINVAL;
+       } else {
+               sleep_ms(1);
+
+               if (!__T(ret, pthread_mutex_lock(&mutex)))
+                       return ret;
+
+               if (!__Tassert(args.lock_acquired))
+                       return -EINVAL;
        }
 
-       /* Stealing the lock (again) from low prio task */
-       dispatch("lock_stealing mutex_lock 4", MUTEX_LOCK, 1, 0, &mutex);
+       if (!__T(ret, pthread_mutex_unlock(&mutex)))
+               return ret;
 
-       ms_sleep(6);
+       if (!__T(ret, pthread_join(tid, &status)))
+               return ret;
 
-       dispatch("lock_stealing mutex_unlock 4", MUTEX_UNLOCK, 1, 0, &mutex);
+       if (!__Tassert(status == NULL))
+               return -EINVAL;
 
-       /* Let waiter_lowprio a chance to run */
-       ms_sleep(20);
+       if (!__T(ret, pthread_mutex_destroy(&mutex)))
+               return ret;
 
-       dispatch("lock_stealing mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
+       return 0;
+}
 
-       if (trylock_result != 0)
-               smokey_note("mutex_trylock not supported");
+static int steal(void)
+{
+       return do_steal(1);
 }
 
-static void *victim(void *cookie)
+static int no_steal(void)
 {
-       pthread_mutex_t *mutex = (pthread_mutex_t *) cookie;
-       unsigned long long start;
+       return do_steal(0);
+}
 
-       dispatch("victim pthread_detach", THREAD_DETACH, 1, 0);
-       dispatch("victim mutex_lock", MUTEX_LOCK, 1, 0, mutex);
+/*
+ * NOTE: Cobalt implements a lazy enforcement scheme for priority
+ * protection of threads running in primary mode, which only registers
+ * a pending boost at locking time, committing it eventually when/if
+ * the owner thread schedules away while holding it. Entering a short
+ * sleep (in primary mode) right after a mutex is grabbed makes sure
+ * the boost is actually applied.
+ */
+static int protect_raise(void)
+{
+       pthread_mutex_t mutex;
+       int ret;
+
+       ret = do_init_mutex_ceiling(&mutex, PTHREAD_MUTEX_NORMAL,
+                                   THREAD_PRIO_HIGH);
+       if (ret)
+               return ret;
 
-       start = timer_get_tsc();
-       while (timer_tsc2ns(timer_get_tsc() - start) < 110000000);
+       if (!__T(ret, pthread_mutex_lock(&mutex)))
+               return ret;
 
-       dispatch("victim mutex_unlock", MUTEX_UNLOCK, 1, 0, mutex);
+       sleep_ms(1);    /* Commit the pending PP request. */
 
-       return cookie;
+       /* We should have been given a MEDIUM -> HIGH boost. */
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_HIGH))
+               return -EINVAL;
+       
+       if (!__T(ret, pthread_mutex_unlock(&mutex)))
+               return ret;
+
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_MEDIUM))
+               return -EINVAL;
+       
+       return 0;
 }
 
-static void deny_stealing(void)
+static int protect_lower(void)
 {
-       unsigned long long start, diff;
        pthread_mutex_t mutex;
-       pthread_t lowprio_tid;
+       int ret;
 
-       smokey_trace("%s", __func__);
+       ret = do_init_mutex_ceiling(&mutex, PTHREAD_MUTEX_NORMAL,
+                                   THREAD_PRIO_LOW);
+       if (ret)
+               return ret;
 
-       dispatch("deny_stealing mutex_init", MUTEX_CREATE, 1, 0, &mutex,
-                PTHREAD_PRIO_INHERIT, PTHREAD_MUTEX_NORMAL);
-       dispatch("deny_stealing mutex_lock 1", MUTEX_LOCK, 1, 0, &mutex);
+       if (!__T(ret, pthread_mutex_lock(&mutex)))
+               return ret;
 
-       /* Main thread should have higher priority */
-       dispatch("deny_stealing thread_create", THREAD_CREATE, 1, 0,
-                &lowprio_tid, 1, victim, &mutex);
+       sleep_ms(1);    /* Commit the pending PP request. */
 
-       /* Give lowprio thread 1 more ms to block on the mutex */
-       ms_sleep(6);
+       /* No boost should be applied. */
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_MEDIUM))
+               return -EINVAL;
+       
+       if (!__T(ret, pthread_mutex_unlock(&mutex)))
+               return ret;
 
-       dispatch("deny_stealing mutex_unlock 1", MUTEX_UNLOCK, 1, 0, &mutex);
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_MEDIUM))
+               return -EINVAL;
+       
+       return 0;
+}
 
-       /* Steal the lock for a short while */
-       dispatch("deny_stealing mutex_lock 2", MUTEX_LOCK, 1, 0, &mutex);
-       dispatch("deny_stealing mutex_unlock 2", MUTEX_UNLOCK, 1, 0, &mutex);
+static int protect_weak(void)
+{
+       struct sched_param old_param, weak_param;
+       pthread_mutex_t mutex;
+       int ret, old_policy;
+
+       if (!__T(ret, pthread_getschedparam(pthread_self(),
+                                           &old_policy, &old_param)))
+               return ret;
+
+       /*
+        * Switch to the SCHED_WEAK class if present. THREAD_PRIO_WEAK
+        * (0) is used to make this work even without SCHED_WEAK
+        * support.
+        */
+       weak_param.sched_priority = THREAD_PRIO_WEAK;
+       if (!__T(ret, pthread_setschedparam(pthread_self(),
+                                           SCHED_WEAK, &weak_param)))
+               return ret;
+
+       ret = do_init_mutex_ceiling(&mutex, PTHREAD_MUTEX_NORMAL,
+                                   THREAD_PRIO_HIGH);
+       if (ret)
+               return ret;
+
+       if (!__T(ret, pthread_mutex_lock(&mutex)))
+               return ret;
+
+       sleep_ms(1);    /* Commit the pending PP request. */
+
+       /* We should have been sent to SCHED_FIFO, THREAD_PRIO_HIGH. */
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_HIGH))
+               return -EINVAL;
+       
+       if (!__T(ret, pthread_mutex_unlock(&mutex)))
+               return ret;
+
+       /* Back to SCHED_WEAK, THREAD_PRIO_WEAK. */
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_WEAK))
+               return -EINVAL;
+
+       if (!__T(ret, pthread_setschedparam(pthread_self(),
+                                           old_policy, &old_param)))
+               return ret;
+       
+       return 0;
+}
 
-       /* Give lowprio thread a chance to run */
-       ms_sleep(6);
+static int protect_nesting_protect(void)
+{
+       pthread_mutex_t mutex_high, mutex_very_high;
+       int ret;
 
-       /* Try to reacquire the lock, but the lowprio thread should hold it */
-       start = timer_get_tsc();
-       dispatch("deny_stealing mutex_lock 3", MUTEX_LOCK, 1, 0, &mutex);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
-       if (diff < 10000000) {
-               fprintf(stderr, "FAILURE: main, waited %Ld.%03u us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
+       ret = do_init_mutex_ceiling(&mutex_high, PTHREAD_MUTEX_NORMAL,
+                                   THREAD_PRIO_HIGH);
+       if (ret)
+               return ret;
 
-       dispatch("deny_stealing mutex_unlock 3", MUTEX_UNLOCK, 1, 0, &mutex);
+       ret = do_init_mutex_ceiling(&mutex_very_high, PTHREAD_MUTEX_NORMAL,
+                                   THREAD_PRIO_VERY_HIGH);
+       if (ret)
+               return ret;
 
-       /* Let waiter_lowprio a chance to run */
-       ms_sleep(20);
+       if (!__T(ret, pthread_mutex_lock(&mutex_high)))
+               return ret;
 
-       dispatch("deny_stealing mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
-}
+       sleep_ms(1);    /* Commit the pending PP request. */
 
-struct cond_mutex {
-       pthread_mutex_t *mutex;
-       pthread_cond_t *cond;
-};
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_HIGH))
+               return -EINVAL;
 
-static void *cond_signaler(void *cookie)
-{
-       struct cond_mutex *cm = (struct cond_mutex *) cookie;
-       unsigned long long start, diff;
+       if (!__T(ret, pthread_mutex_lock(&mutex_very_high)))
+               return ret;
 
-       start = timer_get_tsc();
-       dispatch("cond_signaler mutex_lock 1", MUTEX_LOCK, 1, 0, cm->mutex);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
+       sleep_ms(1);    /* Commit the pending PP request. */
 
-       if (diff < 10000000) {
-               fprintf(stderr,
-                       "FAILURE: cond_signaler, mutex_lock waited %Ld.%03u 
us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
-       ms_sleep(11);
-       dispatch("cond_signaler cond_signal", COND_SIGNAL, 1, 0, cm->cond);
-       dispatch("cond_signaler mutex_unlock 2", MUTEX_UNLOCK, 1, 0, cm->mutex);
-       sched_yield();
-
-       start = timer_get_tsc();
-       dispatch("cond_signaler mutex_lock 2", MUTEX_LOCK, 1, 0, cm->mutex);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
-       if (diff < 10000000) {
-               fprintf(stderr,
-                       "FAILURE: cond_signaler, mutex_lock 2 waited %Ld.%03u 
us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
-       dispatch("cond_signaler mutex_unlock 2", MUTEX_UNLOCK, 1, 0, cm->mutex);
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_VERY_HIGH))
+               return -EINVAL;
+
+       if (!__T(ret, pthread_mutex_unlock(&mutex_very_high)))
+               return ret;
 
-       return cookie;
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_HIGH))
+               return -EINVAL;
+       
+       if (!__T(ret, pthread_mutex_unlock(&mutex_high)))
+               return ret;
+
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_MEDIUM))
+               return -EINVAL;
+       
+       return 0;
 }
 
-static void simple_condwait(void)
+static int protect_nesting_pi(void)
 {
-       unsigned long long start, diff;
-       pthread_mutex_t mutex;
-       pthread_cond_t cond;
-       struct cond_mutex cm = {
-               .mutex = &mutex,
-               .cond = &cond,
-       };
-       pthread_t cond_signaler_tid;
-
-       smokey_trace("%s", __func__);
-
-       dispatch("simple_condwait mutex_init", MUTEX_CREATE, 1, 0, &mutex,
-                PTHREAD_PRIO_NONE, PTHREAD_MUTEX_NORMAL);
-       dispatch("simple_condwait cond_init", COND_CREATE, 1, 0, &cond);
-       dispatch("simple_condwait mutex_lock", MUTEX_LOCK, 1, 0, &mutex);
-       dispatch("simple_condwait thread_create", THREAD_CREATE, 1, 0,
-                &cond_signaler_tid, 2, cond_signaler, &cm);
-
-       ms_sleep(11);
-       start = timer_get_tsc();
-       dispatch("simple_condwait cond_wait", COND_WAIT, 1, 0, &cond, &mutex);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
-       if (diff < 10000000) {
-               fprintf(stderr, "FAILURE: main, waited %Ld.%03u us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
-       ms_sleep(11);
-       dispatch("simple_condwait mutex_unlock", MUTEX_UNLOCK, 1, 0, &mutex);
-       sched_yield();
-
-       dispatch("simple_condwait mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
-       dispatch("simple_condwait cond_destroy", COND_DESTROY, 1, 0, &cond);
+       pthread_mutex_t mutex_pp;
+       int ret;
 
-       dispatch("simple_condwait join", THREAD_JOIN, 1, 0, &cond_signaler_tid);
+       ret = do_init_mutex_ceiling(&mutex_pp, PTHREAD_MUTEX_NORMAL,
+                                   THREAD_PRIO_HIGH);
+       if (ret)
+               return ret;
+
+       if (!__T(ret, pthread_mutex_lock(&mutex_pp)))
+               return ret;
+
+       sleep_ms(1);    /* Commit the pending PP request. */
+
+       /* PP ceiling: MEDIUM -> HIGH */
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_HIGH))
+               return -EINVAL;
+       
+       /* PI boost expected: HIGH -> VERY_HIGH, then back to HIGH */
+       ret = do_pi_contend(THREAD_PRIO_VERY_HIGH);
+       if (ret)
+               return ret;
+
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_HIGH))
+               return -EINVAL;
+       
+       if (!__T(ret, pthread_mutex_unlock(&mutex_pp)))
+               return ret;
+
+       /* PP boost just dropped: HIGH -> MEDIUM. */
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_MEDIUM))
+               return -EINVAL;
+       
+       return 0;
 }
 
-static void recursive_condwait(void)
+static int protect_dynamic(void)
 {
-       unsigned long long start, diff;
        pthread_mutex_t mutex;
-       pthread_cond_t cond;
-       struct cond_mutex cm = {
-               .mutex = &mutex,
-               .cond = &cond,
-       };
-       pthread_t cond_signaler_tid;
-
-       smokey_trace("%s", __func__);
-
-       dispatch("rec_condwait mutex_init", MUTEX_CREATE, 1, 0, &mutex,
-                PTHREAD_PRIO_NONE, PTHREAD_MUTEX_RECURSIVE);
-       dispatch("rec_condwait cond_init", COND_CREATE, 1, 0, &cond);
-       dispatch("rec_condwait mutex_lock 1", MUTEX_LOCK, 1, 0, &mutex);
-       dispatch("rec_condwait mutex_lock 2", MUTEX_LOCK, 1, 0, &mutex);
-       dispatch("rec_condwait thread_create", THREAD_CREATE, 1, 0,
-                &cond_signaler_tid, 2, cond_signaler, &cm);
-
-       ms_sleep(11);
-       start = timer_get_tsc();
-       dispatch("rec_condwait cond_wait", COND_WAIT, 1, 0, &cond, &mutex);
-       diff = timer_tsc2ns(timer_get_tsc() - start);
-       if (diff < 10000000) {
-               fprintf(stderr, "FAILURE: main, waited %Ld.%03u us\n",
-                       diff / 1000, (unsigned) (diff % 1000));
-               exit(EXIT_FAILURE);
-       }
-       dispatch("rec_condwait mutex_unlock 1", MUTEX_UNLOCK, 1, 0, &mutex);
-       ms_sleep(11);
-       dispatch("rec_condwait mutex_unlock 2", MUTEX_UNLOCK, 1, 0, &mutex);
-       sched_yield();
+       int ret, old_ceiling;
 
-       dispatch("rec_condwait mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
-       dispatch("rec_condwait cond_destroy", COND_DESTROY, 1, 0, &cond);
+       ret = do_init_mutex_ceiling(&mutex, PTHREAD_MUTEX_NORMAL,
+                                   THREAD_PRIO_HIGH);
+       if (ret)
+               return ret;
 
-       dispatch("rec_condwait join", THREAD_JOIN, 1, 0, &cond_signaler_tid);
-}
+       if (!__T(ret, pthread_mutex_setprioceiling(&mutex,
+                                                  THREAD_PRIO_VERY_HIGH, 
&old_ceiling)))
+               return ret;
 
-static void nrt_lock(void *cookie)
-{
-       pthread_mutex_t *mutex = cookie;
+       if (!__Tassert(old_ceiling == THREAD_PRIO_HIGH))
+               return -EINVAL;
+
+       if (!__T(ret, pthread_mutex_lock(&mutex)))
+               return ret;
+
+       sleep_ms(1);    /* Commit the pending PP request. */
 
-       /* Check that XNWEAK flag gets cleared and set back when
-          changing priority */
-       check_current_mode(XNRELAX | XNWEAK, XNRELAX | XNWEAK);
-       check_current_prio(0);
-       dispatch("auto_switchback renice 1", THREAD_RENICE, 1, 0, 1);
-       check_current_mode(XNWEAK, 0);
-       check_current_prio(1);
-       dispatch("auto_switchback renice 2", THREAD_RENICE, 1, 0, 0);
-       check_current_mode(XNRELAX | XNWEAK, XNRELAX | XNWEAK);
-       check_current_prio(0);
+       /* We should have been given a HIGH -> VERY_HIGH boost. */
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_VERY_HIGH))
+               return -EINVAL;
+       
+       if (!__T(ret, pthread_mutex_unlock(&mutex)))
+               return ret;
 
-       /* Check mode changes for auto-switchback threads while using
-          mutexes with priority inheritance */
-       dispatch("auto_switchback mutex_lock 1", MUTEX_LOCK, 1, 0, mutex);
-       check_current_mode(XNRELAX, 0);
-       ms_sleep(11);
-       check_current_prio(2);
-       dispatch("auto_switchback mutex_unlock 1", MUTEX_UNLOCK, 1, 0, mutex);
-       check_current_mode(XNRELAX | XNWEAK, XNRELAX | XNWEAK);
+       /* Drop the boost: VERY_HIGH -> MEDIUM. */
+       if (!__Tassert(get_effective_prio() == THREAD_PRIO_MEDIUM))
+               return -EINVAL;
+
+       if (!__T(ret, pthread_mutex_getprioceiling(&mutex, &old_ceiling)))
+               return ret;
+
+       if (!__Tassert(old_ceiling == THREAD_PRIO_VERY_HIGH))
+               return -EINVAL;
+
+       if (!__T(ret, pthread_mutex_destroy(&mutex)))
+               return ret;
+
+       return 0;
 }
 
-static void auto_switchback(void)
+/* Detect obviously wrong execution times. */
+static int check_time_limit(const struct timespec *start,
+                           xnticks_t limit_ns)
 {
-       pthread_t nrt_lock_tid;
-       pthread_mutex_t mutex;
-
-       smokey_trace("%s", __func__);
+       struct timespec stop, delta;
 
-       dispatch("auto_switchback mutex_init", MUTEX_CREATE, 1, 0, &mutex,
-                PTHREAD_PRIO_INHERIT, PTHREAD_MUTEX_RECURSIVE);
-       dispatch("auto_switchback nrt thread_create", THREAD_CREATE, 1, 0,
-                &nrt_lock_tid, 0, nrt_lock, &mutex);
-       ms_sleep(11);
-       dispatch("auto_switchback mutex_lock 2", MUTEX_LOCK, 1, 0, &mutex);
-       dispatch("auto_switchback mutex_unlock 2", MUTEX_UNLOCK, 1, 0, &mutex);
+       clock_gettime(CLOCK_MONOTONIC, &stop);
+       timespec_sub(&delta, &stop, start);
 
-       dispatch("auto_switchback join", THREAD_JOIN, 1, 0, &nrt_lock_tid);
-       dispatch("auto_switchback mutex_destroy", MUTEX_DESTROY, 1, 0, &mutex);
+       return timespec_scalar(&delta) <= limit_ns;
 }
 
-int run_posix_mutex(struct smokey_test *t, int argc, char *const argv[])
+#define do_test(__fn, __limit_ns)                                      \
+       do {                                                            \
+               struct timespec __start;                                \
+               int __ret;                                              \
+               smokey_trace(".. " __stringify(__fn));                  \
+               clock_gettime(CLOCK_MONOTONIC, &__start);               \
+               __ret = __fn();                                         \
+               if (__ret)                                              \
+                       return __ret;                                   \
+               if (!__Tassert(check_time_limit(&__start, __limit_ns))) \
+                       return -ETIMEDOUT;                              \
+       } while (0)
+
+static int run_posix_mutex(struct smokey_test *t, int argc, char *const argv[])
 {
-       struct sched_param sparam;
+       struct sched_param param;
        struct sigaction sa;
+       int ret;
 
        sigemptyset(&sa.sa_mask);
        sa.sa_sigaction = sigdebug;
        sa.sa_flags = SA_SIGINFO;
        sigaction(SIGDEBUG, &sa, NULL);
 
-       /* Set scheduling parameters for the current process */
-       sparam.sched_priority = 2;
-       pthread_setschedparam(pthread_self(), SCHED_FIFO, &sparam);
-
-       /* Call test routines */
-       autoinit_simple_wait();
-       simple_wait();
-       autoinit_recursive_wait();
-       recursive_wait();
-       autoinit_errorcheck_wait();
-       errorcheck_wait();
-       timed_mutex();
-       mode_switch();
-       pi_wait();
-       lock_stealing();
-       deny_stealing();
-       simple_condwait();
-       recursive_condwait();
-       auto_switchback();
+       param.sched_priority = THREAD_PRIO_MEDIUM;
+       if (!__T(ret, pthread_setschedparam(pthread_self(),
+                                           SCHED_FIFO, &param)))
+               return ret;
+
+       do_test(static_init_normal_contend, MAX_100_MS);
+       do_test(dynamic_init_normal_contend, MAX_100_MS);
+       do_test(static_init_recursive_contend, MAX_100_MS);
+       do_test(dynamic_init_recursive_contend, MAX_100_MS);
+       do_test(static_init_errorcheck_contend, MAX_100_MS);
+       do_test(dynamic_init_errorcheck_contend, MAX_100_MS);
+       do_test(timed_contend, MAX_100_MS);
+       do_test(weak_mode_switch, MAX_100_MS);
+       do_test(pi_contend, MAX_100_MS);
+       do_test(steal, MAX_100_MS);
+       do_test(no_steal, MAX_100_MS);
+       do_test(protect_raise, MAX_100_MS);
+       do_test(protect_lower, MAX_100_MS);
+       do_test(protect_nesting_protect, MAX_100_MS);
+       do_test(protect_nesting_pi, MAX_100_MS);
+       do_test(protect_weak, MAX_100_MS);
+       do_test(protect_dynamic, MAX_100_MS);
 
        return 0;
 }


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
https://xenomai.org/mailman/listinfo/xenomai-git

Reply via email to