166 lines
3.6 KiB
C
166 lines
3.6 KiB
C
|
/*
|
||
|
* 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;
|
||
|
}
|