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 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__)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <posix/unistd.h>
|
||||
#include "sys/types.h"
|
||||
#include "posix_sched.h"
|
||||
#include <posix/pthread_key.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -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__ */
|
||||
|
|
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(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)
|
||||
|
||||
|
|
|
@ -10,12 +10,15 @@
|
|||
#include <ksched.h>
|
||||
#include <wait_q.h>
|
||||
#include <posix/pthread.h>
|
||||
#include <misc/slist.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
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