45 std::ifstream input(
"/proc/self/task/" + std::to_string(
id) +
"/stat");
47 if (!std::getline(input, line))
49 auto const command_end = line.rfind(
')');
50 if (command_end == std::string::npos || command_end + 2 >= line.size())
53 std::istringstream fields(line.substr(command_end + 2));
55 if (!(fields >> state) || state ==
'Z' || state ==
'X' || state ==
'x')
58 for (
int field = 4; field < 22; ++field)
59 if (!(fields >> ignored))
61 std::uint64_t value = 0;
62 if (!(fields >> value))
91 if (name.empty() || name.size() > 15)
92 return unexpected(std::make_error_code(std::errc::invalid_argument));
95 return unexpected(std::make_error_code(std::errc::function_not_supported));
97 struct directory_deleter
100 operator()(DIR* directory)
const noexcept
102 if (directory !=
nullptr)
103 (void)closedir(directory);
107 std::unique_ptr<DIR, directory_deleter> directory(opendir(
"/proc/self/task"));
109 return unexpected(std::error_code(errno, std::generic_category()));
111 std::vector<native_thread_identity> matches;
115 auto*
const entry = readdir(directory.get());
116 if (entry ==
nullptr)
119 return unexpected(std::error_code(errno, std::generic_category()));
123 std::string_view
const candidate(entry->d_name);
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)
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)
135 if (start_time.has_value())
136 matches.push_back({ id, start_time.value() });
139 std::sort(matches.begin(), matches.end(), [](
auto const& lhs,
auto const& rhs) { return lhs.id < rhs.id; });