diff --git a/include/posix/pthread.h b/include/posix/pthread.h index 2d5e47e1f8b..947d58508dc 100644 --- a/include/posix/pthread.h +++ b/include/posix/pthread.h @@ -13,6 +13,8 @@ #include #include "sys/types.h" #include "posix_sched.h" +#include +#include enum pthread_state { /* The thread is running and joinable. */ @@ -34,13 +36,11 @@ struct posix_thread { /* Pthread cancellation */ int cancel_state; int cancel_pending; - struct k_sem cancel_lock_sem; pthread_mutex_t cancel_lock; /* Pthread State */ enum pthread_state state; pthread_mutex_t state_lock; - struct k_sem state_lock_sem; pthread_cond_t state_cond; }; @@ -152,61 +152,73 @@ static inline int pthread_condattr_destroy(pthread_condattr_t *att) * * @param name Symbol name of the mutex */ -#define PTHREAD_MUTEX_DEFINE(name) \ - K_SEM_DEFINE(name##_psem, 1, 1); \ - struct pthread_mutex name = { \ - .sem = &name##_psem, \ +#define PTHREAD_MUTEX_DEFINE(name) \ + struct pthread_mutex name \ + __in_section(_k_mutex, static, name) = \ + { \ + .lock_count = 0, \ + .wait_q = {SYS_DLIST_STATIC_INIT((sys_dlist_t *)&name.wait_q)}, \ + .owner = NULL, \ } -/** - * @brief POSIX threading compatibility API +/* + * Mutex attributes - type + * + * PTHREAD_MUTEX_NORMAL: Owner of mutex cannot relock it. Attempting + * to relock will cause deadlock. + * PTHREAD_MUTEX_RECURSIVE: Owner can relock the mutex. + * PTHREAD_MUTEX_ERRORCHECK: If owner attempts to relock the mutex, an + * error is returned. * - * See IEEE 1003.1 */ -static inline int pthread_mutex_init(pthread_mutex_t *m, - const pthread_mutexattr_t *att) -{ - ARG_UNUSED(att); +#define PTHREAD_MUTEX_NORMAL 0 +#define PTHREAD_MUTEX_RECURSIVE 1 +#define PTHREAD_MUTEX_ERRORCHECK 2 +#define PTHREAD_MUTEX_DEFAULT PTHREAD_MUTEX_NORMAL - k_sem_init(m->sem, 1, 1); - - return 0; -} +/* + * Mutex attributes - protocol + * + * PTHREAD_PRIO_NONE: Ownership of mutex does not affect priority. + * PTHREAD_PRIO_INHERIT: Owner's priority is boosted to the priority of + * highest priority thread blocked on the mutex. + * PTHREAD_PRIO_PROTECT: Mutex has a priority ceiling. The owner's + * priority is boosted to the highest priority ceiling of all mutexes + * owned (regardless of whether or not other threads are blocked on + * any of these mutexes). + * FIXME: Only PRIO_NONE is supported. Implement other protocols. + */ +#define PTHREAD_PRIO_NONE 0 /** * @brief POSIX threading compatibility API * * See IEEE 1003.1 */ -static inline int pthread_mutex_destroy(pthread_mutex_t *m) -{ - ARG_UNUSED(m); - - return 0; -} +int pthread_mutex_destroy(pthread_mutex_t *m); /** * @brief POSIX threading compatibility API * * See IEEE 1003.1 */ -static inline int pthread_mutex_lock(pthread_mutex_t *m) -{ - return k_sem_take(m->sem, K_FOREVER); -} +int pthread_mutex_lock(pthread_mutex_t *m); /** * @brief POSIX threading compatibility API * * See IEEE 1003.1 */ -static inline int pthread_mutex_timedlock(pthread_mutex_t *m, - const struct timespec *to) -{ - int ret = k_sem_take(m->sem, _ts_to_ms(to)); +int pthread_mutex_unlock(pthread_mutex_t *m); - return ret == 0 ? ret : ETIMEDOUT; -} +/** + * @brief POSIX threading compatibility API + * + * See IEEE 1003.1 + */ + +int pthread_mutex_timedlock(pthread_mutex_t *m, + const struct timespec *to); /** * @brief POSIX threading compatibility API @@ -220,11 +232,37 @@ int pthread_mutex_trylock(pthread_mutex_t *m); * * See IEEE 1003.1 */ -static inline int pthread_mutex_unlock(pthread_mutex_t *m) -{ - k_sem_give(m->sem); - return 0; -} +int pthread_mutex_init(pthread_mutex_t *m, + const pthread_mutexattr_t *att); + +/** + * @brief POSIX threading compatibility API + * + * See IEEE 1003.1 + */ +int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol); + +/** + * @brief POSIX threading compatibility API + * + * See IEEE 1003.1 + */ +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type); + +/** + * @brief POSIX threading compatibility API + * + * See IEEE 1003.1 + */ +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, + int *protocol); + +/** + * @brief POSIX threading compatibility API + * + * See IEEE 1003.1 + */ +int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type); /** * @brief POSIX threading compatibility API @@ -372,15 +410,11 @@ int pthread_mutex_consistent(pthread_mutex_t *); int pthread_mutex_getprioceiling(const pthread_mutex_t * int *); int pthread_mutex_setprioceiling(pthread_mutex_t *, int int *); int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *, int *); -int pthread_mutexattr_getprotocol(const pthread_mutexattr_t * int *); int pthread_mutexattr_getpshared(const pthread_mutexattr_t * int *); int pthread_mutexattr_getrobust(const pthread_mutexattr_t * int *); -int pthread_mutexattr_gettype(const pthread_mutexattr_t * int *); int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *, int); -int pthread_mutexattr_setprotocol(pthread_mutexattr_t *, int); int pthread_mutexattr_setpshared(pthread_mutexattr_t *, int); int pthread_mutexattr_setrobust(pthread_mutexattr_t *, int); -int pthread_mutexattr_settype(pthread_mutexattr_t *, int); int pthread_barrierattr_getpshared(const pthread_barrierattr_t *, int *); int pthread_barrierattr_setpshared(pthread_barrierattr_t *, int); */ diff --git a/include/posix/sys/types.h b/include/posix/sys/types.h index dca7df39304..912ac54a520 100644 --- a/include/posix/sys/types.h +++ b/include/posix/sys/types.h @@ -37,10 +37,14 @@ typedef struct k_sem sem_t; /* Mutex */ typedef struct pthread_mutex { - struct k_sem *sem; + pthread_t owner; + u16_t lock_count; + int type; + _wait_q_t wait_q; } pthread_mutex_t; typedef struct pthread_mutexattr { + int type; } pthread_mutexattr_t; /* Condition variables */ diff --git a/lib/posix/pthread_cond.c b/lib/posix/pthread_cond.c index 0866e110409..5c433c32732 100644 --- a/lib/posix/pthread_cond.c +++ b/lib/posix/pthread_cond.c @@ -11,12 +11,13 @@ static int cond_wait(pthread_cond_t *cv, pthread_mutex_t *mut, int timeout) { - __ASSERT(mut->sem->count == 0, ""); + __ASSERT(mut->lock_count == 1, ""); int ret, key = irq_lock(); - mut->sem->count = 1; - _ready_one_thread(&mut->sem->wait_q); + mut->lock_count = 0; + mut->owner = NULL; + _ready_one_thread(&mut->wait_q); ret = _pend_current_thread(key, &cv->wait_q, timeout); /* FIXME: this extra lock (and the potential context switch it diff --git a/lib/posix/pthread_mutex.c b/lib/posix/pthread_mutex.c index bd8e429771c..4ae08576f81 100644 --- a/lib/posix/pthread_mutex.c +++ b/lib/posix/pthread_mutex.c @@ -9,16 +9,196 @@ #include #include -int pthread_mutex_trylock(pthread_mutex_t *m) -{ - int key = irq_lock(), ret = EBUSY; +#define MUTEX_MAX_REC_LOCK 32767 - if (m->sem->count) { - m->sem->count = 0; - ret = 0; +/* + * Default mutex attrs. + */ +static const pthread_mutexattr_t def_attr = { + .type = PTHREAD_MUTEX_DEFAULT, +}; + +static int acquire_mutex(pthread_mutex_t *m, int timeout) +{ + int rc = 0, key = irq_lock(); + + if (m->lock_count == 0 && m->owner == NULL) { + m->lock_count++; + m->owner = pthread_self(); + + irq_unlock(key); + return 0; + } else if (m->owner == pthread_self()) { + if (m->type == PTHREAD_MUTEX_RECURSIVE && + m->lock_count < MUTEX_MAX_REC_LOCK) { + m->lock_count++; + rc = 0; + } else if (m->type == PTHREAD_MUTEX_ERRORCHECK) { + rc = EDEADLK; + } else { + rc = EINVAL; + } + + irq_unlock(key); + return rc; } - irq_unlock(key); + if (timeout == K_NO_WAIT) { + irq_unlock(key); + return EINVAL; + } - return ret; + rc = _pend_current_thread(key, &m->wait_q, timeout); + if (rc != 0) { + rc = ETIMEDOUT; + } + + return rc; +} + +/** + * @brief Lock POSIX mutex with non-blocking call. + * + * See IEEE 1003.1 + */ +int pthread_mutex_trylock(pthread_mutex_t *m) +{ + return acquire_mutex(m, K_NO_WAIT); +} + +/** + * @brief Lock POSIX mutex with timeout. + * + * + * See IEEE 1003.1 + */ +int pthread_mutex_timedlock(pthread_mutex_t *m, + const struct timespec *to) +{ + return acquire_mutex(m, _ts_to_ms(to)); +} + +/** + * @brief Intialize POSIX mutex. + * + * See IEEE 1003.1 + */ +int pthread_mutex_init(pthread_mutex_t *m, + const pthread_mutexattr_t *attr) +{ + const pthread_mutexattr_t *mattr; + + m->owner = NULL; + m->lock_count = 0; + + mattr = (attr == NULL) ? &def_attr : attr; + + m->type = mattr->type; + + sys_dlist_init((sys_dlist_t *)&m->wait_q); + + return 0; +} + + +/** + * @brief Lock POSIX mutex with blocking call. + * + * See IEEE 1003.1 + */ +int pthread_mutex_lock(pthread_mutex_t *m) +{ + return acquire_mutex(m, K_FOREVER); +} + +/** + * @brief Unlock POSIX mutex. + * + * See IEEE 1003.1 + */ +int pthread_mutex_unlock(pthread_mutex_t *m) +{ + unsigned int key = irq_lock(); + + k_tid_t thread; + + if (m->owner != pthread_self()) { + irq_unlock(key); + return EPERM; + } + + if (m->lock_count == 0) { + irq_unlock(key); + return EINVAL; + } + + m->lock_count--; + + if (m->lock_count == 0) { + thread = _unpend_first_thread(&m->wait_q); + if (thread) { + m->owner = (pthread_t)thread; + m->lock_count++; + _ready_thread(thread); + _set_thread_return_value(thread, 0); + return _reschedule(key); + } + m->owner = NULL; + + } + irq_unlock(key); + return 0; +} + +/** + * @brief Destroy POSIX mutex. + * + * See IEEE 1003.1 + */ +int pthread_mutex_destroy(pthread_mutex_t *m) +{ + ARG_UNUSED(m); + return 0; +} + +/** + * @brief Read protocol attribute for mutex. + * + * See IEEE 1003.1 + */ +int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, + int *protocol) +{ + *protocol = PTHREAD_PRIO_NONE; + return 0; +} + +/** + * @brief Read type attribute for mutex. + * + * See IEEE 1003.1 + */ +int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type) +{ + *type = attr->type; + return 0; +} + +/** + * @brief Set type attribute for mutex. + * + * See IEEE 1003.1 + */ +int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) +{ + int retc = EINVAL; + + if ((type == PTHREAD_MUTEX_NORMAL) || + (type == PTHREAD_MUTEX_RECURSIVE) || + (type == PTHREAD_MUTEX_ERRORCHECK)) { + attr->type = type; + retc = 0; + } + + return retc; }