From 231827e84e300a8fccde12c5ee5404ba9ac7fc44 Mon Sep 17 00:00:00 2001 From: Tiago Medicci Date: Mon, 16 Dec 2024 15:28:55 -0300 Subject: [PATCH] ostest: Add test for GCC's tls (CONFIG_SCHED_THREAD_LOCAL) Enables testing the GCC thread local storage (tls) and the __thread keyword within ostest. --- testing/ostest/Makefile | 4 + testing/ostest/ostest.h | 4 + testing/ostest/ostest_main.c | 8 + testing/ostest/sched_thread_local.c | 230 ++++++++++++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 testing/ostest/sched_thread_local.c diff --git a/testing/ostest/Makefile b/testing/ostest/Makefile index fcd04665d5f..18fc1c19d80 100644 --- a/testing/ostest/Makefile +++ b/testing/ostest/Makefile @@ -58,6 +58,10 @@ ifneq ($(CONFIG_TLS_NELEM),0) CSRCS += tls.c endif +ifeq ($(CONFIG_SCHED_THREAD_LOCAL),y) +CSRCS += sched_thread_local.c +endif + ifeq ($(CONFIG_TESTING_OSTEST_AIO),y) CSRCS += aio.c endif diff --git a/testing/ostest/ostest.h b/testing/ostest/ostest.h index f369319c2f4..02ed90c7b16 100644 --- a/testing/ostest/ostest.h +++ b/testing/ostest/ostest.h @@ -234,6 +234,10 @@ void sporadic2_test(void); void tls_test(void); +/* sched_thread_local.c *****************************************************/ + +void sched_thread_local_test(void); + /* pthread_rwlock.c *********************************************************/ void pthread_rwlock_test(void); diff --git a/testing/ostest/ostest_main.c b/testing/ostest/ostest_main.c index c0f37dbc951..4a3902c8b55 100644 --- a/testing/ostest/ostest_main.c +++ b/testing/ostest/ostest_main.c @@ -313,6 +313,14 @@ static int user_main(int argc, char *argv[]) check_test_memory_usage(); #endif +#ifdef CONFIG_SCHED_THREAD_LOCAL + /* Test __thread/thread_local keyword */ + + printf("\nuser_main: sched_thread_local test\n"); + sched_thread_local_test(); + check_test_memory_usage(); +#endif + /* Top of test loop */ #if CONFIG_TESTING_OSTEST_LOOPS > 1 diff --git a/testing/ostest/sched_thread_local.c b/testing/ostest/sched_thread_local.c new file mode 100644 index 00000000000..d2fc08a3104 --- /dev/null +++ b/testing/ostest/sched_thread_local.c @@ -0,0 +1,230 @@ +/**************************************************************************** + * apps/testing/ostest/sched_thread_local.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include + +#include "ostest.h" + +#ifdef CONFIG_SCHED_THREAD_LOCAL + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define INIT_VALUE 6 +#define TEST_THREADS 3 + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +__thread short g_tls_short = INIT_VALUE; +__thread int g_tls_int = INIT_VALUE; +__thread long long g_tls_lld = -INIT_VALUE; + +long long g_tls_variables[TEST_THREADS][3]; + +static pthread_barrier_t g_barrier; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void *thread_func(void *parameter) +{ + int id = (int)((intptr_t)parameter); + short value_short = g_tls_short; + int value_int = g_tls_int; + long long value_lld = g_tls_lld; + int status; + + /* Wait at the g_barrier until all threads are synchronized. */ + + status = pthread_barrier_wait(&g_barrier); + if (status != 0 && status != PTHREAD_BARRIER_SERIAL_THREAD) + { + printf("sched_thread_local_test: ERROR thread %d pthread_barrier_wait " + "failed\n", id); + ASSERT(false); + } + + printf("thread_func[%d]: Thread Started\n", id); + + printf("thread_func[%d]: g_tls_short (at 0x%p) initial value = %d\n", + id, &g_tls_short, value_short); + printf("thread_func[%d]: g_tls_int (at 0x%p) initial value = %d\n", + id, &g_tls_int, value_int); + printf("thread_func[%d]: g_tls_lld (at 0x%p) initial value = %lld\n", + id, &g_tls_lld, value_lld); + + if (value_short != INIT_VALUE) + { + printf("thread_func[%d]: " + "ERROR value_short value for this thread is different than the " + "expected initial value (%d): %d\n", + id, INIT_VALUE, value_short); + ASSERT(false); + } + + if (value_int != INIT_VALUE) + { + printf("thread_func[%d]: " + "ERROR value_int value for this thread is different than the " + "expected initial value (%d): %d\n", + id, INIT_VALUE, value_int); + ASSERT(false); + } + + if (value_lld != -INIT_VALUE) + { + printf("thread_func[%d]: " + "ERROR value_lld value for this thread is different than the " + "expected initial value (%d): %lld\n", + id, -INIT_VALUE, value_lld); + ASSERT(false); + } + + printf("thread_func[%d]: setting value_short (at 0x%p) to %d\n", + id, &g_tls_short, value_short + id); + + g_tls_short = value_short + id; + g_tls_variables[id][0] = g_tls_short; + + printf("thread_func[%d]: setting value_int (at 0x%p) to %d\n", + id, &g_tls_int, value_int + id); + + g_tls_int = value_int + id; + g_tls_variables[id][1] = g_tls_int; + + printf("thread_func[%d]: setting value_lld (at 0x%p) to %lld\n", + id, &g_tls_lld, value_lld - id); + + g_tls_lld = value_lld - id; + g_tls_variables[id][2] = g_tls_lld; + + printf("thread_func[%d]: Thread done\n", id); + return NULL; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void sched_thread_local_test(void) +{ + pthread_t thread[TEST_THREADS] = + { + 0 + }; + + int i; + int status; + + printf("sched_thread_local_test: g_tls_int value is: %d\n", g_tls_int); + + /* Create the g_barrier */ + + status = pthread_barrier_init(&g_barrier, NULL, TEST_THREADS); + if (status != OK) + { + printf("sched_thread_local_test: pthread_barrier_init failed, " + "status=%d\n", status); + } + + for (i = 0; i < TEST_THREADS; i++) + { + /* Start three thread instances */ + + printf("sched_thread_local_test: Starting waiter thread %d\n", i); + + status = pthread_create(&thread[i], NULL, + thread_func, (pthread_addr_t)(intptr_t)i); + if (status != 0) + { + printf("sched_thread_local_test: ERROR: " + "Thread %d creation failed: %d\n", i, status); + ASSERT(false); + } + } + + for (i = 0; i < TEST_THREADS; i++) + { + if (thread[i] != (pthread_t)0) + { + pthread_join(thread[i], NULL); + } + } + + for (i = 0; i < TEST_THREADS; i++) + { + printf("sched_thread_local_test: " + "g_tls_variables[thread_%d][g_tls_short] = %lld\n", + i, g_tls_variables[i][0]); + if (g_tls_variables[i][0] != INIT_VALUE + i) + { + printf("sched_thread_local_test: ERROR: " + "g_tls_variables[thread_%d][g_tls_short] = %lld\n", + i, g_tls_variables[i][0]); + ASSERT(false); + } + + printf("sched_thread_local_test: " + "g_tls_variables[thread_%d][g_tls_int] = %lld\n", + i, g_tls_variables[i][1]); + if (g_tls_variables[i][1] != INIT_VALUE + i) + { + printf("sched_thread_local_test: ERROR: " + "g_tls_variables[thread_%d][g_tls_int] = %lld\n", + i, g_tls_variables[i][1]); + ASSERT(false); + } + + printf("sched_thread_local_test: " + "g_tls_variables[thread_%d][g_tls_lld] = %lld\n", + i, g_tls_variables[i][2]); + if (g_tls_variables[i][2] != -INIT_VALUE - i) + { + printf("sched_thread_local_test: ERROR: " + "g_tls_variables[thread_%d][g_tls_lld] = %lld\n", + i, g_tls_variables[i][2]); + ASSERT(false); + } + } + + status = pthread_barrier_destroy(&g_barrier); + if (status != OK) + { + printf("sched_thread_local_test: pthread_barrier_destroy failed, " + "status=%d\n", status); + } +} + +#endif /* CONFIG_SCHED_THREAD_LOCAL */