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