/* * 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; }