Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

posix: abstract pthread_mutex_t as uint32_t #52087

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 1 addition & 6 deletions include/zephyr/posix/posix_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
16 changes: 9 additions & 7 deletions include/zephyr/posix/pthread.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand All @@ -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
Expand Down
7 changes: 7 additions & 0 deletions lib/posix/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
34 changes: 34 additions & 0 deletions lib/posix/posix_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
21 changes: 15 additions & 6 deletions lib/posix/pthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ static void zephyr_thread_wrapper(void *arg1, void *arg2, void *arg3)
int pthread_create(pthread_t *newthread, const pthread_attr_t *attr,
void *(*threadroutine)(void *), void *arg)
{
int rv;
int32_t prio;
k_spinlock_key_t key;
uint32_t pthread_num;
Expand Down Expand Up @@ -181,13 +182,15 @@ int pthread_create(pthread_t *newthread, const pthread_attr_t *attr,
return EAGAIN;
}

prio = posix_to_zephyr_priority(attr->priority, attr->schedpolicy);
rv = pthread_mutex_init(&thread->state_lock, NULL);
if (rv != 0) {
key = k_spin_lock(&pthread_pool_lock);
thread->state = PTHREAD_EXITED;
k_spin_unlock(&pthread_pool_lock, key);
return rv;
}

/*
* Ignore return value, as we know that Zephyr implementation
* cannot fail.
*/
(void)pthread_mutex_init(&thread->state_lock, NULL);
prio = posix_to_zephyr_priority(attr->priority, attr->schedpolicy);

cancel_key = k_spin_lock(&thread->cancel_lock);
thread->cancel_state = (1 << _PTHREAD_CANCEL_POS) & attr->flags;
Expand Down Expand Up @@ -402,6 +405,8 @@ void pthread_exit(void *retval)
}

pthread_mutex_unlock(&self->state_lock);
pthread_mutex_destroy(&self->state_lock);

k_thread_abort((k_tid_t)self);
}

Expand Down Expand Up @@ -440,6 +445,10 @@ int pthread_join(pthread_t thread, void **status)
}

pthread_mutex_unlock(&pthread->state_lock);
if (pthread->state == PTHREAD_EXITED) {
pthread_mutex_destroy(&pthread->state_lock);
}

return ret;
}

Expand Down
25 changes: 17 additions & 8 deletions lib/posix/pthread_cond.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

key = k_spin_lock(&z_pthread_spinlock);
m = to_posix_mutex(mu);
if (m == NULL) {
k_spin_unlock(&z_pthread_spinlock, key);
return EINVAL;
}

mut->lock_count = 0U;
mut->owner = NULL;
_ready_one_thread(&mut->wait_q);
__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
Expand All @@ -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;
}
Expand Down
144 changes: 130 additions & 14 deletions lib/posix/pthread_mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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);

Copy link
Member Author

@cfriedt cfriedt Nov 11, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This also needs to do the same initialization that pthread_mutex_init() does. Actually, it should probably just be moved here

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! (mostly, custom attributes are still applied in pthread_mutex_init()

/* 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++;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}

Expand Down
Loading