Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/elfmz/far2l.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorelfmz <fenix1905@tut.by>2022-10-27 00:19:22 +0300
committerelfmz <fenix1905@tut.by>2022-10-27 10:08:18 +0300
commitecefbdfc83366ac6d119e8356901ecfeb70afa7c (patch)
tree82f7a7c64f16f8878a0a7bb2c0e158c3a243f4a0
parent6cc79cf88da56351d39b4bf4154385adde4f1d19 (diff)
add BSD and MAC support into MountInfo
-rw-r--r--far2l/src/farwinapi.cpp2
-rw-r--r--far2l/src/findfile.cpp2
-rw-r--r--far2l/src/mix/MountInfo.cpp142
-rw-r--r--far2l/src/mix/MountInfo.h12
-rw-r--r--utils/include/Threaded.h4
-rw-r--r--utils/src/Threaded.cpp15
6 files changed, 152 insertions, 25 deletions
diff --git a/far2l/src/farwinapi.cpp b/far2l/src/farwinapi.cpp
index 64e9d254..0afad4d4 100644
--- a/far2l/src/farwinapi.cpp
+++ b/far2l/src/farwinapi.cpp
@@ -514,7 +514,7 @@ BOOL apiGetVolumeInformation(
}
if (pFileSystemName) {
- *pFileSystemName = MountInfo().GetFileSystem(path);
+ *pFileSystemName = MountInfo(false).GetFileSystem(path);
}
return TRUE;
diff --git a/far2l/src/findfile.cpp b/far2l/src/findfile.cpp
index f4655733..d27f3939 100644
--- a/far2l/src/findfile.cpp
+++ b/far2l/src/findfile.cpp
@@ -2803,7 +2803,7 @@ public:
{
SudoClientRegion scr;
DWORD msec = GetProcessUptimeMSec();
- pMountInfo.reset(new MountInfo);
+ pMountInfo.reset(new MountInfo(false));
if (PluginMode)
{
DoPreparePluginList(hDlg);
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;
diff --git a/utils/include/Threaded.h b/utils/include/Threaded.h
index 80590ff2..93caccfb 100644
--- a/utils/include/Threaded.h
+++ b/utils/include/Threaded.h
@@ -7,6 +7,7 @@ class Threaded
{
std::condition_variable _trd_cond;
std::mutex _trd_mtx;
+ bool _self_destruct = false;
pthread_t _trd = 0;
void *_trd_result = nullptr;
@@ -19,7 +20,8 @@ protected:
virtual void *ThreadProc() = 0;
- bool StartThread();
+ void Detach();
+ bool StartThread(bool self_destruct = false);
bool WaitThread(unsigned int msec = (unsigned int)-1);
void *GetThreadResult();
};
diff --git a/utils/src/Threaded.cpp b/utils/src/Threaded.cpp
index ee393a29..7e404f1d 100644
--- a/utils/src/Threaded.cpp
+++ b/utils/src/Threaded.cpp
@@ -21,14 +21,20 @@ void *Threaded::sThreadProc(void *p)
Threaded *it = (Threaded *)p;
void *result = it->ThreadProc();
- std::lock_guard<std::mutex> lock(it->_trd_mtx);
- it->_trd_exited = true;
- it->_trd_cond.notify_all();
+ {
+ std::lock_guard<std::mutex> lock(it->_trd_mtx);
+ it->_trd_exited = true;
+ it->_trd_cond.notify_all();
+ }
+
+ if (it->_self_destruct) {
+ delete it;
+ }
return result;
}
-bool Threaded::StartThread()
+bool Threaded::StartThread(bool self_destruct)
{
std::lock_guard<std::mutex> lock(_trd_mtx);
if (!_trd_joined) {
@@ -41,6 +47,7 @@ bool Threaded::StartThread()
}
_trd_joined = _trd_exited = false;
+ _self_destruct = self_destruct;
if (pthread_create(&_trd, NULL, &sThreadProc, this) != 0) {
_trd_joined = _trd_exited = true;
_trd = 0;