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:
Niranjhana N 2018-04-11 16:00:09 +05:30 committed by Anas Nashif
commit 414c39fc94
6 changed files with 277 additions and 1 deletions

View file

@ -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__)

View file

@ -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__ */

View 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__ */

View file

@ -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)

View file

@ -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
View 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;
}