This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx-apps.git
The following commit(s) were added to refs/heads/master by this push:
new 231827e84 ostest: Add test for GCC's tls (CONFIG_SCHED_THREAD_LOCAL)
231827e84 is described below
commit 231827e84e300a8fccde12c5ee5404ba9ac7fc44
Author: Tiago Medicci <[email protected]>
AuthorDate: Mon Dec 16 15:28:55 2024 -0300
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(+)
diff --git a/testing/ostest/Makefile b/testing/ostest/Makefile
index fcd04665d..18fc1c19d 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 f369319c2..02ed90c7b 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 c0f37dbc9..4a3902c8b 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 000000000..d2fc08a31
--- /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 <nuttx/config.h>
+#include <nuttx/tls.h>
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#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 */