diff options
author | elfmz <fenix1905@tut.by> | 2022-10-27 00:19:22 +0300 |
---|---|---|
committer | elfmz <fenix1905@tut.by> | 2022-10-27 10:08:18 +0300 |
commit | ecefbdfc83366ac6d119e8356901ecfeb70afa7c (patch) | |
tree | 82f7a7c64f16f8878a0a7bb2c0e158c3a243f4a0 /far2l/src/mix | |
parent | 6cc79cf88da56351d39b4bf4154385adde4f1d19 (diff) |
add BSD and MAC support into MountInfo
Diffstat (limited to 'far2l/src/mix')
-rw-r--r-- | far2l/src/mix/MountInfo.cpp | 142 | ||||
-rw-r--r-- | far2l/src/mix/MountInfo.h | 12 |
2 files changed, 136 insertions, 18 deletions
diff --git a/far2l/src/mix/MountInfo.cpp b/far2l/src/mix/MountInfo.cpp index 96368b45..a655ccfb 100644 --- a/far2l/src/mix/MountInfo.cpp +++ b/far2l/src/mix/MountInfo.cpp @@ -7,15 +7,23 @@ #include <sys/statvfs.h> #include <fcntl.h> #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__CYGWIN__) -# include <errno.h> +# if defined(__APPLE__) || defined(__FreeBSD__) +# include <sys/param.h> +# include <sys/ucred.h> +# endif # include <sys/mount.h> #else # include <sys/statfs.h> # include <linux/fs.h> #endif +#include <errno.h> #include <fstream> +#include <chrono> +#include <mutex> +#include <condition_variable> #include "MountInfo.h" #include <ScopeHelpers.h> +#include <Threaded.h> #include <os_call.hpp> static struct FSMagic { @@ -97,9 +105,67 @@ static struct FSMagic { ///////////////////////////////////////////////////////////////////////////////////////////// -MountInfo::MountInfo() +struct Mountpoint +{ + std::string path; + std::string filesystem; + bool multi_thread_friendly; + unsigned long long total, used; +}; + +struct Mountpoints : std::vector<Mountpoint> +{ + struct Pending + { + std::mutex mtx; + std::condition_variable cond; + int cnt{0}; + } pending; +}; + +class ThreadedStatFS : Threaded +{ + std::shared_ptr<Mountpoints> _mps; + size_t _mpi; + + void *ThreadProc() + { + struct statfs fs{}; + int r = statfs((*_mps)[_mpi].path.c_str(), &fs); + if (r == 0) { + (*_mps)[_mpi].total = fs.f_bsize * fs.f_blocks; + (*_mps)[_mpi].used = (fs.f_bsize - fs.f_bfree) * fs.f_blocks; + } + return nullptr; + } + +public: + ThreadedStatFS(std::shared_ptr<Mountpoints> &mps, size_t mpi) + : _mps(mps), _mpi(mpi) + { + } + + virtual ~ThreadedStatFS() + { + std::unique_lock<std::mutex> lock(_mps->pending.mtx); + _mps->pending.cnt--; + if (_mps->pending.cnt == 0) { + _mps->pending.cond.notify_all(); + } + + } + + void Start() + { + if (!StartThread(true)) { + fprintf(stderr, "ThreadedStatFS: can't start thread\n"); + delete this; + } + } +}; + +MountInfo::MountInfo(bool query_space) { -#ifdef __linux__ // force-enable multi-threaded disk access: echo e > ~/.config/far2l/mtfs // force-disable multi-threaded disk access: echo d > ~/.config/far2l/mtfs FDScope fd(open(InMyConfig("mtfs").c_str(), O_RDONLY)); @@ -109,7 +175,9 @@ MountInfo::MountInfo() } fprintf(stderr, "%s: _mtfs='%c'\n", __FUNCTION__, _mtfs); } + _mountpoints = std::make_shared<Mountpoints>(); +#ifdef __linux__ std::ifstream is("/proc/mounts"); if (is.is_open()) { std::string line, sys_path; @@ -142,18 +210,70 @@ MountInfo::MountInfo() if (parts.size() == 1) { parts.emplace_back(); } - _mountpoints.emplace_back(Mountpoint{parts[1], parts[2], multi_thread_friendly}); - fprintf(stderr, "%s: mtf=%d fs='%s' for '%s' at '%s'\n", __FUNCTION__, - multi_thread_friendly, parts[2].c_str(), parts[0].c_str(), parts[1].c_str()); + _mountpoints->emplace_back(Mountpoint{ + parts[1], + parts[2], + multi_thread_friendly, + 0, + 0 + }); } } } - if (_mountpoints.empty()) { - fprintf(stderr, "%s: failed to parse /proc/mounts\n", __FUNCTION__); + +#elif defined(__APPLE__) || defined(__FreeBSD__) + + int r = getfsstat(nullptr, 0, MNT_NOWAIT); + if (r > 0) { + std::vector<struct statfs> buf(r * 2 + 2); + r = getfsstat(buf.data(), buf.size(), MNT_NOWAIT); + if (r > 0) { + buf.resize(r); + for (const auto &fs : buf) { + _mountpoints->emplace_back(Mountpoint{ + fs.f_mntonname, + fs.f_fstypename, + true, + fs.f_bsize * fs.f_blocks, + (fs.f_bsize - fs.f_bfree) * fs.f_blocks + }); + } + } } #endif - // TODO: BSD, MacOS + if (_mountpoints->empty()) { + fprintf(stderr, "%s: no mountpoints found\n", __FUNCTION__); + + } else if (query_space) { + for (size_t i = 0; i < _mountpoints->size(); ++i) { + try { + (new ThreadedStatFS(_mountpoints, i))->Start(); + std::unique_lock<std::mutex> lock(_mountpoints->pending.mtx); + _mountpoints->pending.cnt++; + } catch (std::exception &e) { + fprintf(stderr, "%s: %s\n", __FUNCTION__, e.what()); + } + } + for (DWORD ms = 0; ms < 1000;) { + std::chrono::milliseconds ms_before = std::chrono::duration_cast< std::chrono::milliseconds > + (std::chrono::steady_clock::now().time_since_epoch()); + { + std::unique_lock<std::mutex> lock(_mountpoints->pending.mtx); + _mountpoints->pending.cond.wait_for(lock, std::chrono::milliseconds(1000 - ms)); + if (_mountpoints->pending.cnt == 0) { + break; + } + } + ms+= (std::chrono::duration_cast< std::chrono::milliseconds > + (std::chrono::steady_clock::now().time_since_epoch()) - ms_before).count(); + } + } + + for (const auto &it : *_mountpoints) { + fprintf(stderr, "%s: mtf=%d spc=[%llu/%llu] fs='%s' at '%s'\n", __FUNCTION__, + it.multi_thread_friendly, it.used, it.total, it.filesystem.c_str(), it.path.c_str()); + } } @@ -161,7 +281,7 @@ std::string MountInfo::GetFileSystem(const std::string &path) const { std::string out; size_t longest_match = 0; - for (const auto &it : _mountpoints) { + for (const auto &it : *_mountpoints) { if (it.path.size() > longest_match && StrStartsFrom(path, it.path.c_str())) { longest_match = it.path.size(); out = it.filesystem; @@ -199,7 +319,7 @@ bool MountInfo::IsMultiThreadFriendly(const std::string &path) const bool out = true; size_t longest_match = 0; - for (const auto &it : _mountpoints) { + for (const auto &it : *_mountpoints) { if (it.path.size() > longest_match && StrStartsFrom(path, it.path.c_str())) { longest_match = it.path.size(); out = it.multi_thread_friendly; diff --git a/far2l/src/mix/MountInfo.h b/far2l/src/mix/MountInfo.h index 4c630697..65781245 100644 --- a/far2l/src/mix/MountInfo.h +++ b/far2l/src/mix/MountInfo.h @@ -1,6 +1,9 @@ #pragma once #include <string> #include <vector> +#include <memory> + +struct Mountpoints; /* This class detects if path points to device that is best to be * accessed in multi-thread parallel manner, like SSD drives. @@ -8,16 +11,11 @@ */ class MountInfo { - struct Mountpoint { - std::string path; - std::string filesystem; - bool multi_thread_friendly; - }; - struct Mountpoints : std::vector<Mountpoint> {} _mountpoints; + std::shared_ptr<Mountpoints> _mountpoints; char _mtfs = 0; public: - MountInfo(); + MountInfo(bool query_space); std::string GetFileSystem(const std::string &path) const; |