NUMA++ 0.11.0
Loading...
Searching...
No Matches
thread.cpp
Go to the documentation of this file.
1/**
2 * @file
3 * @ingroup numapp_thread
4 * @copyright ESO 2024 - European Southern Observatory
5 *
6 * @brief Definition of thread functions
7 */
8#include <cstring>
9
10#include <sys/prctl.h>
11#include <sys/resource.h>
12#include <sys/syscall.h>
13#include <sys/types.h>
14#include <unistd.h>
15
16#include <numapp/thread.hpp>
17
18namespace {
19static constexpr const std::size_t THREAD_NAME_MAX_SIZE = 16;
20}
21
22namespace numapp {
23
24namespace thisThread {
25// Mocked functions
26#if !defined(UNIT_TEST)
27pid_t GetThreadId() noexcept {
28 return ::syscall(SYS_gettid);
29}
30#endif
31
32void SetThreadName(std::string_view thread_name, std::error_code& ec) noexcept {
33 if (thread_name.size() >= THREAD_NAME_MAX_SIZE) {
34 ec = std::make_error_code(std::errc::result_out_of_range);
35 return;
36 }
37
38 std::array<char, THREAD_NAME_MAX_SIZE> c_str;
39 std::strncpy(c_str.data(), thread_name.data(), thread_name.size());
40 c_str[thread_name.size()] = '\0';
41
42 if (prctl(PR_SET_NAME, c_str.data()) == -1) {
43 ec = std::make_error_code(static_cast<std::errc>(errno));
44 return;
45 }
46 ec.clear();
47}
48
49void SetThreadName(std::string_view thread_name) {
50 std::error_code ec;
51 SetThreadName(thread_name, ec);
52 if (ec) {
53 throw std::system_error(ec, "Failed to set thread name for current thread");
54 }
55}
56
57std::string GetThreadName(std::error_code& ec) noexcept {
58 std::string thread_name;
59 std::array<char, THREAD_NAME_MAX_SIZE> c_str;
60 if (prctl(PR_GET_NAME, c_str.data()) == -1) {
61 ec = std::make_error_code(static_cast<std::errc>(errno));
62 return thread_name;
63 }
64
65 try {
66 thread_name.assign(c_str.data());
67 ec.clear();
68 return thread_name;
69 } catch (...) {
70 ec = std::make_error_code(std::errc::not_enough_memory);
71 return thread_name;
72 }
73}
74
75std::string GetThreadName() {
76 std::error_code ec;
77 auto name = GetThreadName(ec);
78 if (ec) {
79 throw std::system_error(ec, "failed to get thread name");
80 }
81 return name;
82}
83
84} // namespace thisThread
85
86namespace detail {
87ThreadInitializer::ThreadInitializer(std::string_view name, NumaPolicies const& policies)
88 : m_name(name), m_policies(policies), m_result(), m_cond(), m_mtx(), m_lck(m_mtx) {
89}
90
91auto ThreadInitializer::Wait() -> std::system_error const& {
92 m_cond.wait(m_lck, [&] { return m_result.has_value(); });
93 return *m_result;
94}
95
96auto ThreadInitializer::Initialize() -> std::error_code {
97 // Condition must be signalled on all exit-paths
98 // Although condition_variable::notify_one does not have to be called while holding a
99 // lock this is done to avoid a false-positive reported by thread-sanitizer.
100 // Performance-wise it does not matter one way or another in this case.
101 //
102 auto lck = std::unique_lock(m_mtx);
103
104 {
105 std::error_code ec;
106 if (thisThread::SetThreadName(m_name, ec); ec) {
107 m_result =
108 std::system_error(ec, "MakeThread: numapp::thisThread::SetThreadName() failed");
109 m_cond.notify_one();
110 return ec;
111 }
112 }
113
114 // Apply NUMA policies
115 if (auto ec = thisThread::Apply(m_policies); ec) {
116 m_result = std::system_error(ec, "MakeThread: numapp::thisThread::Apply() failed");
117 m_cond.notify_one();
118 return ec;
119 }
120 // Apply memory policy to stack, moving it if necessary.
121 // This is done because pthread may recycle stack so applying policy before creating
122 // thread does not always work.
123 if (m_policies.GetMemPolicy()) {
124 auto ec = thisThread::ApplyStack(*m_policies.GetMemPolicy(),
125 MemPolicyFlag::Move | MemPolicyFlag::Strict);
126 if (ec) {
127 m_result = std::system_error(ec, "MakeThread: numapp::ApplyStack() failed");
128 m_cond.notify_one();
129 return ec;
130 }
131 }
132
133 // Policies applied, notify creator of thread things were ok
134 m_result = std::system_error(std::error_code());
135 m_cond.notify_one();
136 return {};
137}
138
139} // namespace detail
140} // namespace numapp
std::error_code Apply(CpuAffinity const &affinity) noexcept
Apply policy to calling thread.
std::error_code ApplyStack(MemPolicy const &policy, MemPolicyFlag flags=MemPolicyFlag::Move|MemPolicyFlag::Strict) noexcept
Convenience function that applies a memory policy to current thread stack memory.
pid_t GetThreadId() noexcept
Query the thread id "TID" of the current thread.
Definition thread.cpp:27
void SetThreadName(std::string_view thread_name, std::error_code &ec) noexcept
Set thread name for current thread.
Definition thread.cpp:32
std::string GetThreadName()
Get name of current thread (throwing version).
Definition thread.cpp:75
Contains declarations for numapp thread utilities.