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