diff --git a/CMakeLists.txt b/CMakeLists.txt index 51f1f1b71..cf95b2e98 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -197,7 +197,6 @@ check_function_exists(pthread_attr_setcpupercent_np HAVE_PTHREAD_ATTR_SETCPUPERC check_function_exists(pthread_yield_np HAVE_PTHREAD_YIELD_NP) check_function_exists(pthread_main_np HAVE_PTHREAD_MAIN_NP) check_function_exists(pthread_workqueue_setdispatch_np HAVE_PTHREAD_WORKQUEUE_SETDISPATCH_NP) -check_function_exists(pthread_setname_np HAVE_PTHREAD_SETNAME_NP) check_function_exists(strlcpy HAVE_STRLCPY) check_function_exists(sysconf HAVE_SYSCONF) check_function_exists(arc4random HAVE_ARC4RANDOM) @@ -270,6 +269,14 @@ if (HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME) add_compile_definitions($<$:_GNU_SOURCE=1>) endif() check_symbol_exists(__printflike "bsd/sys/cdefs.h" HAVE_PRINTFLIKE) +if(UNIX) + list(APPEND CMAKE_REQUIRED_LIBRARIES Threads::Threads) + check_symbol_exists(pthread_setname_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SETNAME_NP) + check_symbol_exists(pthread_getname_np "pthread.h;pthread_np.h" HAVE_PTHREAD_GETNAME_NP) + check_symbol_exists(pthread_get_name_np "pthread.h;pthread_np.h" HAVE_PTHREAD_GET_NAME_NP) + check_symbol_exists(pthread_set_name_np "pthread.h;pthread_np.h" HAVE_PTHREAD_SET_NAME_NP) + list(REMOVE_ITEM CMAKE_REQUIRED_LIBRARIES Threads::Threads) +endif() if(ANDROID) set(ENABLE_DTRACE_DEFAULT OFF) diff --git a/cmake/config.h.in b/cmake/config.h.in index fc630ea67..f4ccf5314 100644 --- a/cmake/config.h.in +++ b/cmake/config.h.in @@ -211,6 +211,15 @@ /* Define to 1 if you have the `pthread_setname_np' function. */ #cmakedefine01 HAVE_PTHREAD_SETNAME_NP +/* Define to 1 if you have the `pthread_getname_np' function. */ +#cmakedefine01 HAVE_PTHREAD_GETNAME_NP + +/* Define to 1 if you have the `pthread_set_name_np' function. */ +#cmakedefine01 HAVE_PTHREAD_SET_NAME_NP + +/* Define to 1 if you have the `pthread_get_name_np' function. */ +#cmakedefine01 HAVE_PTHREAD_GET_NAME_NP + /* Define to use non-portable pthread TSD optimizations for Mac OS X) */ #cmakedefine USE_APPLE_TSD_OPTIMIZATIONS diff --git a/src/queue.c b/src/queue.c index fe8344c15..0f5c9199b 100644 --- a/src/queue.c +++ b/src/queue.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008-2013 Apple Inc. All rights reserved. + * Copyright (c) 2008-2026 Apple Inc. All rights reserved. * * @APPLE_APACHE_LICENSE_HEADER_START@ * @@ -6246,6 +6246,12 @@ _dispatch_worker_thread(void *context) dispatch_priority_t pri = dq->dq_priority; pthread_priority_t pp = _dispatch_get_priority(); + #if HAVE_PTHREAD_SETNAME_NP + pthread_setname_np(pthread_self(), "DispatchWorker"); + #elif HAVE_PTHREAD_SET_NAME_NP + pthread_set_name_np(pthread_self(), "DispatchWorker"); + #endif // HAVE_PTHREAD_SETNAME_NP + #if defined(__linux__) // The Linux kernel does not have a direct analogue to the QoS-based // thread policy engine found in XNU. @@ -6263,21 +6269,6 @@ _dispatch_worker_thread(void *context) pp = _dispatch_priority_to_pp_strip_flags(pri); int nice = _dispatch_pp_to_nice(pp); - #if HAVE_PTHREAD_SETNAME_NP - // pthread thread names are restricted to just 16 characters - // including NUL. Truncate the label name from the beginning as it tends - // to be more unique at the end. - size_t label_length = strlen(dq->dq_label); - const char * thread_name = dq->dq_label; - if (label_length > 0) { - const size_t max_thread_name_length = 16 - 1; // minus the NUL byte; - thread_name = thread_name + (label_length - max_thread_name_length); - } else { - thread_name = "DispatchWorker"; - } - pthread_setname_np(pthread_self(), thread_name); - #endif // HAVE_PTHREAD_SETNAME_NP - errno = 0; int rc = setpriority(PRIO_PROCESS, 0, nice); if (rc != -1 || errno == 0) { diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index ed5d2f444..64deaeca6 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -163,6 +163,10 @@ if(EXTENDED_TEST_SUITE) endif() # add C tests for platform-specific functionality when applicable +if(UNIX AND (HAVE_PTHREAD_SETNAME_NP OR HAVE_PTHREAD_SET_NAME_NP)) + list(APPEND DISPATCH_C_TESTS + thread_name) +endif() if(APPLE) list(APPEND DISPATCH_C_TESTS deadname diff --git a/tests/dispatch_thread_name.c b/tests/dispatch_thread_name.c new file mode 100644 index 000000000..b671c652a --- /dev/null +++ b/tests/dispatch_thread_name.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2026 Apple Inc. All rights reserved. + * + * @APPLE_APACHE_LICENSE_HEADER_START@ + * + * Licensed 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. + * + * @APPLE_APACHE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include + +#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) +#include +#include +#endif +#if defined(__OpenBSD__) || defined(__FreeBSD__) +#include +#endif + +#include + +#if HAVE_PTHREAD_SET_NAME_NP && !HAVE_PTHREAD_SETNAME_NP +#define pthread_setname_np pthread_set_name_np +#endif +#if HAVE_PTHREAD_GET_NAME_NP && !HAVE_PTHREAD_GETNAME_NP +#define pthread_getname_np pthread_get_name_np +#endif + +#include +#include "dispatch_test.h" + +#define ITERATIONS 10 + +static void +set_current_thread_name(const char *name) +{ +#if defined(__APPLE__) + pthread_setname_np(name); +#else + pthread_setname_np(pthread_self(), name); +#endif +} + +int +main(void) +{ + dispatch_test_start("Dispatch Thread Name"); + + const char *parent_name = "TestParentName"; + set_current_thread_name(parent_name); + + dispatch_group_t group = dispatch_group_create(); + assert(group); + + dispatch_queue_t q = dispatch_get_global_queue(0, 0); + + for (int i = 0; i < ITERATIONS; i++) { + dispatch_group_async(group, q, ^{ + char thread_name[64] = {0}; + pthread_getname_np(pthread_self(), thread_name, sizeof(thread_name)); + fprintf(stderr, "Worker thread name: '%s'\n", thread_name); + test_long("worker thread name must not be empty", + strlen(thread_name) > 0, 1); + test_long("worker thread must not inherit parent name", + strcmp(thread_name, parent_name) != 0, 1); + }); + } + + test_group_wait(group); + dispatch_release(group); + + test_stop(); + return 0; +}