These provide support for `pthread_setname_np()` and `pthread_getname_np(0)` respectively.
These pthread functions are not portable so provide the following variables to gracefully disable the calls:
- `_pthread_setname_np_unsupported_`
- `_pthread_getname_np_unsupported_`
The newly added functions return `F_implement_not` when these unsupported defines are set.
This allows for programs that call these to not really care if the thread naming support is present.
They can call the function and if it works, then it works and if it doesn't work, then it doesn't work.
#defines -D_di_libcap_
#defines -D_f_file_rename_use_renameat2_
+#defines -D_pthread_getname_np_unsupported_ -D_pthread_setname_np_unsupported_
defines -D_libcap_legacy_only_
defines-clang -D_clang_not_a_compile_time_constant_workaround_
defines-android -D_di_f_thread_attribute_affinity_get_ -D_di_f_thread_attribute_affinity_set_ -D_di_f_thread_attribute_concurrency_get_ -D_di_f_thread_attribute_concurrency_set_ -D_di_f_thread_attribute_default_get_ -D_di_f_thread_attribute_default_set_ -D_di_f_thread_cancel_ -D_di_f_thread_cancel_state_set_ -D_di_f_thread_cancel_test_ -D_di_f_thread_join_try_ -D_di_f_thread_join_timed_ -D_pthread_mutex_prioceiling_unsupported_ -D_di_f_thread_semaphore_file_close_ -D_di_f_thread_semaphore_file_open_ -D_di_f_thread_semaphore_file_delete_ -D_di_f_thread_cancel_type_set_
#defines -D_di_libcap_
#defines -D_f_file_rename_use_renameat2_
+#defines -D_pthread_getname_np_unsupported_ -D_pthread_setname_np_unsupported_
defines -D_libcap_legacy_only_
defines-clang -D_clang_not_a_compile_time_constant_workaround_
defines-android -D_di_f_thread_attribute_affinity_get_ -D_di_f_thread_attribute_affinity_set_ -D_di_f_thread_attribute_concurrency_get_ -D_di_f_thread_attribute_concurrency_set_ -D_di_f_thread_attribute_default_get_ -D_di_f_thread_attribute_default_set_ -D_di_f_thread_cancel_ -D_di_f_thread_cancel_state_set_ -D_di_f_thread_cancel_test_ -D_di_f_thread_join_try_ -D_di_f_thread_join_timed_ -D_pthread_mutex_prioceiling_unsupported_ -D_di_f_thread_semaphore_file_close_ -D_di_f_thread_semaphore_file_open_ -D_di_f_thread_semaphore_file_delete_ -D_di_f_thread_cancel_type_set_
}
#endif // _di_f_thread_mutex_lock_try_
+#if defined(_pthread_setname_np_unsupported_) && !defined(_di_f_thread_name_set_)
+ f_status_t f_thread_name_set(const f_thread_id_t id, const f_string_static_t name) {
+ return F_status_set_error(F_implement_not);
+ }
+#elif !defined(_di_f_thread_name_set_)
+ f_status_t f_thread_name_set(const f_thread_id_t id, const f_string_static_t name) {
+
+ if (!name.used || !name.string) return F_data_not;
+
+ const int error = pthread_setname_np(id, name.string);
+
+ if (error) {
+ if (error == ERANGE) return F_status_set_error(F_buffer_overflow);
+
+ return F_status_set_error(F_failure);
+ }
+
+ return F_okay;
+ }
+#endif // defined(_pthread_getname_np_unsupported_) && !defined(_di_f_thread_name_get_)
+
+#if defined(_pthread_getname_np_unsupported_) && !defined(_di_f_thread_name_get_)
+ f_status_t f_thread_name_get(const f_thread_id_t id, f_string_static_t * const name) {
+ #ifndef _di_level_0_parameter_checking_
+ if (!name) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ return F_status_set_error(F_implement_not);
+ }
+#elif !defined(_di_f_thread_name_get_)
+ f_status_t f_thread_name_get(const f_thread_id_t id, f_string_static_t * const name) {
+ #ifndef _di_level_0_parameter_checking_
+ if (!name) return F_status_set_error(F_parameter);
+ #endif // _di_level_0_parameter_checking_
+
+ if (name->size) {
+ if (name->used > name->size) return F_status_set_error(F_parameter);
+ if (name->used == name->size) return F_status_set_error(F_buffer_underflow);
+ }
+ else if (!name->used) return F_status_set_error(F_buffer_underflow);
+
+ const int error = name->size
+ ? pthread_getname_np(id, name->string + name->used, name->size - name->used)
+ : pthread_getname_np(id, name->string, name->used);
+
+ if (error) {
+ if (error == ERANGE) return F_status_set_error(F_buffer_overflow);
+
+ return F_status_set_error(F_failure);
+ }
+
+ return F_okay;
+ }
+#endif // _di_f_thread_name_get_
+
#if defined(_pthread_mutex_prioceiling_unsupported_) && !defined(_di_f_thread_mutex_priority_ceiling_get_)
f_status_t f_thread_mutex_priority_ceiling_get(f_thread_mutex_t * const mutex, int * const ceiling) {
#ifndef _di_level_0_parameter_checking_
#endif // _di_f_thread_mutex_lock_try_
/**
+ * Set the name of the thread.
+ *
+ * This uses a non-portal call and may do nothing on systems that do not support custom thread names.
+ *
+ * @param id
+ * The thread to name.
+ * @param name
+ * The thread name.
+ *
+ * This must be a NULL terminated string.
+ *
+ * @return
+ * F_data_not if name.used is 0 or name.string is NULL.
+ * F_okay on success.
+ *
+ * F_buffer_overflow (with error bit) If the given name is larged than is allowed for a thread name.
+ * F_parameter (with error bit) if a parameter is invalid.
+ * F_implement_not (with error bit) if pthread_setname_np() is not available.
+ *
+ * F_failure (with error bit) on any other error.
+ *
+ * @see pthread_setname_np()
+ */
+#ifndef _di_f_thread_name_set_
+ extern f_status_t f_thread_name_set(const f_thread_id_t id, const f_string_static_t name);
+#endif // _di_f_thread_name_set_
+
+/**
+ * Set the name of the thread.
+ *
+ * This uses a non-portal call and may do nothing on systems that do not support custom thread names.
+ *
+ * @param id
+ * The thread to name.
+ * @param name
+ * The thread name.
+ *
+ * The pthread_getname_np() uses a static array so this variable is processed as follows:
+ * - If name.size is 0, then this is considered a static string and then name.used is considered the length.
+ * - If name.used is also 0, then this is an error.
+ * - If name.size is greater than 0, then the name.size - name.used is the length.
+ * - If name.used >= name.size, then this is an error.
+ * - The thread name is assigned to the name.string as follows:
+ * - If name.size is 0, then name.string is replaced with the thread name and is always NULL terminated (at name.used - 1; if name.used is 1 then the string.used[0] will always be NULL).
+ * - If name.size > 0, then the thread name is appended onto the string at position of name.used and then the name.used is incremented (this is not NULL terminated).
+ *
+ * Must not be NULL.
+ *
+ * @return
+ * F_okay on success.
+ *
+ * F_buffer_overflow (with error bit) if name is too small to fit the thread name.
+ * F_buffer_underflow (with error bit) if name.size > 0 and name.used == name.size or name.size == 0 and name.used == 0.
+ * F_parameter (with error bit) if a parameter is invalid.
+ *
+ * F_failure (with error bit) on any other error.
+ *
+ * @see pthread_getname_np()
+ */
+#ifndef _di_f_thread_name_get_
+ extern f_status_t f_thread_name_get(const f_thread_id_t id, f_string_static_t * const name);
+#endif // _di_f_thread_name_get_
+
+/**
* Call the given routine only one time and never again.
*
* Subsequent calls will not call the given routine.
_di_thread_support_ disables thread support, which is intended to disable this entire f_thread project. This is not directly used by this library, but is instead used by other libraries to not include f_thread (such as special compilations like monolithic). Future versions may potentially support this, providing stubs.
_pthread_attr_unsupported_ Disable non-portable functionality associated with pthread_attr.
+_pthread_getname_np_unsupported_ Disable GNU specific pthread_getname_np().
_pthread_mutex_prioceiling_unsupported_ Disable mutex_prioceiling related functionality for systems that do not support it.
+_pthread_setname_np_unsupported_ Disable GNU specific pthread_setname_np().
_pthread_sigqueue_unsupported_ Disable GNU specific sigqueue().
environment LANG LC_ALL LC_COLLATE LC_CTYPE LC_FASTMSG LC_MESSAGES LC_MONETARY LC_NUMERIC LC_TIME LOCPATH NLSPATH
defines -D_pthread_attr_unsupported_ -D_pthread_sigqueue_unsupported_
+#defines -D_pthread_getname_np_unsupported_ -D_pthread_setname_np_unsupported_
flags -O2 -g -fdiagnostics-color=always -Wno-logical-not-parentheses -Wno-parentheses -Wno-missing-braces
flags -fstack-clash-protection -fno-delete-null-pointer-checks
flags -Wl,--wrap=pthread_getattr_default_np
flags -Wl,--wrap=pthread_getcpuclockid
flags -Wl,--wrap=pthread_getconcurrency
+flags -Wl,--wrap=pthread_getname_np
flags -Wl,--wrap=pthread_getschedparam
flags -Wl,--wrap=pthread_getspecific
flags -Wl,--wrap=pthread_join
flags -Wl,--wrap=pthread_setcancelstate
flags -Wl,--wrap=pthread_setcanceltype
flags -Wl,--wrap=pthread_setconcurrency
+flags -Wl,--wrap=pthread_setname_np
flags -Wl,--wrap=pthread_setschedparam
flags -Wl,--wrap=pthread_setschedprio
flags -Wl,--wrap=pthread_setspecific
build_sources_program test-thread-spin_create.c test-thread-spin_delete.c
build_sources_program test-thread-spin_lock.c test-thread-spin_lock_try.c test-thread-spin_unlock.c
build_sources_program test-thread-mutex_priority_ceiling_get.c test-thread-mutex_priority_ceiling_set.c
+build_sources_program test-thread-name_get.c test-thread-name_set.c
build_sources_program test-thread-once.c
build_sources_program test-thread-semaphore_create.c test-thread-semaphore_delete.c
build_sources_program test-thread-semaphore_file_open.c test-thread-semaphore_file_close.c test-thread-semaphore_file_delete.c
return 0;
}
+int __wrap_pthread_getname_np(pthread_t thread, char name[], size_t size) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ return mock_type(int);
+ }
+
+ return 0;
+}
+
int __wrap_pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param) {
const bool failure = mock_type(bool);
return 0;
}
+int __wrap_pthread_setname_np(pthread_t thread, const char *name) {
+
+ const bool failure = mock_type(bool);
+
+ if (failure) {
+ return mock_type(int);
+ }
+
+ return 0;
+}
+
int __wrap_pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param) {
const bool failure = mock_type(bool);
extern int __wrap_pthread_getattr_default_np(pthread_attr_t *attr);
extern int __wrap_pthread_getconcurrency(void);
extern int __wrap_pthread_getcpuclockid(pthread_t thread, clockid_t *clock_id);
+extern int __wrap_pthread_getname_np(pthread_t thread, char name[], size_t size);
extern int __wrap_pthread_getschedparam(pthread_t pthread, int *policy, struct sched_param *param);
extern void *__wrap_pthread_getspecific(pthread_key_t key);
extern int __wrap_pthread_join(pthread_t pthread, void **value_ptr);
extern int __wrap_pthread_setcancelstate(int state, int *oldstate);
extern int __wrap_pthread_setcanceltype(int type, int *oldtype);
extern int __wrap_pthread_setconcurrency(int new_level);
+extern int __wrap_pthread_setname_np(pthread_t thread, const char *name);
extern int __wrap_pthread_setschedparam(pthread_t pthread, int policy, const struct sched_param *param);
extern int __wrap_pthread_setschedprio(pthread_t thread, int prio);
extern int __wrap_pthread_setspecific(pthread_key_t key, const void *value);
--- /dev/null
+#include "test-thread.h"
+#include "test-thread-name_get.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_thread_name_get__fails(void **state) {
+
+ const f_thread_id_t id = f_thread_id_t_initialize;
+ f_string_static_t test = macro_f_string_static_t_initialize_1("test", 0, 4);
+ f_string_static_t no_size_no_used = macro_f_string_static_t_initialize_1(0, 0, 0);
+ f_string_static_t size_is_used = macro_f_string_static_t_initialize_1("test", 4, 4);
+ f_string_static_t size_less_used = macro_f_string_static_t_initialize_1("test", 2, 4);
+
+ int errnos[] = {
+ ERANGE,
+ mock_errno_generic,
+ };
+
+ f_status_t statuss[] = {
+ F_buffer_overflow,
+ F_failure,
+ };
+
+ for (uint8_t i = 0; i < 2; ++i) {
+
+ will_return(__wrap_pthread_getname_np, true);
+ will_return(__wrap_pthread_getname_np, errnos[i]);
+
+ const f_status_t status = f_thread_name_get(id, &test);
+
+ assert_int_equal(status, F_status_set_error(statuss[i]));
+ } // for
+
+ {
+ const f_status_t status = f_thread_name_get(id, &no_size_no_used);
+
+ assert_int_equal(status, F_status_set_error(F_buffer_underflow));
+ }
+
+ {
+ const f_status_t status = f_thread_name_get(id, &size_is_used);
+
+ assert_int_equal(status, F_status_set_error(F_buffer_underflow));
+ }
+
+ {
+ const f_status_t status = f_thread_name_get(id, &size_less_used);
+
+ assert_int_equal(status, F_status_set_error(F_parameter));
+ }
+}
+
+void test__f_thread_name_get__parameter_checking(void **state) {
+
+ const f_thread_id_t id = f_thread_id_t_initialize;
+
+ {
+ const f_status_t status = f_thread_name_get(id, 0);
+
+ assert_int_equal(status, F_status_set_error(F_parameter));
+ }
+}
+
+void test__f_thread_name_get__works(void **state) {
+
+ const f_thread_id_t id = f_thread_id_t_initialize;
+ f_string_static_t test = macro_f_string_static_t_initialize_1("test", 0, 4);
+
+ {
+ will_return(__wrap_pthread_getname_np, false);
+
+ const f_status_t status = f_thread_name_get(id, &test);
+
+ assert_int_equal(status, F_okay);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Thread
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the thread project.
+ */
+#ifndef _TEST__F_thread__name_get_h
+#define _TEST__F_thread__name_get_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_thread_name_get()
+ */
+extern void test__f_thread_name_get__fails(void **state);
+
+/**
+ * Test that parameter checking works as expected.
+ *
+ * @see f_thread_name_get()
+ */
+extern void test__f_thread_name_get__parameter_checking(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_thread_name_get()
+ */
+extern void test__f_thread_name_get__works(void **state);
+
+#endif // _TEST__F_thread__name_get_h
--- /dev/null
+#include "test-thread.h"
+#include "test-thread-name_set.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void test__f_thread_name_set__fails(void **state) {
+
+ const f_thread_id_t id = f_thread_id_t_initialize;
+ const f_string_static_t test = macro_f_string_static_t_initialize_1("test", 0, 4);
+
+ int errnos[] = {
+ ERANGE,
+ mock_errno_generic,
+ };
+
+ f_status_t statuss[] = {
+ F_buffer_overflow,
+ F_failure,
+ };
+
+ for (uint8_t i = 0; i < 2; ++i) {
+
+ will_return(__wrap_pthread_setname_np, true);
+ will_return(__wrap_pthread_setname_np, errnos[i]);
+
+ const f_status_t status = f_thread_name_set(id, test);
+
+ assert_int_equal(status, F_status_set_error(statuss[i]));
+ } // for
+}
+
+void test__f_thread_name_set__works(void **state) {
+
+ const f_thread_id_t id = f_thread_id_t_initialize;
+ const f_string_static_t test = macro_f_string_static_t_initialize_1("test", 0, 4);
+ const f_string_static_t no_used = macro_f_string_static_t_initialize_1("test", 0, 0);
+ const f_string_static_t no_string = macro_f_string_static_t_initialize_1(0, 0, 1);
+
+ {
+ will_return(__wrap_pthread_setname_np, false);
+
+ const f_status_t status = f_thread_name_set(id, test);
+
+ assert_int_equal(status, F_okay);
+ }
+
+ {
+ const f_status_t status = f_thread_name_set(id, no_used);
+
+ assert_int_equal(status, F_data_not);
+ }
+
+ {
+ const f_status_t status = f_thread_name_set(id, no_string);
+
+ assert_int_equal(status, F_data_not);
+ }
+}
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
--- /dev/null
+/**
+ * FLL - Level 0
+ *
+ * Project: Thread
+ * API Version: 0.7
+ * Licenses: lgpl-2.1-or-later
+ *
+ * Test the thread project.
+ */
+#ifndef _TEST__F_thread__name_set_h
+#define _TEST__F_thread__name_set_h
+
+/**
+ * Test that function fails.
+ *
+ * @see f_thread_name_set()
+ */
+extern void test__f_thread_name_set__fails(void **state);
+
+/**
+ * Test that function works.
+ *
+ * @see f_thread_name_set()
+ */
+extern void test__f_thread_name_set__works(void **state);
+
+#endif // _TEST__F_thread__name_set_h
cmocka_unit_test(test__f_thread_mutex_priority_ceiling_set__fails),
cmocka_unit_test(test__f_thread_mutex_priority_ceiling_set__works),
+ cmocka_unit_test(test__f_thread_name_get__fails),
+ cmocka_unit_test(test__f_thread_name_get__works),
+
+ cmocka_unit_test(test__f_thread_name_set__fails),
+ cmocka_unit_test(test__f_thread_name_set__works),
+
cmocka_unit_test(test__f_thread_once__fails),
cmocka_unit_test(test__f_thread_once__works),
cmocka_unit_test(test__f_thread_mutex_priority_ceiling_get__parameter_checking),
cmocka_unit_test(test__f_thread_mutex_priority_ceiling_set__parameter_checking),
+ cmocka_unit_test(test__f_thread_name_get__parameter_checking),
+ // f_thread_name_set() doesn't use parameter checking.
+
cmocka_unit_test(test__f_thread_once__parameter_checking),
cmocka_unit_test(test__f_thread_scheduler_parameter_get__parameter_checking),
#include "test-thread-mutex_lock_try.h"
#include "test-thread-mutex_priority_ceiling_get.h"
#include "test-thread-mutex_priority_ceiling_set.h"
+#include "test-thread-name_get.h"
+#include "test-thread-name_set.h"
#include "test-thread-once.h"
#include "test-thread-scheduler_parameter_get.h"
#include "test-thread-scheduler_parameter_set.h"