From 17b19eb810e2429bf91fb231bbeae4a3c82bf0dc Mon Sep 17 00:00:00 2001 From: Nicholas Lowell Date: Fri, 14 Feb 2020 15:12:03 -0500 Subject: [PATCH] pthread: add setname/getname glibc extensions Adding the ability to set and get pthread names by defining some non-standard extension functions that were first introduced by Glibc. Similar to zephyr thread naming, these allow for thread tracking and debugging even when using the more portable posix API. Though Glibc was the originator, the current POSIX functions have return codes based on Oracle's adopted spec, so these functions follow suit. The Oracle and Glibc function prototypes match. Signed-off-by: Nicholas Lowell --- include/posix/pthread.h | 35 +++++++++++++++++++++++++ lib/posix/pthread.c | 44 ++++++++++++++++++++++++++++++++ tests/posix/common/prj.conf | 1 + tests/posix/common/src/pthread.c | 34 ++++++++++++++++++++++++ 4 files changed, 114 insertions(+) diff --git a/include/posix/pthread.h b/include/posix/pthread.h index b93b82861d3..12707894db0 100644 --- a/include/posix/pthread.h +++ b/include/posix/pthread.h @@ -522,6 +522,41 @@ int pthread_key_delete(pthread_key_t key); int pthread_setspecific(pthread_key_t key, const void *value); void *pthread_getspecific(pthread_key_t key); +/* Glibc / Oracle Extension Functions */ + +/** + * @brief Set name of POSIX thread. + * + * Non-portable, extension function that conforms with most + * other definitions of this function. + * + * @param thread POSIX thread to set name + * @param name Name string + * @retval 0 Success + * @retval ESRCH Thread does not exist + * @retval EINVAL Name buffer is NULL + * @retval Negative value if kernel function error + * + */ +int pthread_setname_np(pthread_t thread, const char *name); + +/** + * @brief Get name of POSIX thread and store in name buffer + * that is of size len. + * + * Non-portable, extension function that conforms with most + * other definitions of this function. + * + * @param thread POSIX thread to obtain name information + * @param name Destination buffer + * @param len Destination buffer size + * @retval 0 Success + * @retval ESRCH Thread does not exist + * @retval EINVAL Name buffer is NULL + * @retval Negative value if kernel function error + */ +int pthread_getname_np(pthread_t thread, char *name, size_t len); + #ifdef __cplusplus } #endif diff --git a/lib/posix/pthread.c b/lib/posix/pthread.c index 2178b0518fd..ca4ed4ae732 100644 --- a/lib/posix/pthread.c +++ b/lib/posix/pthread.c @@ -597,3 +597,47 @@ int pthread_attr_destroy(pthread_attr_t *attr) return EINVAL; } + +int pthread_setname_np(pthread_t thread, const char *name) +{ +#ifdef CONFIG_THREAD_NAME + k_tid_t kthread = (k_tid_t)thread; + + if (kthread == NULL) { + return ESRCH; + } + + if (name == NULL) { + return EINVAL; + } + + return k_thread_name_set(kthread, name); +#else + ARG_UNUSED(thread); + ARG_UNUSED(name); + return 0; +#endif +} + +int pthread_getname_np(pthread_t thread, char *name, size_t len) +{ +#ifdef CONFIG_THREAD_NAME + k_tid_t kthread = (k_tid_t)thread; + + if (kthread == NULL) { + return ESRCH; + } + + if (name == NULL) { + return EINVAL; + } + + memset(name, '\0', len); + return k_thread_name_copy(kthread, name, len-1); +#else + ARG_UNUSED(thread); + ARG_UNUSED(name); + ARG_UNUSED(len); + return 0; +#endif +} diff --git a/tests/posix/common/prj.conf b/tests/posix/common/prj.conf index 4f6a845b21c..f01ae5140a9 100644 --- a/tests/posix/common/prj.conf +++ b/tests/posix/common/prj.conf @@ -6,5 +6,6 @@ CONFIG_SEM_VALUE_MAX=32767 CONFIG_POSIX_MQUEUE=y CONFIG_HEAP_MEM_POOL_SIZE=4096 CONFIG_MAX_THREAD_BYTES=4 +CONFIG_THREAD_NAME=y CONFIG_SMP=n diff --git a/tests/posix/common/src/pthread.c b/tests/posix/common/src/pthread.c index 2b73b4ec77d..d055ee7eeb2 100644 --- a/tests/posix/common/src/pthread.c +++ b/tests/posix/common/src/pthread.c @@ -10,6 +10,10 @@ #include #include +#ifndef min +#define min(a, b) ((a) < (b)) ? (a) : (b) +#endif + #define N_THR_E 3 #define N_THR_T 4 #define BOUNCES 64 @@ -235,6 +239,8 @@ void test_posix_pthread_execution(void) void *retval, *stackaddr; size_t stacksize; int serial_threads = 0; + char name[] = "thread name"; + char getName[CONFIG_THREAD_MAX_NAME_LEN]; sem_init(&main_sem, 0, 1); schedparam.sched_priority = CONFIG_NUM_COOP_PRIORITIES - 1; @@ -283,6 +289,14 @@ void test_posix_pthread_execution(void) ret = pthread_attr_destroy(&attr[0]); zassert_equal(ret, EINVAL, "uninitialized attr destroyed!"); + /* TESTPOINT: Try getting thread name before init */ + ret = pthread_getname_np(newthread[0], getName, sizeof(getName)); + zassert_equal(ret, ESRCH, "uninitialized getname!"); + + /* TESTPOINT: Try setting thread name before init */ + ret = pthread_setname_np(newthread[0], name); + zassert_equal(ret, ESRCH, "uninitialized setname!"); + /* TESTPOINT: Try creating thread before attr init */ ret = pthread_create(&newthread[0], &attr[0], thread_top_exec, NULL); @@ -325,6 +339,26 @@ void test_posix_pthread_execution(void) zassert_false(ret, "Number of threads exceed max limit"); } + /* TESTPOINT: Try getting thread name with no buffer */ + ret = pthread_getname_np(newthread[0], NULL, sizeof(getName)); + zassert_equal(ret, EINVAL, "uninitialized getname!"); + + /* TESTPOINT: Try setting thread name with no buffer */ + ret = pthread_setname_np(newthread[0], NULL); + zassert_equal(ret, EINVAL, "uninitialized setname!"); + + /* TESTPOINT: Try setting thread name */ + ret = pthread_setname_np(newthread[0], name); + zassert_false(ret, "Set name failed!"); + + /* TESTPOINT: Try getting thread name */ + ret = pthread_getname_np(newthread[0], getName, sizeof(getName)); + zassert_false(ret, "Get name failed!"); + + /* TESTPOINT: Thread names match */ + ret = strncmp(name, getName, min(strlen(name), strlen(getName))); + zassert_false(ret, "Thread names don't match!"); + while (!bounce_test_done()) { sem_wait(&main_sem); }