blob: e7486c5327ccb4a8d55eb198ffdfa00e3d81225b [file] [log] [blame]
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <pthread.h>
#include <zephyr/sys/util.h>
#include <zephyr/ztest.h>
#define N_THR 2
#define N_KEY 2
#define BUFFSZ 48
static pthread_key_t key;
static pthread_key_t keys[N_KEY];
static pthread_once_t key_once = PTHREAD_ONCE_INIT;
static pthread_once_t keys_once = PTHREAD_ONCE_INIT;
static void *thread_top(void *p1)
{
void *value;
char *buffer[BUFFSZ];
value = k_malloc(sizeof(buffer));
zassert_not_null(value, "thread could not allocate storage");
zassert_ok(pthread_setspecific(key, value), "pthread_setspecific failed");
zassert_equal(pthread_getspecific(key), value, "set and retrieved values are different");
k_free(value);
return NULL;
}
static void *thread_func(void *p1)
{
void *value;
char *buffer[BUFFSZ];
value = k_malloc(sizeof(buffer));
zassert_not_null(value, "thread could not allocate storage");
for (int i = 0; i < N_KEY; i++) {
zassert_ok(pthread_setspecific(keys[i], value), "pthread_setspecific failed");
zassert_equal(pthread_getspecific(keys[i]), value,
"set and retrieved values are different");
}
k_free(value);
return NULL;
}
static void make_key(void)
{
zassert_ok(pthread_key_create(&key, NULL), "insufficient memory to create key");
}
static void make_keys(void)
{
for (int i = 0; i < N_KEY; i++) {
zassert_ok(pthread_key_create(&keys[i], NULL),
"insufficient memory to create keys");
}
}
/**
* @brief Test to demonstrate pthread_key APIs usage
*
* @details The tests spawn a thread which uses pthread_once() to
* create a key via pthread_key_create() API. It then sets the
* thread-specific value to the key using pthread_setspecific() and
* gets it back using pthread_getspecific and asserts that they
* are equal. It then deletes the key using pthread_key_delete().
* Both the sub-tests do the above, but one with multiple threads
* using the same key and the other with a single thread using
* multiple keys.
*/
ZTEST(key, test_key_1toN_thread)
{
void *retval;
pthread_t newthread[N_THR];
zassert_ok(pthread_once(&key_once, make_key), "attempt to create key failed");
/* Different threads set different values to same key */
for (int i = 0; i < N_THR; i++) {
zassert_ok(pthread_create(&newthread[i], NULL, thread_top, NULL),
"attempt to create thread %d failed", i);
}
for (int i = 0; i < N_THR; i++) {
zassert_ok(pthread_join(newthread[i], &retval), "failed to join thread %d", i);
}
zassert_ok(pthread_key_delete(key), "attempt to delete key failed");
}
ZTEST(key, test_key_Nto1_thread)
{
pthread_t newthread;
zassert_ok(pthread_once(&keys_once, make_keys), "attempt to create keys failed");
/* Single thread associates its value with different keys */
zassert_ok(pthread_create(&newthread, NULL, thread_func, NULL),
"attempt to create thread failed");
zassert_ok(pthread_join(newthread, NULL), "failed to join thread");
for (int i = 0; i < N_KEY; i++) {
zassert_ok(pthread_key_delete(keys[i]), "attempt to delete keys[%d] failed", i);
}
}
ZTEST(key, test_key_resource_leak)
{
pthread_key_t key;
for (size_t i = 0; i < CONFIG_MAX_PTHREAD_KEY_COUNT; ++i) {
zassert_ok(pthread_key_create(&key, NULL), "failed to create key %zu", i);
zassert_ok(pthread_key_delete(key), "failed to delete key %zu", i);
}
}
ZTEST(key, test_correct_key_is_deleted)
{
pthread_key_t key;
size_t j = CONFIG_MAX_PTHREAD_KEY_COUNT - 1;
pthread_key_t keys[CONFIG_MAX_PTHREAD_KEY_COUNT];
for (size_t i = 0; i < ARRAY_SIZE(keys); ++i) {
zassert_ok(pthread_key_create(&keys[i], NULL), "failed to create key %zu", i);
}
key = keys[j];
zassert_ok(pthread_key_delete(keys[j]));
zassert_ok(pthread_key_create(&keys[j], NULL), "failed to create key %zu", j);
zassert_equal(key, keys[j], "deleted key %x instead of key %x", keys[j], key);
for (size_t i = 0; i < ARRAY_SIZE(keys); ++i) {
zassert_ok(pthread_key_delete(keys[i]), "failed to delete key %zu", i);
}
}
static void before(void *arg)
{
ARG_UNUSED(arg);
if (!IS_ENABLED(CONFIG_DYNAMIC_THREAD)) {
/* skip redundant testing if there is no thread pool / heap allocation */
ztest_test_skip();
}
}
ZTEST_SUITE(key, NULL, NULL, before, NULL, NULL);