/* * Copyright (C) 2005 Philippe Gerum . * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include #include #include #include "current.h" #include "internal.h" /** * @ingroup cobalt_api * @defgroup cobalt_api_mutex Mutual exclusion * * Cobalt/POSIX mutual exclusion services * * A mutex is a MUTual EXclusion device, and is useful for protecting * shared data structures from concurrent modifications, and implementing * critical sections and monitors. * * A mutex has two possible states: unlocked (not owned by any thread), and * locked (owned by one thread). A mutex can never be owned by two different * threads simultaneously. A thread attempting to lock a mutex that is already * locked by another thread is suspended until the owning thread unlocks the * mutex first. * * Before it can be used, a mutex has to be initialized with * pthread_mutex_init(). An attribute object, which reference may be passed to * this service, allows to select the features of the created mutex, namely its * @a type (see pthread_mutexattr_settype()), the priority @a protocol it * uses (see pthread_mutexattr_setprotocol()) and whether it may be shared * between several processes (see pthread_mutexattr_setpshared()). * * By default, Cobalt mutexes are of the normal type, use no * priority protocol and may not be shared between several processes. * * Note that pthread_mutex_init() should be used to initialize a mutex, using * the static initializer @a PTHREAD_MUTEX_INITIALIZER will delay the * initialization to the first method called on the mutex and will * most likely introduce switches to secondary mode. * The documentation (and specifically api-tags) of the mutex services assumes * a mutex was explicitly initialised with pthread_mutex_init(). * *@{ */ static pthread_mutexattr_t cobalt_default_mutexattr; static union cobalt_mutex_union cobalt_autoinit_mutex_union; static pthread_mutex_t *const cobalt_autoinit_mutex = &cobalt_autoinit_mutex_union.native_mutex; void cobalt_mutex_init(void) { struct cobalt_mutex_shadow *_mutex = &cobalt_autoinit_mutex_union.shadow_mutex; pthread_mutexattr_t rt_init_mattr; int err __attribute__((unused)); pthread_mutexattr_init(&cobalt_default_mutexattr); pthread_mutexattr_init(&rt_init_mattr); pthread_mutexattr_setprotocol(&rt_init_mattr, PTHREAD_PRIO_INHERIT); _mutex->magic = ~COBALT_MUTEX_MAGIC; err = __COBALT(pthread_mutex_init(cobalt_autoinit_mutex, &rt_init_mattr)); assert(err == 0); pthread_mutexattr_destroy(&rt_init_mattr); } /** * Initialize a mutex. * * This services initializes the mutex @a mx, using the mutex attributes object * @a attr. If @a attr is @a NULL, default attributes are used (see * pthread_mutexattr_init()). * * @param mutex the mutex to be initialized; * * @param attr the mutex attributes object. * * @return 0 on success, * @return an error number if: * - EINVAL, the mutex attributes object @a attr is invalid or uninitialized; * - EBUSY, the mutex @a mx was already initialized; * - ENOMEM, insufficient memory available from the system heap to initialize the * mutex, increase CONFIG_XENO_OPT_SYS_HEAPSZ. * - EAGAIN, insufficient memory available to initialize the * 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 * * Specification. * * @apitags{thread-unrestricted} */ COBALT_IMPL(int, pthread_mutex_init, (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr)) { struct cobalt_mutex_shadow *_mutex = &((union cobalt_mutex_union *)mutex)->shadow_mutex; struct cobalt_mutex_state *state; struct cobalt_mutexattr kmattr; int err, tmp; if (_mutex->magic == COBALT_MUTEX_MAGIC) { err = -XENOMAI_SYSCALL1(sc_cobalt_mutex_check_init, _mutex); if (err) return err; } if (attr == NULL) attr = &cobalt_default_mutexattr; err = pthread_mutexattr_getpshared(attr, &tmp); if (err) return err; kmattr.pshared = tmp; err = pthread_mutexattr_gettype(attr, &tmp); if (err) return err; kmattr.type = tmp; err = pthread_mutexattr_getprotocol(attr, &tmp); if (err) 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; state = mutex_get_state(_mutex); cobalt_commit_memory(state); return err; } /** * Test if a mutex structure contains a valid autoinitializer. * * @return the mutex type on success, * @return -1 if not in supported autoinitializer state */ static int __attribute__((cold)) cobalt_mutex_autoinit_type(const pthread_mutex_t *mutex) { static const pthread_mutex_t mutex_initializers[] = { #if HAVE_DECL_PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, #endif #if HAVE_DECL_PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, #endif PTHREAD_MUTEX_INITIALIZER }; static const int mutex_types[] = { #if HAVE_DECL_PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_MUTEX_ERRORCHECK_NP, #endif #if HAVE_DECL_PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_MUTEX_RECURSIVE_NP, #endif PTHREAD_MUTEX_DEFAULT }; int i; for (i = sizeof(mutex_types) / sizeof(mutex_types[0]); i > 0; --i) { if (memcmp(mutex, &mutex_initializers[i - 1], sizeof(mutex_initializers[0])) == 0) return mutex_types[i - 1]; } return -1; } static int __attribute__((cold)) cobalt_mutex_doautoinit(union cobalt_mutex_union *umutex) { struct cobalt_mutex_shadow *_mutex = &umutex->shadow_mutex; int err __attribute__((unused)); pthread_mutexattr_t mattr; int ret = 0, type; type = cobalt_mutex_autoinit_type(&umutex->native_mutex); if (type < 0) return EINVAL; pthread_mutexattr_init(&mattr); pthread_mutexattr_settype(&mattr, type); err = __COBALT(pthread_mutex_lock(cobalt_autoinit_mutex)); if (err) { ret = err; goto out; } if (_mutex->magic != COBALT_MUTEX_MAGIC) ret = __COBALT(pthread_mutex_init(&umutex->native_mutex, &mattr)); err = __COBALT(pthread_mutex_unlock(cobalt_autoinit_mutex)); if (err) { if (ret == 0) ret = err; } out: pthread_mutexattr_destroy(&mattr); return ret; } static inline int cobalt_mutex_autoinit(union cobalt_mutex_union *umutex) { if (umutex->shadow_mutex.magic != COBALT_MUTEX_MAGIC) return cobalt_mutex_doautoinit(umutex); return 0; } /** * Destroy a mutex. * * This service destroys the mutex @a mx, if it is unlocked and not referenced * by any condition variable. The mutex becomes invalid for all mutex services * (they all return the EINVAL error) except pthread_mutex_init(). * * @param mutex the mutex to be destroyed. * * @return 0 on success, * @return an error number if: * - EINVAL, the mutex @a mx is invalid; * - EPERM, the mutex is not process-shared and does not belong to the current * process; * - EBUSY, the mutex is locked, or used by a condition variable. * * @see * * Specification. * * @apitags{thread-unrestricted} */ COBALT_IMPL(int, pthread_mutex_destroy, (pthread_mutex_t *mutex)) { struct cobalt_mutex_shadow *_mutex = &((union cobalt_mutex_union *)mutex)->shadow_mutex; int err; if (_mutex->magic != COBALT_MUTEX_MAGIC) return (cobalt_mutex_autoinit_type(mutex) < 0) ? EINVAL : 0; err = XENOMAI_SYSCALL1(sc_cobalt_mutex_destroy, _mutex); return -err; } /** * Lock a mutex. * * This service attempts to lock the mutex @a mx. If the mutex is free, it * becomes locked. If it was locked by another thread than the current one, the * current thread is suspended until the mutex is unlocked. If it was already * locked by the current mutex, the behaviour of this service depends on the * mutex type : * - for mutexes of the @a PTHREAD_MUTEX_NORMAL type, this service deadlocks; * - for mutexes of the @a PTHREAD_MUTEX_ERRORCHECK type, this service returns * the EDEADLK error number; * - for mutexes of the @a PTHREAD_MUTEX_RECURSIVE type, this service increments * the lock recursion count and returns 0. * * @param mutex the mutex to be locked. * * @return 0 on success * @return an error number if: * - 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; * - EDEADLK, the mutex is of the @a PTHREAD_MUTEX_ERRORCHECK type and was * already locked by the current thread; * - EAGAIN, the mutex is of the @a PTHREAD_MUTEX_RECURSIVE type and the maximum * number of recursive locks has been exceeded. * * @see * * Specification. * * @apitags{xthread-only, switch-primary} */ COBALT_IMPL(int, pthread_mutex_lock, (pthread_mutex_t *mutex)) { struct cobalt_mutex_shadow *_mutex = &((union cobalt_mutex_union *)mutex)->shadow_mutex; struct xnthread_user_window *u_window; int status, ret, lazy_protect = 0; xnhandle_t cur; cur = cobalt_get_current(); if (cur == XN_NO_HANDLE) return EPERM; ret = cobalt_mutex_autoinit((union cobalt_mutex_union *)mutex); if (ret) return ret; /* * We track resource ownership for auto-relax of non real-time * shadows and some debug features, so we must always obtain * them via a syscall. */ 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 (lazy_protect) u_window->pp_pending = XN_NO_HANDLE; switch(_mutex->attr.type) { case PTHREAD_MUTEX_NORMAL: break; case PTHREAD_MUTEX_ERRORCHECK: return EDEADLK; case PTHREAD_MUTEX_RECURSIVE: if (_mutex->lockcnt == UINT32_MAX) return EAGAIN; ++_mutex->lockcnt; return 0; } } do ret = XENOMAI_SYSCALL1(sc_cobalt_mutex_lock, _mutex); while (ret == -EINTR); if (ret == 0) _mutex->lockcnt = 1; return -ret; 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; } /** * Attempt, during a bounded time, to lock a mutex. * * This service is equivalent to pthread_mutex_lock(), except that if the mutex * @a mx is locked by another thread than the current one, this service only * suspends the current thread until the timeout specified by @a to expires. * * @param mutex the mutex to be locked; * * @param to the timeout, expressed as an absolute value of the CLOCK_REALTIME * clock. * * @return 0 on success; * @return an error number if: * - 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; * - ETIMEDOUT, the mutex could not be locked and the specified timeout * expired; * - EDEADLK, the mutex is of the @a PTHREAD_MUTEX_ERRORCHECK type and the mutex * was already locked by the current thread; * - EAGAIN, the mutex is of the @a PTHREAD_MUTEX_RECURSIVE type and the maximum * number of recursive locks has been exceeded. * * @see * * Specification. * * @apitags{xthread-only, switch-primary} */ COBALT_IMPL(int, pthread_mutex_timedlock, (pthread_mutex_t *mutex, const struct timespec *to)) { struct cobalt_mutex_shadow *_mutex = &((union cobalt_mutex_union *)mutex)->shadow_mutex; struct xnthread_user_window *u_window; int status, ret, lazy_protect = 0; xnhandle_t cur; cur = cobalt_get_current(); if (cur == XN_NO_HANDLE) return EPERM; ret = cobalt_mutex_autoinit((union cobalt_mutex_union *)mutex); if (ret) return ret; /* See __cobalt_pthread_mutex_lock() */ 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 (lazy_protect) u_window->pp_pending = XN_NO_HANDLE; switch(_mutex->attr.type) { case PTHREAD_MUTEX_NORMAL: break; case PTHREAD_MUTEX_ERRORCHECK: return EDEADLK; case PTHREAD_MUTEX_RECURSIVE: if (_mutex->lockcnt == UINT32_MAX) return EAGAIN; ++_mutex->lockcnt; return 0; } } do { #ifdef __USE_TIME_BITS64 ret = XENOMAI_SYSCALL2(sc_cobalt_mutex_timedlock64, _mutex, to); #else ret = XENOMAI_SYSCALL2(sc_cobalt_mutex_timedlock, _mutex, to); #endif } while (ret == -EINTR); if (ret == 0) _mutex->lockcnt = 1; return -ret; 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; } /** * Attempt to lock a mutex. * * This service is equivalent to pthread_mutex_lock(), except that if the mutex * @a mx is locked by another thread than the current one, this service returns * immediately. * * @param mutex the mutex to be locked. * * @return 0 on success; * @return an error number if: * - 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; * - EBUSY, the mutex was locked by another thread than the current one; * - EAGAIN, the mutex is recursive, and the maximum number of recursive locks * has been exceeded. * * @see * * Specification. * * @apitags{xthread-only, switch-primary} */ COBALT_IMPL(int, pthread_mutex_trylock, (pthread_mutex_t *mutex)) { struct cobalt_mutex_shadow *_mutex = &((union cobalt_mutex_union *)mutex)->shadow_mutex; struct xnthread_user_window *u_window; int status, ret, lazy_protect = 0; xnhandle_t cur; cur = cobalt_get_current(); if (cur == XN_NO_HANDLE) return EPERM; ret = cobalt_mutex_autoinit((union cobalt_mutex_union *)mutex); if (ret) return ret; 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 (lazy_protect) u_window->pp_pending = XN_NO_HANDLE; if (_mutex->attr.type == PTHREAD_MUTEX_RECURSIVE) { if (_mutex->lockcnt == UINT32_MAX) return EAGAIN; ++_mutex->lockcnt; return 0; } return EBUSY; } do { ret = XENOMAI_SYSCALL1(sc_cobalt_mutex_trylock, _mutex); } while (ret == -EINTR); if (ret == 0) _mutex->lockcnt = 1; return -ret; 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 @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 * mutex @a type attribute. * * @param mutex the mutex to be released. * * @return 0 on success; * @return an error number if: * - 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 * * Specification. * * @apitags{xthread-only, switch-primary} */ 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; err = cobalt_mutex_autoinit((union cobalt_mutex_union *)mutex); if (err) return err; cur = cobalt_get_current(); if (cur == XN_NO_HANDLE) return EPERM; state = mutex_get_state(_mutex); if (xnsynch_fast_owner_check(&state->owner, cur) != 0) return EPERM; if (_mutex->lockcnt > 1) { --_mutex->lockcnt; return 0; } if ((state->flags & COBALT_MUTEX_COND_SIGNAL)) goto do_syscall; if (cobalt_get_current_mode() & (XNWEAK|XNDEBUG)) goto do_syscall; 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; 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 * * Specification. * * @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 * * Specification. * * @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; } /** * Initialize a mutex attributes object. * * This services initializes the mutex attributes object @a attr with default * values for all attributes. Default value are : * - for the @a type attribute, @a PTHREAD_MUTEX_NORMAL; * - for the @a protocol attribute, @a PTHREAD_PRIO_NONE; * - for the @a pshared attribute, @a PTHREAD_PROCESS_PRIVATE. * * If this service is called specifying a mutex attributes object that was * already initialized, the attributes object is reinitialized. * * @param attr the mutex attributes object to be initialized. * * @return 0 on success; * @return an error number if: * - ENOMEM, the mutex attributes object pointer @a attr is @a NULL. * * @see * * Specification. * * @apitags{thread-unrestricted} */ int pthread_mutexattr_init(pthread_mutexattr_t * attr); /** * Destroy a mutex attributes object. * * This service destroys the mutex attributes object @a attr. The object becomes * invalid for all mutex services (they all return EINVAL) except * pthread_mutexattr_init(). * * @param attr the initialized mutex attributes object to be destroyed. * * @return 0 on success; * @return an error number if: * - EINVAL, the mutex attributes object @a attr is invalid. * * @see * * Specification. * * @apitags{thread-unrestricted} */ int pthread_mutexattr_destroy(pthread_mutexattr_t * attr); /** * Get the mutex type attribute from a mutex attributes object. * * This service stores, at the address @a type, the value of the @a type * attribute in the mutex attributes object @a attr. * * See pthread_mutex_lock() and pthread_mutex_unlock() for a * description of the values of the @a type attribute and their effect * on a mutex. * * @param attr an initialized mutex attributes object, * * @param type address where the @a type attribute value will be stored on * success. * * @return 0 on sucess, * @return an error number if: * - EINVAL, the @a type address is invalid; * - EINVAL, the mutex attributes object @a attr is invalid. * * @see * * Specification. * * @apitags{thread-unrestricted} */ int pthread_mutexattr_gettype(const pthread_mutexattr_t * attr, int *type); /** * Set the mutex type attribute of a mutex attributes object. * * This service set the @a type attribute of the mutex attributes object * @a attr. * * See pthread_mutex_lock() and pthread_mutex_unlock() for a * description of the values of the @a type attribute and their effect * on a mutex. * * The @a PTHREAD_MUTEX_DEFAULT default @a type is the same as @a * PTHREAD_MUTEX_NORMAL. Note that using a recursive Cobalt mutex with * a Cobalt condition variable is safe (see pthread_cond_wait() * documentation). * * @param attr an initialized mutex attributes object, * * @param type value of the @a type attribute. * * @return 0 on success, * @return an error number if: * - EINVAL, the mutex attributes object @a attr is invalid; * - EINVAL, the value of @a type is invalid for the @a type attribute. * * @see * * Specification. * * @apitags{thread-unrestricted} */ int pthread_mutexattr_settype(pthread_mutexattr_t * attr, int type); /** * Get the protocol attribute from a mutex attributes object. * * 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 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; * * @param proto address where the value of the @a protocol attribute will be * stored on success. * * @return 0 on success, * @return an error number if: * - EINVAL, the @a proto address is invalid; * - EINVAL, the mutex attributes object @a attr is invalid. * * @see * * Specification. * * @apitags{thread-unrestricted} */ int pthread_mutexattr_getprotocol(const pthread_mutexattr_t * attr, int *proto); /** * Set the protocol attribute of a mutex attributes object. * * This service set the @a type attribute of the mutex attributes object * @a attr. * * @param attr an initialized mutex attributes object, * * @param proto value of the @a protocol attribute, may be one of: * - PTHREAD_PRIO_NONE, meaning that a mutex created with the attributes object * @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. * - 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: * - EINVAL, the mutex attributes object @a attr is invalid; * - ENOTSUP, the value of @a proto is unsupported; * - EINVAL, the value of @a proto is invalid. * * @see * * Specification. * * @apitags{thread-unrestricted} */ int pthread_mutexattr_setprotocol(pthread_mutexattr_t * attr, int proto); /** * Get the process-shared attribute of a mutex attributes object. * * This service stores, at the address @a pshared, the value of the @a pshared * attribute in the mutex attributes object @a attr. * * The @a pashared attribute may only be one of @a PTHREAD_PROCESS_PRIVATE or * @a PTHREAD_PROCESS_SHARED. See pthread_mutexattr_setpshared() for the meaning * of these two constants. * * @param attr an initialized mutex attributes object; * * @param pshared address where the value of the @a pshared attribute will be * stored on success. * * @return 0 on success; * @return an error number if: * - EINVAL, the @a pshared address is invalid; * - EINVAL, the mutex attributes object @a attr is invalid. * * @see * * Specification. * * @apitags{thread-unrestricted} */ int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared); /** * Set the process-shared attribute of a mutex attributes object. * * This service set the @a pshared attribute of the mutex attributes object @a * attr. * * @param attr an initialized mutex attributes object. * * @param pshared value of the @a pshared attribute, may be one of: * - PTHREAD_PROCESS_PRIVATE, meaning that a mutex created with the attributes * object @a attr will only be accessible by threads within the same process * as the thread that initialized the mutex; * - PTHREAD_PROCESS_SHARED, meaning that a mutex created with the attributes * object @a attr will be accessible by any thread that has access to the * memory where the mutex is allocated. * * @return 0 on success, * @return an error status if: * - EINVAL, the mutex attributes object @a attr is invalid; * - EINVAL, the value of @a pshared is invalid. * * @see * * Specification. * * @apitags{thread-unrestricted} */ int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared); /** @} */