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

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 +++++
 lib/cobalt/mutex.c         |  172 ++++++++++++++++++++++++++++++--------------
 3 files changed, 141 insertions(+), 52 deletions(-)

diff --git a/configure.ac b/configure.ac
index 20fa0ec..7aaedc2 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/lib/cobalt/mutex.c b/lib/cobalt/mutex.c
index 9d8a914..d0e61f2 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,15 @@ 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;
+               kmattr.ceiling = tmp;
+       }
+
        err = -XENOMAI_SYSCALL2(sc_cobalt_mutex_init, _mutex, &kmattr);
        if (err)
                return err;
@@ -270,7 +275,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 +291,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 +326,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 +336,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;
 }
 
 /**
@@ -366,7 +390,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 +402,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 +438,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 +447,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;
 }
 
 /**
@@ -451,7 +494,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,49 +504,66 @@ 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;
 }
 
 /**
@@ -535,14 +596,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 +623,28 @@ 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;
 }
 
 /**
@@ -692,9 +760,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 +795,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:


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

Reply via email to