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/test/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 :
49 : void
50 41 : set_current_thread_name(char const* name) noexcept
51 : {
52 : #if defined(_WIN32)
53 : // SetThreadDescription requires Windows 10 1607+. Older Windows versions
54 : // are unsupported; the program may fail to link on those systems.
55 :
56 : // Query required buffer size for UTF-8 to wide conversion.
57 : int required = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0);
58 : if(required <= 0)
59 : return;
60 :
61 : // Allocate and convert; catch exceptions to maintain noexcept.
62 : std::wstring wname;
63 : try
64 : {
65 : wname.resize(static_cast<std::size_t>(required));
66 : }
67 : catch(...)
68 : {
69 : return;
70 : }
71 :
72 : if(MultiByteToWideChar(CP_UTF8, 0, name, -1, wname.data(), required) <= 0)
73 : return;
74 :
75 : // Ignore return value: thread naming is best-effort for debugging.
76 : (void)SetThreadDescription(GetCurrentThread(), wname.c_str());
77 : #elif defined(__APPLE__)
78 : // macOS pthread_setname_np takes only the name (no thread handle)
79 : // and has a 64 char limit (63 + null terminator)
80 : char truncated[64];
81 : std::strncpy(truncated, name, 63);
82 : truncated[63] = '\0';
83 :
84 : // Ignore return value: thread naming is best-effort for debugging.
85 : (void)pthread_setname_np(truncated);
86 : #elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
87 : // pthread_setname_np has 16 char limit (15 + null terminator)
88 : char truncated[16];
89 41 : std::strncpy(truncated, name, 15);
90 41 : truncated[15] = '\0';
91 :
92 : // Ignore return value: thread naming is best-effort for debugging.
93 41 : (void)pthread_setname_np(pthread_self(), truncated);
94 : #else
95 : (void)name;
96 : #endif
97 41 : }
98 :
99 : } // capy
100 : } // boost
|