posix: add pthread_key and pthread_once APIs
Added 4 new pthread_key APIs for thread-specific data key creation, deletion, setting and getting the values. Added a key list to the posix_struct for threads. Added pthread_once API. Signed-off-by: Niranjhana N <niranjhana.n@intel.com>
This commit is contained in:
parent
f84caef220
commit
414c39fc94
6 changed files with 277 additions and 1 deletions
|
@ -47,9 +47,10 @@
|
||||||
#define mq_attr zap_mq_attr
|
#define mq_attr zap_mq_attr
|
||||||
#define dirent zap_dirent
|
#define dirent zap_dirent
|
||||||
#define DIR zap_DIR
|
#define DIR zap_DIR
|
||||||
|
#define pthread_once_t zap_pthread_once_t
|
||||||
|
#define pthread_key_t zap_pthread_key_t
|
||||||
|
|
||||||
/* Condition variables */
|
/* Condition variables */
|
||||||
|
|
||||||
#define pthread_cond_init(...) zap_pthread_cond_init(__VA_ARGS__)
|
#define pthread_cond_init(...) zap_pthread_cond_init(__VA_ARGS__)
|
||||||
#define pthread_cond_destroy(...) zap_pthread_cond_destroy(__VA_ARGS__)
|
#define pthread_cond_destroy(...) zap_pthread_cond_destroy(__VA_ARGS__)
|
||||||
#define pthread_cond_signal(...) zap_pthread_cond_signal(__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_equal(...) zap_pthread_equal(__VA_ARGS__)
|
||||||
#define pthread_self(...) zap_pthread_self(__VA_ARGS__)
|
#define pthread_self(...) zap_pthread_self(__VA_ARGS__)
|
||||||
#define pthread_getschedparam(...) zap_pthread_getschedparam(__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_exit(...) zap_pthread_exit(__VA_ARGS__)
|
||||||
#define pthread_join(...) zap_pthread_join(__VA_ARGS__)
|
#define pthread_join(...) zap_pthread_join(__VA_ARGS__)
|
||||||
#define pthread_detach(...) zap_pthread_detach(__VA_ARGS__)
|
#define pthread_detach(...) zap_pthread_detach(__VA_ARGS__)
|
||||||
|
@ -154,6 +156,12 @@
|
||||||
#define pthread_rwlockattr_destroy(...)\
|
#define pthread_rwlockattr_destroy(...)\
|
||||||
zap_pthread_rwlockattr_destroy(__VA_ARGS__)
|
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 */
|
/* message queue */
|
||||||
#define mq_open(...) zap_mq_open(__VA_ARGS__)
|
#define mq_open(...) zap_mq_open(__VA_ARGS__)
|
||||||
#define mq_close(...) zap_mq_close(__VA_ARGS__)
|
#define mq_close(...) zap_mq_close(__VA_ARGS__)
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <posix/unistd.h>
|
#include <posix/unistd.h>
|
||||||
#include "sys/types.h"
|
#include "sys/types.h"
|
||||||
#include "posix_sched.h"
|
#include "posix_sched.h"
|
||||||
|
#include <posix/pthread_key.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
@ -30,6 +31,9 @@ enum pthread_state {
|
||||||
struct posix_thread {
|
struct posix_thread {
|
||||||
struct k_thread thread;
|
struct k_thread thread;
|
||||||
|
|
||||||
|
/* List of keys that thread has called pthread_setspecific() on */
|
||||||
|
sys_slist_t key_list;
|
||||||
|
|
||||||
/* Exit status */
|
/* Exit status */
|
||||||
void *retval;
|
void *retval;
|
||||||
|
|
||||||
|
@ -53,6 +57,9 @@ struct posix_thread {
|
||||||
#define PTHREAD_CANCEL_ENABLE (0 << _PTHREAD_CANCEL_POS)
|
#define PTHREAD_CANCEL_ENABLE (0 << _PTHREAD_CANCEL_POS)
|
||||||
#define PTHREAD_CANCEL_DISABLE (1 << _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
|
* @brief Declare a pthread condition variable
|
||||||
*
|
*
|
||||||
|
@ -480,6 +487,7 @@ int pthread_attr_getstack(const pthread_attr_t *attr,
|
||||||
void **stackaddr, size_t *stacksize);
|
void **stackaddr, size_t *stacksize);
|
||||||
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
|
int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr,
|
||||||
size_t stacksize);
|
size_t stacksize);
|
||||||
|
int pthread_once(pthread_once_t *once, void (*initFunc)(void));
|
||||||
void pthread_exit(void *retval);
|
void pthread_exit(void *retval);
|
||||||
int pthread_join(pthread_t thread, void **status);
|
int pthread_join(pthread_t thread, void **status);
|
||||||
int pthread_cancel(pthread_t pthread);
|
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_trywrlock(pthread_rwlock_t *rwlock);
|
||||||
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
|
int pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
|
||||||
int pthread_rwlock_wrlock(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__ */
|
#endif /* __PTHREAD_H__ */
|
||||||
|
|
52
include/posix/pthread_key.h
Normal file
52
include/posix/pthread_key.h
Normal file
|
@ -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 <misc/slist.h>
|
||||||
|
#include <zephyr/types.h>
|
||||||
|
|
||||||
|
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__ */
|
|
@ -15,6 +15,7 @@ zephyr_library_sources(sleep.c)
|
||||||
zephyr_library_sources(timer.c)
|
zephyr_library_sources(timer.c)
|
||||||
zephyr_library_sources(pthread_rwlock.c)
|
zephyr_library_sources(pthread_rwlock.c)
|
||||||
zephyr_library_sources(semaphore.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_MQUEUE mqueue.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_POSIX_FS fs.c)
|
zephyr_library_sources_ifdef(CONFIG_POSIX_FS fs.c)
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,15 @@
|
||||||
#include <ksched.h>
|
#include <ksched.h>
|
||||||
#include <wait_q.h>
|
#include <wait_q.h>
|
||||||
#include <posix/pthread.h>
|
#include <posix/pthread.h>
|
||||||
|
#include <misc/slist.h>
|
||||||
|
|
||||||
#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE
|
#define PTHREAD_INIT_FLAGS PTHREAD_CANCEL_ENABLE
|
||||||
#define PTHREAD_CANCELED ((void *) -1)
|
#define PTHREAD_CANCELED ((void *) -1)
|
||||||
|
|
||||||
#define LOWEST_POSIX_THREAD_PRIORITY 1
|
#define LOWEST_POSIX_THREAD_PRIORITY 1
|
||||||
|
|
||||||
|
PTHREAD_MUTEX_DEFINE(pthread_key_lock);
|
||||||
|
|
||||||
static const pthread_attr_t init_pthread_attrs = {
|
static const pthread_attr_t init_pthread_attrs = {
|
||||||
.priority = LOWEST_POSIX_THREAD_PRIORITY,
|
.priority = LOWEST_POSIX_THREAD_PRIORITY,
|
||||||
.stack = NULL,
|
.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->state_lock, NULL);
|
||||||
pthread_mutex_init(&thread->cancel_lock, NULL);
|
pthread_mutex_init(&thread->cancel_lock, NULL);
|
||||||
pthread_cond_init(&thread->state_cond, &cond_attr);
|
pthread_cond_init(&thread->state_cond, &cond_attr);
|
||||||
|
sys_slist_init(&thread->key_list);
|
||||||
|
|
||||||
*newthread = (pthread_t) k_thread_create(&thread->thread, attr->stack,
|
*newthread = (pthread_t) k_thread_create(&thread->thread, attr->stack,
|
||||||
attr->stacksize,
|
attr->stacksize,
|
||||||
|
@ -299,6 +303,28 @@ int pthread_getschedparam(pthread_t pthread, int *policy,
|
||||||
return 0;
|
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.
|
* @brief Terminate calling thread.
|
||||||
*
|
*
|
||||||
|
@ -307,6 +333,9 @@ int pthread_getschedparam(pthread_t pthread, int *policy,
|
||||||
void pthread_exit(void *retval)
|
void pthread_exit(void *retval)
|
||||||
{
|
{
|
||||||
struct posix_thread *self = (struct posix_thread *)pthread_self();
|
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 */
|
/* Make a thread as cancelable before exiting */
|
||||||
pthread_mutex_lock(&self->cancel_lock);
|
pthread_mutex_lock(&self->cancel_lock);
|
||||||
|
@ -326,6 +355,14 @@ void pthread_exit(void *retval)
|
||||||
self->state = PTHREAD_TERMINATED;
|
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);
|
pthread_mutex_unlock(&self->state_lock);
|
||||||
k_thread_abort((k_tid_t)self);
|
k_thread_abort((k_tid_t)self);
|
||||||
}
|
}
|
||||||
|
|
165
lib/posix/pthread_key.c
Normal file
165
lib/posix/pthread_key.c
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2018 Intel Corporation
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
#include <kernel.h>
|
||||||
|
#include <posix/pthread.h>
|
||||||
|
#include <posix/pthread_key.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue