ThreadSchedule 3.0.0
Modern C++ thread management library
Loading...
Searching...
No Matches
identity.hpp
Go to the documentation of this file.
1#pragma once
2
8#include "../../result.hpp"
9#include "../scheduling/native.hpp"
10
11#include <algorithm>
12#include <charconv>
13#include <cstdint>
14#include <fstream>
15#include <memory>
16#include <optional>
17#include <sstream>
18#include <string>
19#include <string_view>
20#include <system_error>
21#include <vector>
22
23#ifndef _WIN32
24# include <cerrno>
25# include <dirent.h>
26# include <sys/syscall.h>
27# include <unistd.h>
28#endif
29
31{
32
34{
36 std::uint64_t start_time{};
37};
38
39#ifndef _WIN32
40[[nodiscard]] inline auto
41read_thread_start_time(native_thread_id id) noexcept -> std::optional<std::uint64_t>
42{
43 try
44 {
45 std::ifstream input("/proc/self/task/" + std::to_string(id) + "/stat");
46 std::string line;
47 if (!std::getline(input, line))
48 return std::nullopt;
49 auto const command_end = line.rfind(')');
50 if (command_end == std::string::npos || command_end + 2 >= line.size())
51 return std::nullopt;
52
53 std::istringstream fields(line.substr(command_end + 2));
54 char state = '\0';
55 if (!(fields >> state) || state == 'Z' || state == 'X' || state == 'x')
56 return std::nullopt;
57 std::string ignored;
58 for (int field = 4; field < 22; ++field)
59 if (!(fields >> ignored))
60 return std::nullopt;
61 std::uint64_t value = 0;
62 if (!(fields >> value))
63 return std::nullopt;
64 return value;
65 }
66 catch (...)
67 {
68 return std::nullopt;
69 }
70}
71#endif
72
73[[nodiscard]] inline auto
74native_thread_is_alive(native_thread_identity const& identity) noexcept -> bool
75{
76#ifdef _WIN32
77 (void)identity;
78 return false;
79#else
80 errno = 0;
81 if (syscall(SYS_tgkill, getpid(), identity.id, 0) != 0 && errno != EPERM)
82 return false;
83 auto const current = read_thread_start_time(identity.id);
84 return current.has_value() && current.value() == identity.start_time;
85#endif
86}
87
88[[nodiscard]] inline auto
90{
91 if (name.empty() || name.size() > 15)
92 return unexpected(std::make_error_code(std::errc::invalid_argument));
93
94#ifdef _WIN32
95 return unexpected(std::make_error_code(std::errc::function_not_supported));
96#else
97 struct directory_deleter
98 {
99 void
100 operator()(DIR* directory) const noexcept
101 {
102 if (directory != nullptr)
103 (void)closedir(directory);
104 }
105 };
106
107 std::unique_ptr<DIR, directory_deleter> directory(opendir("/proc/self/task"));
108 if (!directory)
109 return unexpected(std::error_code(errno, std::generic_category()));
110
111 std::vector<native_thread_identity> matches;
112 while (true)
113 {
114 errno = 0;
115 auto* const entry = readdir(directory.get());
116 if (entry == nullptr)
117 {
118 if (errno != 0)
119 return unexpected(std::error_code(errno, std::generic_category()));
120 break;
121 }
122
123 std::string_view const candidate(entry->d_name);
124 native_thread_id id{};
125 auto const parsed = std::from_chars(candidate.data(), candidate.data() + candidate.size(), id);
126 if (parsed.ec != std::errc{} || parsed.ptr != candidate.data() + candidate.size() || id <= 0)
127 continue;
128
129 std::ifstream comm("/proc/self/task/" + std::to_string(id) + "/comm");
130 std::string current_name;
131 if (!std::getline(comm, current_name) || current_name != name)
132 continue;
133
134 auto const start_time = read_thread_start_time(id);
135 if (start_time.has_value())
136 matches.push_back({ id, start_time.value() });
137 }
138
139 std::sort(matches.begin(), matches.end(), [](auto const& lhs, auto const& rhs) { return lhs.id < rhs.id; });
140 return matches;
141#endif
142}
143
144} // namespace threadschedule::detail
Aggregates multiple thread_registry_backend instances into a single queryable view.
auto read_thread_start_time(native_thread_id id) noexcept -> std::optional< std::uint64_t >
Definition identity.hpp:41
auto native_thread_is_alive(native_thread_identity const &identity) noexcept -> bool
Definition identity.hpp:74
auto find_native_threads_by_name(std::string_view name) -> result< std::vector< native_thread_identity > >
Definition identity.hpp:89