posix: mutex: abstract pthread_mutex_t as uint32_t
Consistent with the change of `pthread_t` from `struct posix_thread` to `uint32_t`, we can now also abstract `pthread_mutex_t` as `uint32_t` and separate `struct posix_mutex` as an implementation detail, hidden from POSIX API consumers. This change deprecates `PTHREAD_MUTEX_DEFINE()` in favour of the (standardized) `PTHREAD_MUTEX_INITIALIZER`. This change introduces `CONFIG_MAX_PTHREAD_MUTEX_COUNT`. Signed-off-by: Chris Friedt <cfriedt@meta.com>
This commit is contained in:
parent
6042acc1a9
commit
b0b4c9c3f1
@ -50,12 +50,7 @@ typedef uint32_t pthread_t;
|
||||
typedef struct k_sem sem_t;
|
||||
|
||||
/* Mutex */
|
||||
typedef struct pthread_mutex {
|
||||
k_tid_t owner;
|
||||
uint16_t lock_count;
|
||||
int type;
|
||||
_wait_q_t wait_q;
|
||||
} pthread_mutex_t;
|
||||
typedef uint32_t pthread_mutex_t;
|
||||
|
||||
typedef struct pthread_mutexattr {
|
||||
int type;
|
||||
|
||||
@ -129,6 +129,13 @@ static inline int pthread_condattr_destroy(pthread_condattr_t *att)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Declare a mutex as initialized
|
||||
*
|
||||
* Initialize a mutex with the default mutex attributes.
|
||||
*/
|
||||
#define PTHREAD_MUTEX_INITIALIZER (-1)
|
||||
|
||||
/**
|
||||
* @brief Declare a pthread mutex
|
||||
*
|
||||
@ -137,14 +144,9 @@ static inline int pthread_condattr_destroy(pthread_condattr_t *att)
|
||||
* kernel objects.
|
||||
*
|
||||
* @param name Symbol name of the mutex
|
||||
* @deprecated Use @c PTHREAD_MUTEX_INITIALIZER instead.
|
||||
*/
|
||||
#define PTHREAD_MUTEX_DEFINE(name) \
|
||||
struct pthread_mutex name = \
|
||||
{ \
|
||||
.lock_count = 0, \
|
||||
.wait_q = Z_WAIT_Q_INIT(&name.wait_q), \
|
||||
.owner = NULL, \
|
||||
}
|
||||
#define PTHREAD_MUTEX_DEFINE(name) pthread_mutex_t name = PTHREAD_MUTEX_INITIALIZER
|
||||
|
||||
/*
|
||||
* Mutex attributes - type
|
||||
|
||||
@ -35,6 +35,13 @@ config MAX_PTHREAD_COUNT
|
||||
help
|
||||
Maximum number of simultaneously active threads in a POSIX application.
|
||||
|
||||
config MAX_PTHREAD_MUTEX_COUNT
|
||||
int "Maximum simultaneously active mutex count in POSIX application"
|
||||
default 5
|
||||
range 0 255
|
||||
help
|
||||
Maximum number of simultaneously active mutexes in a POSIX application.
|
||||
|
||||
config SEM_VALUE_MAX
|
||||
int "Maximum semaphore limit"
|
||||
default 32767
|
||||
|
||||
@ -7,6 +7,19 @@
|
||||
#ifndef ZEPHYR_LIB_POSIX_POSIX_INTERNAL_H_
|
||||
#define ZEPHYR_LIB_POSIX_POSIX_INTERNAL_H_
|
||||
|
||||
/*
|
||||
* Bit used to mark a pthread_mutex_t as initialized. Initialization status is
|
||||
* verified (against internal status) in lock / unlock / destroy functions.
|
||||
*/
|
||||
#define PTHREAD_MUTEX_MASK_INIT 0x80000000
|
||||
|
||||
struct posix_mutex {
|
||||
k_tid_t owner;
|
||||
uint16_t lock_count;
|
||||
int type;
|
||||
_wait_q_t wait_q;
|
||||
};
|
||||
|
||||
enum pthread_state {
|
||||
/* The thread structure is unallocated and available for reuse. */
|
||||
PTHREAD_TERMINATED = 0,
|
||||
@ -40,4 +53,25 @@ struct posix_thread {
|
||||
|
||||
struct posix_thread *to_posix_thread(pthread_t pthread);
|
||||
|
||||
/* get and possibly initialize a posix_mutex */
|
||||
struct posix_mutex *to_posix_mutex(pthread_mutex_t *mu);
|
||||
|
||||
/* get a previously initialized posix_mutex */
|
||||
struct posix_mutex *get_posix_mutex(pthread_mutex_t mut);
|
||||
|
||||
static inline bool is_pthread_mutex_initialized(pthread_mutex_t mut)
|
||||
{
|
||||
return (mut & PTHREAD_MUTEX_MASK_INIT) != 0;
|
||||
}
|
||||
|
||||
static inline pthread_mutex_t mark_pthread_mutex_initialized(pthread_mutex_t mut)
|
||||
{
|
||||
return mut | PTHREAD_MUTEX_MASK_INIT;
|
||||
}
|
||||
|
||||
static inline pthread_mutex_t mark_pthread_mutex_uninitialized(pthread_mutex_t mut)
|
||||
{
|
||||
return mut & ~PTHREAD_MUTEX_MASK_INIT;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -9,21 +9,30 @@
|
||||
#include <zephyr/wait_q.h>
|
||||
#include <zephyr/posix/pthread.h>
|
||||
|
||||
#include "posix_internal.h"
|
||||
|
||||
extern struct k_spinlock z_pthread_spinlock;
|
||||
|
||||
int64_t timespec_to_timeoutms(const struct timespec *abstime);
|
||||
|
||||
static int cond_wait(pthread_cond_t *cv, pthread_mutex_t *mut,
|
||||
static int cond_wait(pthread_cond_t *cv, pthread_mutex_t *mu,
|
||||
k_timeout_t timeout)
|
||||
{
|
||||
__ASSERT(mut->lock_count == 1U, "");
|
||||
|
||||
int ret;
|
||||
k_spinlock_key_t key = k_spin_lock(&z_pthread_spinlock);
|
||||
k_spinlock_key_t key;
|
||||
struct posix_mutex *m;
|
||||
|
||||
mut->lock_count = 0U;
|
||||
mut->owner = NULL;
|
||||
_ready_one_thread(&mut->wait_q);
|
||||
key = k_spin_lock(&z_pthread_spinlock);
|
||||
m = to_posix_mutex(mu);
|
||||
if (m == NULL) {
|
||||
k_spin_unlock(&z_pthread_spinlock, key);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
__ASSERT_NO_MSG(m->lock_count == 1U);
|
||||
m->lock_count = 0U;
|
||||
m->owner = NULL;
|
||||
_ready_one_thread(&m->wait_q);
|
||||
ret = z_sched_wait(&z_pthread_spinlock, key, &cv->wait_q, timeout, NULL);
|
||||
|
||||
/* FIXME: this extra lock (and the potential context switch it
|
||||
@ -34,7 +43,7 @@ static int cond_wait(pthread_cond_t *cv, pthread_mutex_t *mut,
|
||||
* But that requires putting scheduler intelligence into this
|
||||
* higher level abstraction and is probably not worth it.
|
||||
*/
|
||||
pthread_mutex_lock(mut);
|
||||
pthread_mutex_lock(mu);
|
||||
|
||||
return ret == -EAGAIN ? ETIMEDOUT : ret;
|
||||
}
|
||||
|
||||
@ -8,6 +8,9 @@
|
||||
#include <ksched.h>
|
||||
#include <zephyr/wait_q.h>
|
||||
#include <zephyr/posix/pthread.h>
|
||||
#include <zephyr/sys/bitarray.h>
|
||||
|
||||
#include "posix_internal.h"
|
||||
|
||||
struct k_spinlock z_pthread_spinlock;
|
||||
|
||||
@ -22,10 +25,92 @@ static const pthread_mutexattr_t def_attr = {
|
||||
.type = PTHREAD_MUTEX_DEFAULT,
|
||||
};
|
||||
|
||||
static int acquire_mutex(pthread_mutex_t *m, k_timeout_t timeout)
|
||||
static struct posix_mutex posix_mutex_pool[CONFIG_MAX_PTHREAD_MUTEX_COUNT];
|
||||
SYS_BITARRAY_DEFINE_STATIC(posix_mutex_bitarray, CONFIG_MAX_PTHREAD_MUTEX_COUNT);
|
||||
|
||||
/*
|
||||
* We reserve the MSB to mark a pthread_mutex_t as initialized (from the
|
||||
* perspective of the application). With a linear space, this means that
|
||||
* the theoretical pthread_mutex_t range is [0,2147483647].
|
||||
*/
|
||||
BUILD_ASSERT(CONFIG_MAX_PTHREAD_MUTEX_COUNT < PTHREAD_MUTEX_MASK_INIT,
|
||||
"CONFIG_MAX_PTHREAD_MUTEX_COUNT is too high");
|
||||
|
||||
static inline size_t posix_mutex_to_offset(struct posix_mutex *m)
|
||||
{
|
||||
return m - posix_mutex_pool;
|
||||
}
|
||||
|
||||
static inline size_t to_posix_mutex_idx(pthread_mutex_t mut)
|
||||
{
|
||||
return mark_pthread_mutex_uninitialized(mut);
|
||||
}
|
||||
|
||||
struct posix_mutex *get_posix_mutex(pthread_mutex_t mu)
|
||||
{
|
||||
int actually_initialized;
|
||||
size_t bit = to_posix_mutex_idx(mu);
|
||||
|
||||
/* if the provided mutex does not claim to be initialized, its invalid */
|
||||
if (!is_pthread_mutex_initialized(mu)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Mask off the MSB to get the actual bit index */
|
||||
if (sys_bitarray_test_bit(&posix_mutex_bitarray, bit, &actually_initialized) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (actually_initialized == 0) {
|
||||
/* The mutex claims to be initialized but is actually not */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return &posix_mutex_pool[bit];
|
||||
}
|
||||
|
||||
struct posix_mutex *to_posix_mutex(pthread_mutex_t *mu)
|
||||
{
|
||||
size_t bit;
|
||||
struct posix_mutex *m;
|
||||
|
||||
if (*mu != PTHREAD_MUTEX_INITIALIZER) {
|
||||
return get_posix_mutex(*mu);
|
||||
}
|
||||
|
||||
/* Try and automatically associate a posix_mutex */
|
||||
if (sys_bitarray_alloc(&posix_mutex_bitarray, 1, &bit) < 0) {
|
||||
/* No mutexes left to allocate */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Record the associated posix_mutex in mu and mark as initialized */
|
||||
*mu = mark_pthread_mutex_initialized(bit);
|
||||
|
||||
/* Initialize the posix_mutex */
|
||||
m = &posix_mutex_pool[bit];
|
||||
|
||||
m->owner = NULL;
|
||||
m->lock_count = 0U;
|
||||
|
||||
z_waitq_init(&m->wait_q);
|
||||
|
||||
return m;
|
||||
}
|
||||
|
||||
static int acquire_mutex(pthread_mutex_t *mu, k_timeout_t timeout)
|
||||
{
|
||||
int rc = 0;
|
||||
k_spinlock_key_t key = k_spin_lock(&z_pthread_spinlock);
|
||||
k_spinlock_key_t key;
|
||||
struct posix_mutex *m;
|
||||
|
||||
key = k_spin_lock(&z_pthread_spinlock);
|
||||
|
||||
m = to_posix_mutex(mu);
|
||||
if (m == NULL) {
|
||||
k_spin_unlock(&z_pthread_spinlock, key);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (m->lock_count == 0U && m->owner == NULL) {
|
||||
m->lock_count++;
|
||||
@ -89,19 +174,24 @@ int pthread_mutex_timedlock(pthread_mutex_t *m,
|
||||
*
|
||||
* See IEEE 1003.1
|
||||
*/
|
||||
int pthread_mutex_init(pthread_mutex_t *m,
|
||||
int pthread_mutex_init(pthread_mutex_t *mu,
|
||||
const pthread_mutexattr_t *attr)
|
||||
{
|
||||
const pthread_mutexattr_t *mattr;
|
||||
k_spinlock_key_t key;
|
||||
struct posix_mutex *m;
|
||||
|
||||
m->owner = NULL;
|
||||
m->lock_count = 0U;
|
||||
*mu = PTHREAD_MUTEX_INITIALIZER;
|
||||
key = k_spin_lock(&z_pthread_spinlock);
|
||||
|
||||
mattr = (attr == NULL) ? &def_attr : attr;
|
||||
m = to_posix_mutex(mu);
|
||||
if (m == NULL) {
|
||||
k_spin_unlock(&z_pthread_spinlock, key);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
m->type = mattr->type;
|
||||
m->type = (attr == NULL) ? def_attr.type : attr->type;
|
||||
|
||||
z_waitq_init(&m->wait_q);
|
||||
k_spin_unlock(&z_pthread_spinlock, key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -122,11 +212,20 @@ int pthread_mutex_lock(pthread_mutex_t *m)
|
||||
*
|
||||
* See IEEE 1003.1
|
||||
*/
|
||||
int pthread_mutex_unlock(pthread_mutex_t *m)
|
||||
int pthread_mutex_unlock(pthread_mutex_t *mu)
|
||||
{
|
||||
k_spinlock_key_t key = k_spin_lock(&z_pthread_spinlock);
|
||||
|
||||
k_tid_t thread;
|
||||
k_spinlock_key_t key;
|
||||
struct posix_mutex *m;
|
||||
pthread_mutex_t mut = *mu;
|
||||
|
||||
key = k_spin_lock(&z_pthread_spinlock);
|
||||
|
||||
m = get_posix_mutex(mut);
|
||||
if (m == NULL) {
|
||||
k_spin_unlock(&z_pthread_spinlock, key);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (m->owner != k_current_get()) {
|
||||
k_spin_unlock(&z_pthread_spinlock, key);
|
||||
@ -162,9 +261,26 @@ int pthread_mutex_unlock(pthread_mutex_t *m)
|
||||
*
|
||||
* See IEEE 1003.1
|
||||
*/
|
||||
int pthread_mutex_destroy(pthread_mutex_t *m)
|
||||
int pthread_mutex_destroy(pthread_mutex_t *mu)
|
||||
{
|
||||
ARG_UNUSED(m);
|
||||
__unused int rc;
|
||||
k_spinlock_key_t key;
|
||||
struct posix_mutex *m;
|
||||
pthread_mutex_t mut = *mu;
|
||||
size_t bit = to_posix_mutex_idx(mut);
|
||||
|
||||
key = k_spin_lock(&z_pthread_spinlock);
|
||||
m = get_posix_mutex(mut);
|
||||
if (m == NULL) {
|
||||
k_spin_unlock(&z_pthread_spinlock, key);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
rc = sys_bitarray_free(&posix_mutex_bitarray, 1, bit);
|
||||
__ASSERT(rc == 0, "failed to free bit %zu", bit);
|
||||
|
||||
k_spin_unlock(&z_pthread_spinlock, key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user