posix: key: abstract pthread_key_t as uint32_t
Consistent with the change of `pthread_t`, `pthread_mutex_t`, and `pthread_cond_t` to `uint32_t`, we can now also abstract `pthread_key_t` as `uint32_t` and separate the implementation detail, hidden from POSIX API consumers. This change introduces `CONFIG_MAX_PTHREAD_KEY_COUNT`. Signed-off-by: Chris Friedt <cfriedt@meta.com>
This commit is contained in:
parent
96b9d7cb6d
commit
f1ececc682
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
@ -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,11 +6,84 @@
|
|||
#include <zephyr/kernel.h>
|
||||
#include <zephyr/posix/pthread.h>
|
||||
#include <zephyr/posix/pthread_key.h>
|
||||
#include <zephyr/sys/bitarray.h>
|
||||
|
||||
#include "posix_internal.h"
|
||||
|
||||
static struct k_spinlock pthread_key_lock;
|
||||
|
||||
/* 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
|
||||
*
|
||||
|
@ -21,10 +94,8 @@ 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;
|
||||
}
|
||||
|
@ -32,7 +103,6 @@ int pthread_key_create(pthread_key_t *key,
|
|||
sys_slist_init(&(new_key->key_data_l));
|
||||
|
||||
new_key->destructor = destructor;
|
||||
*key = (void *)new_key;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -44,13 +114,19 @@ 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;
|
||||
|
||||
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),
|
||||
node_l, next_node_l) {
|
||||
|
@ -63,7 +139,7 @@ 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_spin_unlock(&pthread_key_lock, key_key);
|
||||
|
||||
|
@ -77,7 +153,7 @@ 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;
|
||||
|
@ -91,6 +167,12 @@ int pthread_setspecific(pthread_key_t key, const void *value)
|
|||
*/
|
||||
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) {
|
||||
|
||||
thread_spec_data = (pthread_thread_data *)node_l;
|
||||
|
@ -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 */
|
||||
|
@ -140,7 +222,7 @@ out:
|
|||
*/
|
||||
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;
|
||||
|
@ -149,6 +231,12 @@ void *pthread_getspecific(pthread_key_t key)
|
|||
|
||||
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));
|
||||
|
||||
/* Traverse the list of keys set by the thread, looking for key */
|
||||
|
|
Loading…
Reference in New Issue