diff --git a/arch/posix/include/posix_cheats.h b/arch/posix/include/posix_cheats.h index d44d5f16284..b18d7756f7f 100644 --- a/arch/posix/include/posix_cheats.h +++ b/arch/posix/include/posix_cheats.h @@ -47,9 +47,10 @@ #define mq_attr zap_mq_attr #define dirent zap_dirent #define DIR zap_DIR +#define pthread_once_t zap_pthread_once_t +#define pthread_key_t zap_pthread_key_t /* Condition variables */ - #define pthread_cond_init(...) zap_pthread_cond_init(__VA_ARGS__) #define pthread_cond_destroy(...) zap_pthread_cond_destroy(__VA_ARGS__) #define pthread_cond_signal(...) zap_pthread_cond_signal(__VA_ARGS__) @@ -97,6 +98,7 @@ #define pthread_equal(...) zap_pthread_equal(__VA_ARGS__) #define pthread_self(...) zap_pthread_self(__VA_ARGS__) #define pthread_getschedparam(...) zap_pthread_getschedparam(__VA_ARGS__) +#define pthread_once(...) zap_pthread_once(__VA_ARGS__) #define pthread_exit(...) zap_pthread_exit(__VA_ARGS__) #define pthread_join(...) zap_pthread_join(__VA_ARGS__) #define pthread_detach(...) zap_pthread_detach(__VA_ARGS__) @@ -154,6 +156,12 @@ #define pthread_rwlockattr_destroy(...)\ zap_pthread_rwlockattr_destroy(__VA_ARGS__) +/* Pthread key */ +#define pthread_key_create(...) zap_pthread_key_create(__VA_ARGS__) +#define pthread_key_delete(...) zap_pthread_key_delete(__VA_ARGS__) +#define pthread_setspecific(...) zap_pthread_setspecific(__VA_ARGS__) +#define pthread_getspecific(...) zap_pthread_getspecific(__VA_ARGS__) + /* message queue */ #define mq_open(...) zap_mq_open(__VA_ARGS__) #define mq_close(...) zap_mq_close(__VA_ARGS__) diff --git a/include/posix/pthread.h b/include/posix/pthread.h index ecc3ce72a90..255418c54d5 100644 --- a/include/posix/pthread.h +++ b/include/posix/pthread.h @@ -13,6 +13,7 @@ #include #include "sys/types.h" #include "posix_sched.h" +#include #include #include @@ -30,6 +31,9 @@ enum pthread_state { struct posix_thread { struct k_thread thread; + /* List of keys that thread has called pthread_setspecific() on */ + sys_slist_t key_list; + /* Exit status */ void *retval; @@ -53,6 +57,9 @@ struct posix_thread { #define PTHREAD_CANCEL_ENABLE (0 << _PTHREAD_CANCEL_POS) #define PTHREAD_CANCEL_DISABLE (1 << _PTHREAD_CANCEL_POS) +/* Passed to pthread_once */ +#define PTHREAD_ONCE_INIT 1 + /** * @brief Declare a pthread condition variable * @@ -480,6 +487,7 @@ int pthread_attr_getstack(const pthread_attr_t *attr, void **stackaddr, size_t *stacksize); int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize); +int pthread_once(pthread_once_t *once, void (*initFunc)(void)); void pthread_exit(void *retval); int pthread_join(pthread_t thread, void **status); int pthread_cancel(pthread_t pthread); @@ -503,5 +511,10 @@ int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock); int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock); int pthread_rwlock_unlock(pthread_rwlock_t *rwlock); int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock); +int pthread_key_create(pthread_key_t *key, + void (*destructor)(void *)); +int pthread_key_delete(pthread_key_t key); +int pthread_setspecific(pthread_key_t key, const void *value); +void *pthread_getspecific(pthread_key_t key); #endif /* __PTHREAD_H__ */ diff --git a/include/posix/pthread_key.h b/include/posix/pthread_key.h new file mode 100644 index 00000000000..ac6521a1b66 --- /dev/null +++ b/include/posix/pthread_key.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __POSIX_THREAD_KEY_H__ +#define __POSIX_THREAD_KEY_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef CONFIG_PTHREAD_IPC +#include +#include + +typedef u32_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; + +#endif /* CONFIG_PTHREAD_IPC */ + +#ifdef __cplusplus +} +#endif + +#endif /* __POSIX_THREAD_KEY_H__ */ diff --git a/lib/posix/CMakeLists.txt b/lib/posix/CMakeLists.txt index 49459edd501..7fa03335df7 100644 --- a/lib/posix/CMakeLists.txt +++ b/lib/posix/CMakeLists.txt @@ -15,6 +15,7 @@ zephyr_library_sources(sleep.c) zephyr_library_sources(timer.c) zephyr_library_sources(pthread_rwlock.c) zephyr_library_sources(semaphore.c) +zephyr_library_sources(pthread_key.c) zephyr_library_sources_ifdef(CONFIG_POSIX_MQUEUE mqueue.c) zephyr_library_sources_ifdef(CONFIG_POSIX_FS fs.c) diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index cf46a50ce50..8867389c8e7 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -10,12 +10,15 @@ #include #include #include +#include #define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE #define PTHREAD_CANCELED ((void *) -1) #define LOWEST_POSIX_THREAD_PRIORITY 1 +PTHREAD_MUTEX_DEFINE(pthread_key_lock); + static const pthread_attr_t init_pthread_attrs = { .priority = LOWEST_POSIX_THREAD_PRIORITY, .stack = NULL, @@ -162,6 +165,7 @@ int pthread_create(pthread_t *newthread, const pthread_attr_t *attr, pthread_mutex_init(&thread->state_lock, NULL); pthread_mutex_init(&thread->cancel_lock, NULL); pthread_cond_init(&thread->state_cond, &cond_attr); + sys_slist_init(&thread->key_list); *newthread = (pthread_t) k_thread_create(&thread->thread, attr->stack, attr->stacksize, @@ -299,6 +303,28 @@ int pthread_getschedparam(pthread_t pthread, int *policy, return 0; } +/** + * @brief Dynamic package initialization + * + * See IEEE 1003.1 + */ +int pthread_once(pthread_once_t *once, void (*init_func)(void)) +{ + pthread_mutex_lock(&pthread_key_lock); + + if (*once == PTHREAD_ONCE_INIT) { + pthread_mutex_unlock(&pthread_key_lock); + return 0; + } + + init_func(); + *once = PTHREAD_ONCE_INIT; + + pthread_mutex_unlock(&pthread_key_lock); + + return 0; +} + /** * @brief Terminate calling thread. * @@ -307,6 +333,9 @@ int pthread_getschedparam(pthread_t pthread, int *policy, void pthread_exit(void *retval) { struct posix_thread *self = (struct posix_thread *)pthread_self(); + pthread_key_obj *key_obj; + pthread_thread_data *thread_spec_data; + sys_snode_t *node_l; /* Make a thread as cancelable before exiting */ pthread_mutex_lock(&self->cancel_lock); @@ -326,6 +355,14 @@ void pthread_exit(void *retval) self->state = PTHREAD_TERMINATED; } + SYS_SLIST_FOR_EACH_NODE(&self->key_list, node_l) { + thread_spec_data = (pthread_thread_data *)node_l; + key_obj = thread_spec_data->key; + if ((key_obj->destructor != NULL) && (thread_spec_data != NULL)) { + (key_obj->destructor)(thread_spec_data->spec_data); + } + } + pthread_mutex_unlock(&self->state_lock); k_thread_abort((k_tid_t)self); } diff --git a/lib/posix/pthread_key.c b/lib/posix/pthread_key.c new file mode 100644 index 00000000000..b8391286a10 --- /dev/null +++ b/lib/posix/pthread_key.c @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2018 Intel Corporation + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include +#include +#include + +struct k_sem pthread_key_sem; + +K_SEM_DEFINE(pthread_key_sem, 1, 1); + +/** + * @brief Create a key for thread-specific data + * + * See IEEE 1003.1 + */ +int pthread_key_create(pthread_key_t *key, + void (*destructor)(void *)) +{ + pthread_key_obj *new_key; + + *key = NULL; + + new_key = k_malloc(sizeof(pthread_key_obj)); + + if (new_key == NULL) { + return ENOMEM; + } + + sys_slist_init(&(new_key->key_data_l)); + + new_key->destructor = destructor; + *key = (void *)new_key; + + return 0; +} + +/** + * @brief Delete a key for thread-specific data + * + * See IEEE 1003.1 + */ +int pthread_key_delete(pthread_key_t key) +{ + pthread_key_obj *key_obj = (pthread_key_obj *)key; + pthread_key_data *key_data; + sys_snode_t *node_l, *next_node_l; + + k_sem_take(&pthread_key_sem, K_FOREVER); + + /* Delete thread-specific elements associated with the key */ + SYS_SLIST_FOR_EACH_NODE_SAFE(&(key_obj->key_data_l), + node_l, next_node_l) { + + /* Remove the object from the list key_data_l */ + key_data = (pthread_key_data *) + sys_slist_get(&(key_obj->key_data_l)); + + /* Deallocate the object's memory */ + k_free((void *)key_data); + } + + k_free((void *)key_obj); + + k_sem_give(&pthread_key_sem); + + return 0; +} + +/** + * @brief Associate a thread-specific value with a key + * + * See IEEE 1003.1 + */ +int pthread_setspecific(pthread_key_t key, const void *value) +{ + pthread_key_obj *key_obj = (pthread_key_obj *)key; + struct posix_thread *thread = (struct posix_thread *)pthread_self(); + pthread_key_data *key_data; + pthread_thread_data *thread_spec_data; + 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); + + SYS_SLIST_FOR_EACH_NODE(&(thread->key_list), node_l) { + + thread_spec_data = (pthread_thread_data *)node_l; + + if (thread_spec_data->key == key_obj) { + + /* Key is already present so + * associate thread specific data + */ + thread_spec_data->spec_data = (void *)value; + goto out; + } + } + + if (node_l == NULL) { + key_data = k_malloc(sizeof(pthread_key_data)); + + if (key_data == NULL) { + retval = ENOMEM; + goto out; + + } else { + /* Associate thread specific data, initialize new key */ + key_data->thread_data.key = key; + key_data->thread_data.spec_data = (void *)value; + + /* Append new thread key data to thread's key list */ + sys_slist_append((&thread->key_list), + (sys_snode_t *)(&key_data->thread_data)); + + /* Append new key data to the key object's list */ + sys_slist_append(&(key_obj->key_data_l), + (sys_snode_t *)key_data); + } + } + +out: + k_sem_give(&pthread_key_sem); + + return retval; +} + +/** + * @brief Get the thread-specific value associated with the key + * + * See IEEE 1003.1 + */ +void *pthread_getspecific(pthread_key_t key) +{ + pthread_key_obj *key_obj = (pthread_key_obj *)key; + struct posix_thread *thread = (struct posix_thread *)pthread_self(); + pthread_thread_data *thread_spec_data; + void *value = NULL; + sys_snode_t *node_l; + + k_sem_take(&pthread_key_sem, K_FOREVER); + + node_l = sys_slist_peek_head(&(thread->key_list)); + + /* Traverse the list of keys set by the thread, looking for key */ + + SYS_SLIST_FOR_EACH_NODE(&(thread->key_list), node_l) { + thread_spec_data = (pthread_thread_data *)node_l; + if (thread_spec_data->key == key_obj) { + /* Key is present, so get the set thread data */ + value = thread_spec_data->spec_data; + break; + } + } + + k_sem_give(&pthread_key_sem); + + return value; +}