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 <nlowell@lexmark.com>
This commit is contained in:
Nicholas Lowell 2020-02-14 15:12:03 -05:00 committed by Johan Hedberg
commit 17b19eb810
4 changed files with 114 additions and 0 deletions

View file

@ -522,6 +522,41 @@ int pthread_key_delete(pthread_key_t key);
int pthread_setspecific(pthread_key_t key, const void *value); int pthread_setspecific(pthread_key_t key, const void *value);
void *pthread_getspecific(pthread_key_t key); 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 #ifdef __cplusplus
} }
#endif #endif

View file

@ -597,3 +597,47 @@ int pthread_attr_destroy(pthread_attr_t *attr)
return EINVAL; 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
}

View file

@ -6,5 +6,6 @@ CONFIG_SEM_VALUE_MAX=32767
CONFIG_POSIX_MQUEUE=y CONFIG_POSIX_MQUEUE=y
CONFIG_HEAP_MEM_POOL_SIZE=4096 CONFIG_HEAP_MEM_POOL_SIZE=4096
CONFIG_MAX_THREAD_BYTES=4 CONFIG_MAX_THREAD_BYTES=4
CONFIG_THREAD_NAME=y
CONFIG_SMP=n CONFIG_SMP=n

View file

@ -10,6 +10,10 @@
#include <semaphore.h> #include <semaphore.h>
#include <sys/util.h> #include <sys/util.h>
#ifndef min
#define min(a, b) ((a) < (b)) ? (a) : (b)
#endif
#define N_THR_E 3 #define N_THR_E 3
#define N_THR_T 4 #define N_THR_T 4
#define BOUNCES 64 #define BOUNCES 64
@ -235,6 +239,8 @@ void test_posix_pthread_execution(void)
void *retval, *stackaddr; void *retval, *stackaddr;
size_t stacksize; size_t stacksize;
int serial_threads = 0; int serial_threads = 0;
char name[] = "thread name";
char getName[CONFIG_THREAD_MAX_NAME_LEN];
sem_init(&main_sem, 0, 1); sem_init(&main_sem, 0, 1);
schedparam.sched_priority = CONFIG_NUM_COOP_PRIORITIES - 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]); ret = pthread_attr_destroy(&attr[0]);
zassert_equal(ret, EINVAL, "uninitialized attr destroyed!"); 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 */ /* TESTPOINT: Try creating thread before attr init */
ret = pthread_create(&newthread[0], &attr[0], ret = pthread_create(&newthread[0], &attr[0],
thread_top_exec, NULL); thread_top_exec, NULL);
@ -325,6 +339,26 @@ void test_posix_pthread_execution(void)
zassert_false(ret, "Number of threads exceed max limit"); 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()) { while (!bounce_test_done()) {
sem_wait(&main_sem); sem_wait(&main_sem);
} }