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_key_t as uint32_t #52313

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
25 changes: 1 addition & 24 deletions include/zephyr/posix/pthread_key.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,7 @@ extern "C" {
typedef uint32_t pthread_once_t;

/* pthread_key */
typedef void *pthread_key_t;

typedef struct pthread_key_obj {
/* List of pthread_key_data objects that contain thread
* specific data for the key
*/
sys_slist_t key_data_l;

/* Optional destructor that is passed to pthread_key_create() */
void (*destructor)(void *);
} pthread_key_obj;

typedef struct pthread_thread_data {
sys_snode_t node;

/* Key and thread specific data passed to pthread_setspecific() */
pthread_key_obj *key;
void *spec_data;
} pthread_thread_data;

typedef struct pthread_key_data {
sys_snode_t node;
pthread_thread_data thread_data;
} pthread_key_data;
typedef uint32_t pthread_key_t;

#ifdef __cplusplus
}
Expand Down
7 changes: 7 additions & 0 deletions lib/posix/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ config MAX_PTHREAD_COND_COUNT
help
Maximum number of simultaneously active condition variables in a POSIX application.

config MAX_PTHREAD_KEY_COUNT
int "Maximum simultaneously active keys in a POSIX application"
default 5
range 0 255
help
Maximum number of simultaneously active keys in a POSIX application.

config SEM_VALUE_MAX
int "Maximum semaphore limit"
default 32767
Expand Down
29 changes: 29 additions & 0 deletions lib/posix/posix_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,29 @@ struct posix_thread {
pthread_cond_t state_cond;
};

typedef struct pthread_key_obj {
/* List of pthread_key_data objects that contain thread
* specific data for the key
*/
sys_slist_t key_data_l;

/* Optional destructor that is passed to pthread_key_create() */
void (*destructor)(void *value);
} pthread_key_obj;

typedef struct pthread_thread_data {
sys_snode_t node;

/* Key and thread specific data passed to pthread_setspecific() */
pthread_key_obj *key;
void *spec_data;
} pthread_thread_data;

typedef struct pthread_key_data {
sys_snode_t node;
pthread_thread_data thread_data;
} pthread_key_data;

static inline bool is_pthread_obj_initialized(uint32_t obj)
{
return (obj & PTHREAD_OBJ_MASK_INIT) != 0;
Expand Down Expand Up @@ -84,4 +107,10 @@ struct posix_cond *to_posix_cond(pthread_cond_t *cvar);
/* get a previously initialized posix_cond */
struct posix_cond *get_posix_cond(pthread_cond_t cond);

/* get and possibly initialize a posix_key */
pthread_key_obj *to_posix_key(pthread_key_t *keyp);

/* get a previously initialized posix_key */
pthread_key_obj *get_posix_key(pthread_key_t key);

#endif
6 changes: 3 additions & 3 deletions lib/posix/pthread.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

#define LOWEST_POSIX_THREAD_PRIORITY 1

K_MUTEX_DEFINE(pthread_key_lock);
K_MUTEX_DEFINE(pthread_once_lock);

static const pthread_attr_t init_pthread_attrs = {
.priority = LOWEST_POSIX_THREAD_PRIORITY,
Expand Down Expand Up @@ -352,14 +352,14 @@ int pthread_getschedparam(pthread_t pthread, int *policy,
*/
int pthread_once(pthread_once_t *once, void (*init_func)(void))
{
k_mutex_lock(&pthread_key_lock, K_FOREVER);
k_mutex_lock(&pthread_once_lock, K_FOREVER);

if (*once == PTHREAD_ONCE_INIT) {
init_func();
*once = 0;
}

k_mutex_unlock(&pthread_key_lock);
k_mutex_unlock(&pthread_once_lock);

return 0;
}
Expand Down
125 changes: 107 additions & 18 deletions lib/posix/pthread_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,83 @@
#include <zephyr/kernel.h>
#include <zephyr/posix/pthread.h>
#include <zephyr/posix/pthread_key.h>
#include <zephyr/sys/bitarray.h>

#include "posix_internal.h"

struct k_sem pthread_key_sem;
static struct k_spinlock pthread_key_lock;

K_SEM_DEFINE(pthread_key_sem, 1, 1);
/* This is non-standard (i.e. an implementation detail) */
#define PTHREAD_KEY_INITIALIZER (-1)

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

static pthread_key_obj posix_key_pool[CONFIG_MAX_PTHREAD_KEY_COUNT];
SYS_BITARRAY_DEFINE_STATIC(posix_key_bitarray, CONFIG_MAX_PTHREAD_KEY_COUNT);

static inline size_t posix_key_to_offset(pthread_key_obj *k)
{
return k - posix_key_pool;
}

static inline size_t to_posix_key_idx(pthread_key_t key)
{
return mark_pthread_obj_uninitialized(key);
}

pthread_key_obj *get_posix_key(pthread_key_t key)
{
int actually_initialized;
size_t bit = to_posix_key_idx(key);

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

/* Mask off the MSB to get the actual bit index */
if (sys_bitarray_test_bit(&posix_key_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_key_pool[bit];
}

pthread_key_obj *to_posix_key(pthread_key_t *key)
{
size_t bit;
pthread_key_obj *k;

if (*key != PTHREAD_KEY_INITIALIZER) {
return get_posix_key(*key);
}

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

/* Record the associated posix_cond in mu and mark as initialized */
*key = mark_pthread_obj_initialized(bit);
k = &posix_key_pool[bit];

/* Initialize the condition variable here */
memset(k, 0, sizeof(*k));

return k;
}

/**
* @brief Create a key for thread-specific data
Expand All @@ -23,18 +94,15 @@ int pthread_key_create(pthread_key_t *key,
{
pthread_key_obj *new_key;

*key = NULL;

new_key = k_malloc(sizeof(pthread_key_obj));

*key = PTHREAD_KEY_INITIALIZER;
new_key = to_posix_key(key);
if (new_key == NULL) {
return ENOMEM;
}

sys_slist_init(&(new_key->key_data_l));

new_key->destructor = destructor;
*key = (void *)new_key;

return 0;
}
Expand All @@ -46,11 +114,18 @@ int pthread_key_create(pthread_key_t *key,
*/
int pthread_key_delete(pthread_key_t key)
{
pthread_key_obj *key_obj = (pthread_key_obj *)key;
pthread_key_obj *key_obj;
pthread_key_data *key_data;
sys_snode_t *node_l, *next_node_l;
k_spinlock_key_t key_key;

k_sem_take(&pthread_key_sem, K_FOREVER);
key_key = k_spin_lock(&pthread_key_lock);

key_obj = get_posix_key(key);
if (key_obj == NULL) {
k_spin_unlock(&pthread_key_lock, key_key);
return EINVAL;
}

/* Delete thread-specific elements associated with the key */
SYS_SLIST_FOR_EACH_NODE_SAFE(&(key_obj->key_data_l),
Expand All @@ -64,9 +139,9 @@ int pthread_key_delete(pthread_key_t key)
k_free((void *)key_data);
}

k_free((void *)key_obj);
(void)sys_bitarray_free(&posix_key_bitarray, 1, 0);

k_sem_give(&pthread_key_sem);
k_spin_unlock(&pthread_key_lock, key_key);

return 0;
}
Expand All @@ -78,18 +153,25 @@ int pthread_key_delete(pthread_key_t key)
*/
int pthread_setspecific(pthread_key_t key, const void *value)
{
pthread_key_obj *key_obj = (pthread_key_obj *)key;
pthread_key_obj *key_obj;
struct posix_thread *thread = to_posix_thread(pthread_self());
pthread_key_data *key_data;
pthread_thread_data *thread_spec_data;
k_spinlock_key_t key_key;
sys_snode_t *node_l;
int retval = 0;

/* Traverse the list of keys set by the thread, looking for key.
* If the key is already in the list, re-assign its value.
* Else add the key to the thread's list.
*/
k_sem_take(&pthread_key_sem, K_FOREVER);
key_key = k_spin_lock(&pthread_key_lock);

key_obj = get_posix_key(key);
if (key_obj == NULL) {
k_spin_unlock(&pthread_key_lock, key_key);
return EINVAL;
}

SYS_SLIST_FOR_EACH_NODE(&(thread->key_list), node_l) {

Expand All @@ -114,7 +196,7 @@ int pthread_setspecific(pthread_key_t key, const void *value)

} else {
/* Associate thread specific data, initialize new key */
key_data->thread_data.key = key;
key_data->thread_data.key = key_obj;
key_data->thread_data.spec_data = (void *)value;

/* Append new thread key data to thread's key list */
Expand All @@ -128,7 +210,7 @@ int pthread_setspecific(pthread_key_t key, const void *value)
}

out:
k_sem_give(&pthread_key_sem);
k_spin_unlock(&pthread_key_lock, key_key);

return retval;
}
Expand All @@ -140,13 +222,20 @@ int pthread_setspecific(pthread_key_t key, const void *value)
*/
void *pthread_getspecific(pthread_key_t key)
{
pthread_key_obj *key_obj = (pthread_key_obj *)key;
pthread_key_obj *key_obj;
struct posix_thread *thread = to_posix_thread(pthread_self());
pthread_thread_data *thread_spec_data;
void *value = NULL;
sys_snode_t *node_l;
k_spinlock_key_t key_key;

k_sem_take(&pthread_key_sem, K_FOREVER);
key_key = k_spin_lock(&pthread_key_lock);

key_obj = get_posix_key(key);
if (key_obj == NULL) {
k_spin_unlock(&pthread_key_lock, key_key);
return NULL;
}

node_l = sys_slist_peek_head(&(thread->key_list));

Expand All @@ -161,7 +250,7 @@ void *pthread_getspecific(pthread_key_t key)
}
}

k_sem_give(&pthread_key_sem);
k_spin_unlock(&pthread_key_lock, key_key);

return value;
}