Skip to content

posix: abstract pthread_cond_t as uint32_t #52173

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

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
4 changes: 1 addition & 3 deletions include/zephyr/posix/posix_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,7 @@ typedef struct pthread_mutexattr {
} pthread_mutexattr_t;

/* Condition variables */
typedef struct pthread_cond {
_wait_q_t wait_q;
} pthread_cond_t;
typedef uint32_t pthread_cond_t;

typedef struct pthread_condattr {
} pthread_condattr_t;
Expand Down
27 changes: 11 additions & 16 deletions include/zephyr/posix/pthread.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,13 @@ extern "C" {
/* The minimum allowable stack size */
#define PTHREAD_STACK_MIN Z_KERNEL_STACK_SIZE_ADJUST(0)

/**
* @brief Declare a condition variable as initialized
*
* Initialize a condition variable with the default condition variable attributes.
*/
#define PTHREAD_COND_INITIALIZER (-1)

/**
* @brief Declare a pthread condition variable
*
Expand All @@ -44,35 +51,23 @@ extern "C" {
* strategies for kernel objects.
*
* @param name Symbol name of the condition variable
* @deprecated Use @c PTHREAD_COND_INITIALIZER instead.
*/
#define PTHREAD_COND_DEFINE(name) \
struct pthread_cond name = { \
.wait_q = Z_WAIT_Q_INIT(&name.wait_q), \
}
#define PTHREAD_COND_DEFINE(name) pthread_cond_t name = PTHREAD_COND_INITIALIZER

/**
* @brief POSIX threading compatibility API
*
* See IEEE 1003.1
*/
static inline int pthread_cond_init(pthread_cond_t *cv,
const pthread_condattr_t *att)
{
ARG_UNUSED(att);
z_waitq_init(&cv->wait_q);
return 0;
}
int pthread_cond_init(pthread_cond_t *cv, const pthread_condattr_t *att);

/**
* @brief POSIX threading compatibility API
*
* See IEEE 1003.1
*/
static inline int pthread_cond_destroy(pthread_cond_t *cv)
{
ARG_UNUSED(cv);
return 0;
}
int pthread_cond_destroy(pthread_cond_t *cv);

/**
* @brief POSIX threading compatibility API
Expand Down
7 changes: 7 additions & 0 deletions lib/posix/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ config MAX_PTHREAD_MUTEX_COUNT
help
Maximum number of simultaneously active mutexes in a POSIX application.

config MAX_PTHREAD_COND_COUNT
int "Maximum simultaneously active condition variables in a POSIX application"
default 5
range 0 255
help
Maximum number of simultaneously active condition variables in a POSIX application.

config SEM_VALUE_MAX
int "Maximum semaphore limit"
default 32767
Expand Down
40 changes: 25 additions & 15 deletions lib/posix/posix_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
#define ZEPHYR_LIB_POSIX_POSIX_INTERNAL_H_

/*
* Bit used to mark a pthread_mutex_t as initialized. Initialization status is
* Bit used to mark a pthread object as initialized. Initialization status is
* verified (against internal status) in lock / unlock / destroy functions.
*/
#define PTHREAD_MUTEX_MASK_INIT 0x80000000
#define PTHREAD_OBJ_MASK_INIT 0x80000000

struct posix_mutex {
k_tid_t owner;
Expand All @@ -20,6 +20,10 @@ struct posix_mutex {
_wait_q_t wait_q;
};

struct posix_cond {
_wait_q_t wait_q;
};

enum pthread_state {
/* The thread structure is unallocated and available for reuse. */
PTHREAD_TERMINATED = 0,
Expand Down Expand Up @@ -51,6 +55,21 @@ struct posix_thread {
pthread_cond_t state_cond;
};

static inline bool is_pthread_obj_initialized(uint32_t obj)
{
return (obj & PTHREAD_OBJ_MASK_INIT) != 0;
}

static inline uint32_t mark_pthread_obj_initialized(uint32_t obj)
{
return obj | PTHREAD_OBJ_MASK_INIT;
}

static inline uint32_t mark_pthread_obj_uninitialized(uint32_t obj)
{
return obj & ~PTHREAD_OBJ_MASK_INIT;
}

struct posix_thread *to_posix_thread(pthread_t pthread);

/* get and possibly initialize a posix_mutex */
Expand All @@ -59,19 +78,10 @@ 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;
}
/* get and possibly initialize a posix_cond */
struct posix_cond *to_posix_cond(pthread_cond_t *cvar);

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;
}
/* get a previously initialized posix_cond */
struct posix_cond *get_posix_cond(pthread_cond_t cond);

#endif
2 changes: 2 additions & 0 deletions lib/posix/pthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,8 @@ void pthread_exit(void *retval)
pthread_mutex_unlock(&self->state_lock);
pthread_mutex_destroy(&self->state_lock);

pthread_cond_destroy(&self->state_cond);

k_thread_abort((k_tid_t)self);
}

Expand Down
159 changes: 153 additions & 6 deletions lib/posix/pthread_cond.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,88 @@
#include <ksched.h>
#include <zephyr/wait_q.h>
#include <zephyr/posix/pthread.h>
#include <zephyr/sys/bitarray.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 *mu,
k_timeout_t timeout)
static struct posix_cond posix_cond_pool[CONFIG_MAX_PTHREAD_COND_COUNT];
SYS_BITARRAY_DEFINE_STATIC(posix_cond_bitarray, CONFIG_MAX_PTHREAD_COND_COUNT);

/*
* We reserve the MSB to mark a pthread_cond_t as initialized (from the
* perspective of the application). With a linear space, this means that
* the theoretical pthread_cond_t range is [0,2147483647].
*/
BUILD_ASSERT(CONFIG_MAX_PTHREAD_COND_COUNT < PTHREAD_OBJ_MASK_INIT,
"CONFIG_MAX_PTHREAD_COND_COUNT is too high");

static inline size_t posix_cond_to_offset(struct posix_cond *cv)
{
return cv - posix_cond_pool;
}

static inline size_t to_posix_cond_idx(pthread_cond_t cond)
{
return mark_pthread_obj_uninitialized(cond);
}

struct posix_cond *get_posix_cond(pthread_cond_t cond)
{
int actually_initialized;
size_t bit = to_posix_cond_idx(cond);

/* if the provided cond does not claim to be initialized, its invalid */
if (!is_pthread_obj_initialized(cond)) {
return NULL;
}

/* Mask off the MSB to get the actual bit index */
if (sys_bitarray_test_bit(&posix_cond_bitarray, bit, &actually_initialized) < 0) {
return NULL;
}

if (actually_initialized == 0) {
/* The cond claims to be initialized but is actually not */
return NULL;
}

return &posix_cond_pool[bit];
}

struct posix_cond *to_posix_cond(pthread_cond_t *cvar)
{
size_t bit;
struct posix_cond *cv;

if (*cvar != PTHREAD_COND_INITIALIZER) {
return get_posix_cond(*cvar);
}

/* Try and automatically associate a posix_cond */
if (sys_bitarray_alloc(&posix_cond_bitarray, 1, &bit) < 0) {
/* No conds left to allocate */
return NULL;
}

/* Record the associated posix_cond in mu and mark as initialized */
*cvar = mark_pthread_obj_initialized(bit);
cv = &posix_cond_pool[bit];

/* Initialize the condition variable here */
z_waitq_init(&cv->wait_q);

return cv;
}

static int cond_wait(pthread_cond_t *cond, pthread_mutex_t *mu, k_timeout_t timeout)
{
int ret;
k_spinlock_key_t key;
struct posix_cond *cv;
struct posix_mutex *m;

key = k_spin_lock(&z_pthread_spinlock);
Expand All @@ -29,6 +99,12 @@ static int cond_wait(pthread_cond_t *cv, pthread_mutex_t *mu,
return EINVAL;
}

cv = to_posix_cond(cond);
if (cv == NULL) {
k_spin_unlock(&z_pthread_spinlock, key);
return EINVAL;
}

__ASSERT_NO_MSG(m->lock_count == 1U);
m->lock_count = 0U;
m->owner = NULL;
Expand All @@ -48,14 +124,41 @@ static int cond_wait(pthread_cond_t *cv, pthread_mutex_t *mu,
return ret == -EAGAIN ? ETIMEDOUT : ret;
}

int pthread_cond_signal(pthread_cond_t *cv)
int pthread_cond_signal(pthread_cond_t *cvar)
{
k_spinlock_key_t key;
struct posix_cond *cv;

key = k_spin_lock(&z_pthread_spinlock);

cv = to_posix_cond(cvar);
if (cv == NULL) {
k_spin_unlock(&z_pthread_spinlock, key);
return EINVAL;
}

k_spin_unlock(&z_pthread_spinlock, key);

z_sched_wake(&cv->wait_q, 0, NULL);

return 0;
}

int pthread_cond_broadcast(pthread_cond_t *cv)
int pthread_cond_broadcast(pthread_cond_t *cvar)
{
k_spinlock_key_t key;
struct posix_cond *cv;

key = k_spin_lock(&z_pthread_spinlock);

cv = to_posix_cond(cvar);
if (cv == NULL) {
k_spin_unlock(&z_pthread_spinlock, key);
return EINVAL;
}

k_spin_unlock(&z_pthread_spinlock, key);

z_sched_wake_all(&cv->wait_q, 0, NULL);
return 0;
}
Expand All @@ -65,9 +168,53 @@ int pthread_cond_wait(pthread_cond_t *cv, pthread_mutex_t *mut)
return cond_wait(cv, mut, K_FOREVER);
}

int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mut,
const struct timespec *abstime)
int pthread_cond_timedwait(pthread_cond_t *cv, pthread_mutex_t *mut, const struct timespec *abstime)
{
int32_t timeout = (int32_t)timespec_to_timeoutms(abstime);
return cond_wait(cv, mut, K_MSEC(timeout));
}

int pthread_cond_init(pthread_cond_t *cvar, const pthread_condattr_t *att)
{
k_spinlock_key_t key;
struct posix_cond *cv;

ARG_UNUSED(att);
*cvar = PTHREAD_COND_INITIALIZER;

key = k_spin_lock(&z_pthread_spinlock);

cv = to_posix_cond(cvar);
if (cv == NULL) {
k_spin_unlock(&z_pthread_spinlock, key);
return EINVAL;
}

k_spin_unlock(&z_pthread_spinlock, key);

return 0;
}

int pthread_cond_destroy(pthread_cond_t *cvar)
{
__unused int rc;
k_spinlock_key_t key;
struct posix_cond *cv;
pthread_cond_t c = *cvar;
size_t bit = to_posix_cond_idx(c);

key = k_spin_lock(&z_pthread_spinlock);

cv = get_posix_cond(c);
if (cv == NULL) {
k_spin_unlock(&z_pthread_spinlock, key);
return EINVAL;
}

rc = sys_bitarray_free(&posix_cond_bitarray, 1, bit);
__ASSERT(rc == 0, "failed to free bit %zu", bit);

k_spin_unlock(&z_pthread_spinlock, key);

return 0;
}
8 changes: 4 additions & 4 deletions lib/posix/pthread_mutex.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ SYS_BITARRAY_DEFINE_STATIC(posix_mutex_bitarray, CONFIG_MAX_PTHREAD_MUTEX_COUNT)
* 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,
BUILD_ASSERT(CONFIG_MAX_PTHREAD_MUTEX_COUNT < PTHREAD_OBJ_MASK_INIT,
"CONFIG_MAX_PTHREAD_MUTEX_COUNT is too high");

static inline size_t posix_mutex_to_offset(struct posix_mutex *m)
Expand All @@ -43,7 +43,7 @@ static inline size_t posix_mutex_to_offset(struct posix_mutex *m)

static inline size_t to_posix_mutex_idx(pthread_mutex_t mut)
{
return mark_pthread_mutex_uninitialized(mut);
return mark_pthread_obj_uninitialized(mut);
}

struct posix_mutex *get_posix_mutex(pthread_mutex_t mu)
Expand All @@ -52,7 +52,7 @@ struct posix_mutex *get_posix_mutex(pthread_mutex_t mu)
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)) {
if (!is_pthread_obj_initialized(mu)) {
return NULL;
}

Expand Down Expand Up @@ -85,7 +85,7 @@ struct posix_mutex *to_posix_mutex(pthread_mutex_t *mu)
}

/* Record the associated posix_mutex in mu and mark as initialized */
*mu = mark_pthread_mutex_initialized(bit);
*mu = mark_pthread_obj_initialized(bit);

/* Initialize the posix_mutex */
m = &posix_mutex_pool[bit];
Expand Down
Loading