Line data Source code
1 : //
2 : // Copyright (c) 2026 Michael Vandeberg
3 : //
4 : // Distributed under the Boost Software License, Version 1.0. (See accompanying
5 : // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6 : //
7 : // Official repository: https://github.com/cppalliance/capy
8 : //
9 :
10 : #include <boost/capy/detail/thread_name.hpp>
11 :
12 : #if defined(_WIN32)
13 :
14 : #ifndef NOMINMAX
15 : #define NOMINMAX
16 : #endif
17 : #include <windows.h>
18 : #include <string>
19 :
20 : #elif defined(__APPLE__)
21 :
22 : #include <pthread.h>
23 : #include <cstring>
24 :
25 : #elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
26 :
27 : #include <pthread.h>
28 : #include <cstring>
29 :
30 : #endif
31 :
32 : /*
33 : Platform-specific thread naming implementation.
34 :
35 : Each platform has a different API and name length limit:
36 : - Windows: SetThreadDescription with UTF-8 to UTF-16 conversion (no limit)
37 : - macOS: pthread_setname_np(name) with 63-char limit
38 : - Linux/BSD: pthread_setname_np(thread, name) with 15-char limit
39 :
40 : All operations are best-effort and silently fail on error, since thread
41 : naming is purely for debugging visibility and should never affect program
42 : correctness. The noexcept guarantee is maintained by catching exceptions
43 : from std::wstring allocation on Windows.
44 : */
45 :
46 : namespace boost {
47 : namespace capy {
48 : namespace detail {
49 :
50 : void
51 39 : set_current_thread_name(char const* name) noexcept
52 : {
53 : #if defined(_WIN32)
54 : // SetThreadDescription requires Windows 10 1607+. Older Windows versions
55 : // are unsupported; the program may fail to link on those systems.
56 :
57 : // Query required buffer size for UTF-8 to wide conversion.
58 : int required = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0);
59 : if(required <= 0)
60 : return;
61 :
62 : // Allocate and convert; catch exceptions to maintain noexcept.
63 : std::wstring wname;
64 : try
65 : {
66 : wname.resize(static_cast<std::size_t>(required));
67 : }
68 : catch(...)
69 : {
70 : return;
71 : }
72 :
73 : if(MultiByteToWideChar(CP_UTF8, 0, name, -1, wname.data(), required) <= 0)
74 : return;
75 :
76 : // Ignore return value: thread naming is best-effort for debugging.
77 : (void)SetThreadDescription(GetCurrentThread(), wname.c_str());
78 : #elif defined(__APPLE__)
79 : // macOS pthread_setname_np takes only the name (no thread handle)
80 : // and has a 64 char limit (63 + null terminator)
81 : char truncated[64];
82 : std::strncpy(truncated, name, 63);
83 : truncated[63] = '\0';
84 :
85 : // Ignore return value: thread naming is best-effort for debugging.
86 : (void)pthread_setname_np(truncated);
87 : #elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
88 : // pthread_setname_np has 16 char limit (15 + null terminator)
89 : char truncated[16];
90 39 : std::strncpy(truncated, name, 15);
91 39 : truncated[15] = '\0';
92 :
93 : // Ignore return value: thread naming is best-effort for debugging.
94 39 : (void)pthread_setname_np(pthread_self(), truncated);
95 : #else
96 : (void)name;
97 : #endif
98 39 : }
99 :
100 : } // detail
101 : } // capy
102 : } // boost
|