Module: xenomai-3
Branch: wip/prioceil
Commit: 8df8a403a09c8cf9ddc07c8e8fb589e43715bde6
URL:    
http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=8df8a403a09c8cf9ddc07c8e8fb589e43715bde6

Author: Philippe Gerum <r...@xenomai.org>
Date:   Tue Feb 16 10:13:03 2016 +0100

lib/cobalt/mutex: add support for priority ceiling protocol

---

 configure.ac               |    2 +
 include/boilerplate/libc.h |   19 +++
 include/cobalt/pthread.h   |    7 ++
 lib/cobalt/cobalt.wrappers |    2 +
 lib/cobalt/init.c          |    1 +
 lib/cobalt/internal.h      |    8 ++
 lib/cobalt/mutex.c         |  301 +++++++++++++++++++++++++++++++++++---------
 lib/cobalt/sched.c         |   33 ++++-
 lib/cobalt/thread.c        |    7 +-
 9 files changed, 311 insertions(+), 69 deletions(-)

diff --git a/configure.ac b/configure.ac
index 8bbeeef..578327e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -504,6 +504,8 @@ save_LIBS="$LIBS"
 LIBS="$LIBS -lrt -lpthread"
 AC_CHECK_FUNCS([pthread_mutexattr_setprotocol  \
                pthread_mutexattr_getprotocol   \
+               pthread_mutexattr_getprioceiling \
+               pthread_mutexattr_setprioceiling \
                pthread_mutexattr_setrobust_np  \
                pthread_condattr_getclock       \
                pthread_condattr_setclock       \
diff --git a/include/boilerplate/libc.h b/include/boilerplate/libc.h
index 0e51b86..3a5af8c 100644
--- a/include/boilerplate/libc.h
+++ b/include/boilerplate/libc.h
@@ -108,6 +108,25 @@ int pthread_mutexattr_getprotocol(const 
pthread_mutexattr_t *
 }
 #endif /* !HAVE_PTHREAD_MUTEXATTR_GETPROTOCOL */
 
+#ifndef HAVE_PTHREAD_MUTEXATTR_SETPRIOCEILING
+static inline
+int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr,
+                                    int prioceiling)
+{
+       return ENOSYS;
+}
+#endif /* !HAVE_PTHREAD_MUTEXATTR_SETPRIOCEILING */
+
+#ifndef HAVE_PTHREAD_MUTEXATTR_GETPRIOCEILING
+static inline
+int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *
+                                     __restrict attr,
+                                    int *__restrict prioceiling)
+{
+       return ENOSYS;
+}
+#endif /* !HAVE_PTHREAD_MUTEXATTR_GETPRIOCEILING */
+
 #ifndef HAVE_PTHREAD_ATTR_SETAFFINITY_NP
 #include <sched.h>
 static inline
diff --git a/include/cobalt/pthread.h b/include/cobalt/pthread.h
index 386c337..f1b1c8a 100644
--- a/include/cobalt/pthread.h
+++ b/include/cobalt/pthread.h
@@ -67,6 +67,13 @@ COBALT_DECL(int, pthread_mutex_trylock(pthread_mutex_t 
*mutex));
 
 COBALT_DECL(int, pthread_mutex_unlock(pthread_mutex_t *mutex));
 
+COBALT_DECL(int, pthread_mutex_setprioceiling(pthread_mutex_t *__restrict 
mutex,
+                                             int prioceiling,
+                                             int *__restrict old_ceiling));
+  
+COBALT_DECL(int, pthread_mutex_getprioceiling(pthread_mutex_t *__restrict 
mutex,
+                                             int *__restrict old_ceiling));
+
 COBALT_DECL(int, pthread_cond_init (pthread_cond_t *cond,
                                    const pthread_condattr_t *attr));
 
diff --git a/lib/cobalt/cobalt.wrappers b/lib/cobalt/cobalt.wrappers
index 9480f34..75f29d6 100644
--- a/lib/cobalt/cobalt.wrappers
+++ b/lib/cobalt/cobalt.wrappers
@@ -32,6 +32,8 @@
 --wrap pthread_mutex_trylock
 --wrap pthread_mutex_timedlock
 --wrap pthread_mutex_unlock
+--wrap pthread_mutex_setprioceiling
+--wrap pthread_mutex_getprioceiling
 --wrap pthread_cond_init
 --wrap pthread_cond_destroy
 --wrap pthread_cond_wait
diff --git a/lib/cobalt/init.c b/lib/cobalt/init.c
index f260744..69d4763 100644
--- a/lib/cobalt/init.c
+++ b/lib/cobalt/init.c
@@ -177,6 +177,7 @@ static void __cobalt_init(void)
                            sizeof(struct cobalt_sem_shadow));
 
        cobalt_mutex_init();
+       cobalt_sched_init();
        cobalt_thread_init();
        cobalt_print_init();
 }
diff --git a/lib/cobalt/internal.h b/lib/cobalt/internal.h
index 69ec7d1..cdb2eee 100644
--- a/lib/cobalt/internal.h
+++ b/lib/cobalt/internal.h
@@ -47,6 +47,8 @@ void cobalt_thread_init(void);
 
 int cobalt_thread_probe(pid_t pid);
 
+void cobalt_sched_init(void);
+
 void cobalt_print_init(void);
 
 void cobalt_print_init_atfork(void);
@@ -68,4 +70,10 @@ void cobalt_check_features(struct cobalt_featinfo *finfo);
 
 extern struct sigaction __cobalt_orig_sigdebug;
 
+extern int __cobalt_std_fifo_minpri,
+          __cobalt_std_fifo_maxpri;
+
+extern int __cobalt_std_rr_minpri,
+          __cobalt_std_rr_maxpri;
+
 #endif /* _LIB_COBALT_INTERNAL_H */
diff --git a/lib/cobalt/mutex.c b/lib/cobalt/mutex.c
index 9d8a914..1456099 100644
--- a/lib/cobalt/mutex.c
+++ b/lib/cobalt/mutex.c
@@ -99,6 +99,9 @@ void cobalt_mutex_init(void)
  *   mutex, increase CONFIG_XENO_OPT_SHARED_HEAPSZ for a process-shared
  *   mutex, or CONFIG_XENO_OPT_PRIVATE_HEAPSZ for a process-private mutex.
  * - EAGAIN, no registry slot available, check/raise 
CONFIG_XENO_OPT_REGISTRY_NRSLOTS.
+ * - ENOSYS, @a attr mentions priority protection
+ *  (PTHREAD_PRIO_PROTECT), but the C library does not provide
+ *  pthread_mutexattr_get/setprioceiling().
  *
  * @see
  * <a 
href="http://www.opengroup.org/onlinepubs/000095399/functions/pthread_mutex_init.html";>
@@ -117,7 +120,6 @@ COBALT_IMPL(int, pthread_mutex_init, (pthread_mutex_t 
*mutex,
 
        if (_mutex->magic == COBALT_MUTEX_MAGIC) {
                err = -XENOMAI_SYSCALL1(sc_cobalt_mutex_check_init, _mutex);
-
                if (err)
                        return err;
        }
@@ -138,12 +140,19 @@ COBALT_IMPL(int, pthread_mutex_init, (pthread_mutex_t 
*mutex,
        err = pthread_mutexattr_getprotocol(attr, &tmp);
        if (err)
                return err;
-       if (tmp == PTHREAD_PRIO_PROTECT) { /* Prio ceiling unsupported */
-               err = EINVAL;
-               return err;
-       }
        kmattr.protocol = tmp;
 
+       if (kmattr.protocol == PTHREAD_PRIO_PROTECT) {
+               err = pthread_mutexattr_getprioceiling(attr, &tmp);
+               if (err)
+                       return err;
+               if (tmp == 0 || /* Could not cope with null minpri. */
+                   tmp < __cobalt_std_fifo_minpri ||
+                   tmp > __cobalt_std_fifo_maxpri)
+                       return EINVAL;
+               kmattr.ceiling = tmp - 1;
+       }
+
        err = -XENOMAI_SYSCALL2(sc_cobalt_mutex_init, _mutex, &kmattr);
        if (err)
                return err;
@@ -251,7 +260,7 @@ static int __attribute__((cold)) 
cobalt_mutex_autoinit(pthread_mutex_t *mutex)
  *
  * @return 0 on success
  * @return an error number if:
- * - EPERM, the caller context is invalid;
+ * - EPERM, the caller is not allowed to perform the operation;
  * - EINVAL, the mutex @a mx is invalid;
  * - EPERM, the mutex is not process-shared and does not belong to the current
  *   process;
@@ -270,7 +279,8 @@ COBALT_IMPL(int, pthread_mutex_lock, (pthread_mutex_t 
*mutex))
 {
        struct cobalt_mutex_shadow *_mutex =
                &((union cobalt_mutex_union *)mutex)->shadow_mutex;
-       int status, ret;
+       struct xnthread_user_window *u_window;
+       int status, ret, lazy_protect = 0;
        xnhandle_t cur;
 
        cur = cobalt_get_current();
@@ -285,21 +295,28 @@ COBALT_IMPL(int, pthread_mutex_lock, (pthread_mutex_t 
*mutex))
         * shadows and some debug features, so we must always obtain
         * them via a syscall.
         */
-  cont:
+start:
        status = cobalt_get_current_mode();
        if ((status & (XNRELAX|XNWEAK|XNDEBUG)) == 0) {
+               if (_mutex->attr.protocol == PTHREAD_PRIO_PROTECT)
+                       goto protect;
+fast_path:
                ret = xnsynch_fast_acquire(mutex_get_ownerp(_mutex), cur);
                if (ret == 0) {
                        _mutex->lockcnt = 1;
                        return 0;
                }
        } else {
+slow_path:
                ret = xnsynch_fast_owner_check(mutex_get_ownerp(_mutex), cur);
                if (ret == 0)
                        ret = -EBUSY;
        }
 
-       if (ret == -EBUSY)
+       if (ret == -EBUSY) {
+               if (lazy_protect)
+                       u_window->pp_pending = XN_NO_HANDLE;
+
                switch(_mutex->attr.type) {
                case PTHREAD_MUTEX_NORMAL:
                        break;
@@ -313,6 +330,7 @@ COBALT_IMPL(int, pthread_mutex_lock, (pthread_mutex_t 
*mutex))
                        ++_mutex->lockcnt;
                        return 0;
                }
+       }
 
        do
                ret = XENOMAI_SYSCALL1(sc_cobalt_mutex_lock, _mutex);
@@ -322,12 +340,22 @@ COBALT_IMPL(int, pthread_mutex_lock, (pthread_mutex_t 
*mutex))
                _mutex->lockcnt = 1;
 
        return -ret;
-
-  autoinit:
+protect:       
+       u_window = cobalt_get_current_window();
+       /*
+        * Can't nest lazy ceiling requests, have to take the slow
+        * path when this happens.
+        */
+       if (u_window->pp_pending != XN_NO_HANDLE)
+               goto slow_path;
+       u_window->pp_pending = _mutex->handle;
+       lazy_protect = 1;
+       goto fast_path;
+autoinit:
        ret = cobalt_mutex_autoinit(mutex);
        if (ret)
                return ret;
-       goto cont;
+       goto start;
 }
 
 /**
@@ -344,7 +372,7 @@ COBALT_IMPL(int, pthread_mutex_lock, (pthread_mutex_t 
*mutex))
  *
  * @return 0 on success;
  * @return an error number if:
- * - EPERM, the caller context is invalid;
+ * - EPERM, the caller is not allowed to perform the operation;
  * - EINVAL, the mutex @a mx is invalid;
  * - EPERM, the mutex is not process-shared and does not belong to the current
  *   process;
@@ -366,7 +394,8 @@ COBALT_IMPL(int, pthread_mutex_timedlock, (pthread_mutex_t 
*mutex,
 {
        struct cobalt_mutex_shadow *_mutex =
                &((union cobalt_mutex_union *)mutex)->shadow_mutex;
-       int status, ret;
+       struct xnthread_user_window *u_window;
+       int status, ret, lazy_protect = 0;
        xnhandle_t cur;
 
        cur = cobalt_get_current();
@@ -377,21 +406,28 @@ COBALT_IMPL(int, pthread_mutex_timedlock, 
(pthread_mutex_t *mutex,
                goto autoinit;
 
        /* See __cobalt_pthread_mutex_lock() */
-  cont:
+start:
        status = cobalt_get_current_mode();
        if ((status & (XNRELAX|XNWEAK|XNDEBUG)) == 0) {
+               if (_mutex->attr.protocol == PTHREAD_PRIO_PROTECT)
+                       goto protect;
+fast_path:
                ret = xnsynch_fast_acquire(mutex_get_ownerp(_mutex), cur);
                if (ret == 0) {
                        _mutex->lockcnt = 1;
                        return 0;
                }
        } else {
+slow_path:
                ret = xnsynch_fast_owner_check(mutex_get_ownerp(_mutex), cur);
                if (ret == 0)
                        ret = -EBUSY;
        }
 
-       if (ret == -EBUSY)
+       if (ret == -EBUSY) {
+               if (lazy_protect)
+                       u_window->pp_pending = XN_NO_HANDLE;
+                       
                switch(_mutex->attr.type) {
                case PTHREAD_MUTEX_NORMAL:
                        break;
@@ -406,6 +442,7 @@ COBALT_IMPL(int, pthread_mutex_timedlock, (pthread_mutex_t 
*mutex,
                        ++_mutex->lockcnt;
                        return 0;
                }
+       }
 
        do {
                ret = XENOMAI_SYSCALL2(sc_cobalt_mutex_timedlock, _mutex, to);
@@ -414,12 +451,22 @@ COBALT_IMPL(int, pthread_mutex_timedlock, 
(pthread_mutex_t *mutex,
        if (ret == 0)
                _mutex->lockcnt = 1;
        return -ret;
-
-  autoinit:
+protect:       
+       u_window = cobalt_get_current_window();
+       /*
+        * Can't nest lazy ceiling requests, have to take the slow
+        * path when this happens.
+        */
+       if (u_window->pp_pending != XN_NO_HANDLE)
+               goto slow_path;
+       u_window->pp_pending = _mutex->handle;
+       lazy_protect = 1;
+       goto fast_path;
+autoinit:
        ret = cobalt_mutex_autoinit(mutex);
        if (ret)
                return ret;
-       goto cont;
+       goto start;
 }
 
 /**
@@ -433,7 +480,7 @@ COBALT_IMPL(int, pthread_mutex_timedlock, (pthread_mutex_t 
*mutex,
  *
  * @return 0 on success;
  * @return an error number if:
- * - EPERM, the caller context is invalid;
+ * - EPERM, the caller is not allowed to perform the operation;
  * - EINVAL, the mutex is invalid;
  * - EPERM, the mutex is not process-shared and does not belong to the current
  *   process;
@@ -451,7 +498,8 @@ COBALT_IMPL(int, pthread_mutex_trylock, (pthread_mutex_t 
*mutex))
 {
        struct cobalt_mutex_shadow *_mutex =
                &((union cobalt_mutex_union *)mutex)->shadow_mutex;
-       int status, err;
+       struct xnthread_user_window *u_window;
+       int status, ret, lazy_protect = 0;
        xnhandle_t cur;
 
        cur = cobalt_get_current();
@@ -460,58 +508,75 @@ COBALT_IMPL(int, pthread_mutex_trylock, (pthread_mutex_t 
*mutex))
 
        if (_mutex->magic != COBALT_MUTEX_MAGIC)
                goto autoinit;
-
-  cont:
+start:
        status = cobalt_get_current_mode();
        if ((status & (XNRELAX|XNWEAK|XNDEBUG)) == 0) {
-               err = xnsynch_fast_acquire(mutex_get_ownerp(_mutex), cur);
-               if (err == 0) {
+               if (_mutex->attr.protocol == PTHREAD_PRIO_PROTECT)
+                       goto protect;
+fast_path:
+               ret = xnsynch_fast_acquire(mutex_get_ownerp(_mutex), cur);
+               if (ret == 0) {
                        _mutex->lockcnt = 1;
                        return 0;
                }
        } else {
-               err = xnsynch_fast_owner_check(mutex_get_ownerp(_mutex), cur);
-               if (err < 0)
+slow_path:
+               ret = xnsynch_fast_owner_check(mutex_get_ownerp(_mutex), cur);
+               if (ret < 0)
                        goto do_syscall;
 
-               err = -EBUSY;
+               ret = -EBUSY;
        }
 
-       if (err == -EBUSY && _mutex->attr.type == PTHREAD_MUTEX_RECURSIVE) {
-               if (_mutex->lockcnt == UINT32_MAX)
-                       return EAGAIN;
+       if (ret == -EBUSY) {
+               if (lazy_protect)
+                       u_window->pp_pending = XN_NO_HANDLE;
 
-               ++_mutex->lockcnt;
-               return 0;
+               if (_mutex->attr.type == PTHREAD_MUTEX_RECURSIVE) {
+                       if (_mutex->lockcnt == UINT32_MAX)
+                               return EAGAIN;
+
+                       ++_mutex->lockcnt;
+                       return 0;
+               }
        }
 
        return EBUSY;
 
 do_syscall:
-
        do {
-               err = XENOMAI_SYSCALL1(sc_cobalt_mutex_trylock, _mutex);
-       } while (err == -EINTR);
+               ret = XENOMAI_SYSCALL1(sc_cobalt_mutex_trylock, _mutex);
+       } while (ret == -EINTR);
 
-       if (!err)
+       if (ret == 0)
                _mutex->lockcnt = 1;
 
-       return -err;
-
-  autoinit:
-       err = cobalt_mutex_autoinit(mutex);
-       if (err)
-               return err;
-       goto cont;
+       return -ret;
+autoinit:
+       ret = cobalt_mutex_autoinit(mutex);
+       if (ret)
+               return ret;
+       goto start;
+protect:       
+       u_window = cobalt_get_current_window();
+       /*
+        * Can't nest lazy ceiling requests, have to take the slow
+        * path when this happens.
+        */
+       if (u_window->pp_pending != XN_NO_HANDLE)
+               goto slow_path;
+       u_window->pp_pending = _mutex->handle;
+       lazy_protect = 1;
+       goto fast_path;
 }
 
 /**
  * Unlock a mutex.
  *
- * This service unlocks the mutex @a mx. If the mutex is of the @a
- * PTHREAD_MUTEX_RECURSIVE @a type and the locking recursion count is greater
- * than one, the lock recursion count is decremented and the mutex remains
- * locked.
+ * This service unlocks the @a mutex. If @a mutex is of the @a
+ * PTHREAD_MUTEX_RECURSIVE and the locking recursion count is greater
+ * than one, the lock recursion count is decremented and the mutex
+ * remains locked.
  *
  * Attempting to unlock a mutex which is not locked or which is locked by
  * another thread than the current one yields the EPERM error, whatever the
@@ -521,8 +586,8 @@ do_syscall:
  *
  * @return 0 on success;
  * @return an error number if:
- * - EPERM, the caller context is invalid;
- * - EINVAL, the mutex @a mx is invalid;
+ * - EPERM, the caller is not allowed to perform the operation;
+ * - EINVAL, the mutex @a mutex is invalid;
  * - EPERM, the mutex was not locked by the current thread.
  *
  * @see
@@ -535,14 +600,14 @@ COBALT_IMPL(int, pthread_mutex_unlock, (pthread_mutex_t 
*mutex))
 {
        struct cobalt_mutex_shadow *_mutex =
                &((union cobalt_mutex_union *)mutex)->shadow_mutex;
+       struct xnthread_user_window *u_window;
        struct cobalt_mutex_state *state;
        xnhandle_t cur;
        int err;
 
        if (_mutex->magic != COBALT_MUTEX_MAGIC)
                goto autoinit;
-
-  cont:
+start:
        cur = cobalt_get_current();
        if (cur == XN_NO_HANDLE)
                return EPERM;
@@ -562,21 +627,135 @@ COBALT_IMPL(int, pthread_mutex_unlock, (pthread_mutex_t 
*mutex))
        if (cobalt_get_current_mode() & (XNWEAK|XNDEBUG))
                goto do_syscall;
 
-       if (xnsynch_fast_release(&state->owner, cur))
+       if (xnsynch_fast_release(&state->owner, cur)) {
+               if (_mutex->attr.protocol == PTHREAD_PRIO_PROTECT)
+                       goto unprotect;
                return 0;
+       }
 do_syscall:
-
        do {
                err = XENOMAI_SYSCALL1(sc_cobalt_mutex_unlock, _mutex);
        } while (err == -EINTR);
 
        return -err;
 
-  autoinit:
+autoinit:
        err = cobalt_mutex_autoinit(mutex);
        if (err)
                return err;
-       goto cont;
+       goto start;
+unprotect:
+       u_window = cobalt_get_current_window();
+       u_window->pp_pending = XN_NO_HANDLE;
+
+       return 0;
+}
+
+/**
+ * Set a mutex's priority ceiling.
+ *
+ * This routine acquires the specified mutex, then changes the
+ * associated priority ceiling value and releases it.  @a prioceiling
+ * must be between the values returned by sched_get_priority_min() and
+ * sched_get_priority_max(), inclusive.
+ *
+ * The Cobalt implementation applies the priority ceiling protocol
+ * using the previous ceiling value during this operation. The new
+ * priority ceiling will apply next time the @a mutex transitions from
+ * the unlocked to locked state.
+ *
+ * @param mutex the target mutex.
+ *
+ * @param prioceiling the new ceiling value.
+ *
+ * @param old_ceiling on success and if this parameter is non-NULL,
+ * the previous ceiling value is copied to this address.
+ *
+ * @return 0 on success;
+ * @return an error number if:
+ * - EPERM, the caller is not allowed to perform the operation;
+ * - EINVAL, @a mutex is invalid;
+ * - EINVAL, @a mutex is not of type PTHREAD_PRIO_PROTECT;
+ * - EINVAL, @a prioceiling is out of range;
+ *
+ * @see
+ * <a 
href="http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_mutex_setprioceiling.html";>
+ * Specification.</a>
+ *
+ * @apitags{xthread-only, switch-primary}
+ *
+ * @note If the calling thread's priority is higher than the mutex's
+ * new priority ceiling, the operation will nevertheless succeed; the
+ * Cobalt core never decreases the effective priority of a thread
+ * which locks a priority-protected mutex.
+ */
+COBALT_IMPL(int, pthread_mutex_setprioceiling,
+           (pthread_mutex_t *__restrict mutex,
+            int prioceiling, int *__restrict old_ceiling))
+{
+       struct cobalt_mutex_shadow *_mutex =
+               &((union cobalt_mutex_union *)mutex)->shadow_mutex;
+       struct cobalt_mutex_state *state;
+       int ret;
+
+       if (_mutex->magic != COBALT_MUTEX_MAGIC ||
+           _mutex->attr.protocol != PTHREAD_PRIO_PROTECT)
+               return EINVAL;
+       
+       if (prioceiling < __cobalt_std_fifo_minpri ||
+           prioceiling > __cobalt_std_fifo_maxpri)
+               return EINVAL;
+
+       ret = __COBALT(pthread_mutex_lock(mutex));
+       if (ret)
+               return ret;
+
+       state = mutex_get_state(_mutex);
+       if (old_ceiling)
+               *old_ceiling = state->ceiling;
+
+       state->ceiling = prioceiling;
+
+       return __COBALT(pthread_mutex_unlock(mutex));
+}
+
+/**
+ * Get a mutex's priority ceiling.
+ *
+ * This routine retrieves the priority ceiling value of the specified
+ * mutex.
+ *
+ * @param mutex the target mutex.
+ *
+ * @param prioceiling on success, the current ceiling value is copied
+ * to this address.
+ *
+ * @return 0 on success;
+ * @return an error number if:
+ * - EINVAL, @a mutex is invalid;
+ * - EINVAL, @a mutex is not of type PTHREAD_PRIO_PROTECT;
+ *
+ * @see
+ * <a 
href="http://pubs.opengroup.org/onlinepubs/009695399/functions/pthread_mutex_getprioceiling.html";>
+ * Specification.</a>
+ *
+ * @apitags{thread-unrestricted}
+ */
+COBALT_IMPL(int, pthread_mutex_getprioceiling,
+           (pthread_mutex_t *__restrict mutex, int *__restrict prioceiling))
+{
+       struct cobalt_mutex_shadow *_mutex =
+               &((union cobalt_mutex_union *)mutex)->shadow_mutex;
+       struct cobalt_mutex_state *state;
+
+       if (_mutex->magic != COBALT_MUTEX_MAGIC ||
+           _mutex->attr.protocol != PTHREAD_PRIO_PROTECT)
+               return EINVAL;
+       
+       state = mutex_get_state(_mutex);
+       *prioceiling = state->ceiling;
+
+       return 0;
 }
 
 /**
@@ -692,9 +871,9 @@ int pthread_mutexattr_settype(pthread_mutexattr_t * attr, 
int type);
  * This service stores, at the address @a proto, the value of the @a protocol
  * attribute in the mutex attributes object @a attr.
  *
- * The @a protcol attribute may only be one of @a PTHREAD_PRIO_NONE or @a
- * PTHREAD_PRIO_INHERIT. See pthread_mutexattr_setprotocol() for the meaning of
- * these two constants.
+ * The @a protcol attribute may be one of @a PTHREAD_PRIO_NONE, @a
+ * PTHREAD_PRIO_INHERIT or @a PTHREAD_PRIO_PROTECT. See
+ * pthread_mutexattr_setprotocol() for the meaning of these constants.
  *
  * @param attr an initialized mutex attributes object;
  *
@@ -727,8 +906,8 @@ int pthread_mutexattr_getprotocol(const pthread_mutexattr_t 
* attr, int *proto);
  *   @a attr will not follow any priority protocol;
  * - PTHREAD_PRIO_INHERIT, meaning that a mutex created with the attributes
  *   object @a attr, will follow the priority inheritance protocol.
- *
- * The value PTHREAD_PRIO_PROTECT (priority ceiling protocol) is unsupported.
+ * - PTHREAD_PRIO_PROTECT, meaning that a mutex created with the attributes
+ *   object @a attr, will follow the priority protect protocol.
  *
  * @return 0 on success,
  * @return an error number if:
diff --git a/lib/cobalt/sched.c b/lib/cobalt/sched.c
index 7376110..b0292b5 100644
--- a/lib/cobalt/sched.c
+++ b/lib/cobalt/sched.c
@@ -80,7 +80,11 @@ COBALT_IMPL(int, sched_yield, (void))
  * <a 
href="http://www.opengroup.org/onlinepubs/000095399/functions/sched_get_priority_min.html";>
  * Specification.</a>
  *
- * @apitags{thread-unrestricted}
+ * @apitags{thread-unrestricted, switch-secondary}
+ *
+ * @note Fetching the minimum priority level of SCHED_FIFO, SCHED_RR
+ * or any Xenomai-specific policy never leads to a mode switch. Any
+ * other value of @a policy may switch the caller to secondary mode.
  */
 COBALT_IMPL(int, sched_get_priority_min, (int policy))
 {
@@ -88,8 +92,9 @@ COBALT_IMPL(int, sched_get_priority_min, (int policy))
 
        switch (policy) {
        case SCHED_FIFO:
+               return __cobalt_std_fifo_minpri;
        case SCHED_RR:
-               break;
+               return __cobalt_std_rr_minpri;
        default:
                ret = XENOMAI_SYSCALL1(sc_cobalt_sched_minprio, policy);
                if (ret >= 0)
@@ -152,7 +157,11 @@ int sched_get_priority_min_ex(int policy)
  * <a 
href="http://www.opengroup.org/onlinepubs/000095399/functions/sched_get_priority_max.html";>
  * Specification.</a>
  *
- * @apitags{thread-unrestricted}
+ * @apitags{thread-unrestricted, switch-secondary}
+ *
+ * @note Fetching the maximum priority level of SCHED_FIFO, SCHED_RR
+ * or any Xenomai-specific policy never leads to a mode switch. Any
+ * other value of @a policy may switch the caller to secondary mode.
  */
 COBALT_IMPL(int, sched_get_priority_max, (int policy))
 {
@@ -160,8 +169,9 @@ COBALT_IMPL(int, sched_get_priority_max, (int policy))
 
        switch (policy) {
        case SCHED_FIFO:
+               return __cobalt_std_fifo_maxpri;
        case SCHED_RR:
-               break;
+               return __cobalt_std_rr_maxpri;
        default:
                ret = XENOMAI_SYSCALL1(sc_cobalt_sched_maxprio, policy);
                if (ret >= 0)
@@ -611,3 +621,18 @@ ssize_t sched_getconfig_np(int cpu, int policy,
 }
 
 /** @} */
+
+int __cobalt_std_fifo_minpri,
+    __cobalt_std_fifo_maxpri;
+
+int __cobalt_std_rr_minpri,
+    __cobalt_std_rr_maxpri;
+
+void cobalt_sched_init(void)
+{
+       /* Fill in the standard priority limit cache. */
+       __cobalt_std_fifo_minpri = __STD(sched_get_priority_min(SCHED_FIFO));
+       __cobalt_std_fifo_maxpri = __STD(sched_get_priority_max(SCHED_FIFO));
+       __cobalt_std_rr_minpri = __STD(sched_get_priority_min(SCHED_RR));
+       __cobalt_std_rr_maxpri = __STD(sched_get_priority_max(SCHED_RR));
+}
diff --git a/lib/cobalt/thread.c b/lib/cobalt/thread.c
index aab2c81..e6b3eae 100644
--- a/lib/cobalt/thread.c
+++ b/lib/cobalt/thread.c
@@ -50,7 +50,7 @@ int cobalt_xlate_schedparam(int policy,
                            const struct sched_param_ex *param_ex,
                            struct sched_param *param)
 {
-       int std_policy, priority, std_maxpri;
+       int std_policy, priority;
 
        /*
         * Translates Cobalt scheduling parameters to native ones,
@@ -77,9 +77,8 @@ int cobalt_xlate_schedparam(int policy,
                 * "weak" (negative) priorities - which are only
                 * meaningful for the Cobalt core - to regular values.
                 */
-               std_maxpri = __STD(sched_get_priority_max(SCHED_FIFO));
-               if (priority > std_maxpri)
-                       priority = std_maxpri;
+               if (priority > __cobalt_std_fifo_maxpri)
+                       priority = __cobalt_std_fifo_maxpri;
        }
 
        if (priority < 0)


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

Reply via email to