/* vim:set ts=2 sw=2 sts=2 et: */ /** * \author Marcus Holland-Moritz (github@mhxnet.de) * \copyright Copyright (c) Marcus Holland-Moritz * * This file is part of dwarfs. * * dwarfs is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * dwarfs is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with dwarfs. If not, see . */ #include #include #include #include #include #ifdef __APPLE__ #include #include #endif #include #include #include namespace dwarfs { namespace fs = std::filesystem; namespace { #ifdef _WIN32 DWORD std_to_win_thread_id(std::thread::id tid) { static_assert(sizeof(std::thread::id) == sizeof(DWORD), "Win32 thread id type mismatch"); DWORD id; std::memcpy(&id, &tid, sizeof(id)); return id; } #else pthread_t std_to_pthread_id(std::thread::id tid) { static_assert(std::is_same_v); static_assert(sizeof(std::thread::id) == sizeof(std::thread::native_handle_type)); pthread_t id{0}; std::memcpy(&id, &tid, sizeof(id)); return id; } #endif class generic_dir_reader final : public dir_reader { public: explicit generic_dir_reader(fs::path const& path) : it_(fs::directory_iterator(path)) {} bool read(fs::path& name) override { if (it_ != fs::directory_iterator()) { name.assign(it_->path()); ++it_; return true; } return false; } private: fs::directory_iterator it_; }; } // namespace std::unique_ptr os_access_generic::opendir(fs::path const& path) const { return std::make_unique(path); } file_stat os_access_generic::symlink_info(fs::path const& path) const { return file_stat(path); } fs::path os_access_generic::read_symlink(fs::path const& path) const { return fs::read_symlink(path); } std::unique_ptr os_access_generic::map_file(fs::path const& path) const { return std::make_unique(path); } std::unique_ptr os_access_generic::map_file(fs::path const& path, size_t size) const { return std::make_unique(path, size); } int os_access_generic::access(fs::path const& path, int mode) const { #ifdef _WIN32 return ::_waccess(path.wstring().c_str(), mode); #else return ::access(path.string().c_str(), mode); #endif } fs::path os_access_generic::canonical(fs::path const& path) const { return canonical_path(path); } fs::path os_access_generic::current_path() const { return fs::current_path(); } std::optional os_access_generic::getenv(std::string_view name) const { std::string name_str(name); if (auto value = std::getenv(name_str.c_str())) { return value; } return std::nullopt; } void os_access_generic::thread_set_affinity(std::thread::id tid [[maybe_unused]], std::span cpus [[maybe_unused]], std::error_code& ec [[maybe_unused]]) const { #if !(defined(_WIN32) || defined(__APPLE__)) cpu_set_t cpuset; for (auto cpu : cpus) { CPU_SET(cpu, &cpuset); } if (auto error = pthread_setaffinity_np(std_to_pthread_id(tid), sizeof(cpu_set_t), &cpuset); error != 0) { ec.assign(error, std::generic_category()); } #endif } std::chrono::nanoseconds os_access_generic::thread_get_cpu_time(std::thread::id tid, std::error_code& ec) const { #ifdef _WIN32 HANDLE h = ::OpenThread(THREAD_QUERY_LIMITED_INFORMATION, FALSE, std_to_win_thread_id(tid)); if (h == nullptr) { ec.assign(::GetLastError(), std::system_category()); return {}; } FILETIME t_create, t_exit, t_sys, t_user; if (!::GetThreadTimes(h, &t_create, &t_exit, &t_sys, &t_user)) { ec.assign(::GetLastError(), std::system_category()); return {}; } uint64_t sys = (static_cast(t_sys.dwHighDateTime) << 32) + t_sys.dwLowDateTime; uint64_t user = (static_cast(t_user.dwHighDateTime) << 32) + t_user.dwLowDateTime; return std::chrono::nanoseconds(100 * (sys + user)); #elif defined(__APPLE__) auto port = ::pthread_mach_thread_np(std_to_pthread_id(tid)); ::thread_basic_info_data_t ti; ::mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT; if (::thread_info(port, THREAD_BASIC_INFO, reinterpret_cast(&ti), &count) != KERN_SUCCESS) { ec = std::make_error_code(std::errc::not_supported); return {}; } return std::chrono::seconds(ti.user_time.seconds + ti.system_time.seconds) + std::chrono::microseconds(ti.user_time.microseconds + ti.system_time.microseconds); #else ::clockid_t cid; struct ::timespec ts; if (auto err = ::pthread_getcpuclockid(std_to_pthread_id(tid), &cid); err != 0) { ec.assign(err, std::generic_category()); return {}; } if (::clock_gettime(cid, &ts) != 0) { ec.assign(errno, std::generic_category()); return {}; } return std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec); #endif } std::filesystem::path os_access_generic::find_executable(std::filesystem::path const& name) const { return boost::process::search_path(name.wstring()).wstring(); } } // namespace dwarfs