|
|
@@ -0,0 +1,112 @@ |
|
|
|
#ifdef _WIN32 |
|
|
|
|
|
|
|
#include "./flock.hpp" |
|
|
|
|
|
|
|
#include <dds/util/signal.hpp> |
|
|
|
|
|
|
|
#include <spdlog/fmt/fmt.h> |
|
|
|
#include <wil/resource.h> |
|
|
|
|
|
|
|
using namespace dds; |
|
|
|
|
|
|
|
namespace { |
|
|
|
|
|
|
|
enum fail_mode { |
|
|
|
blocking, |
|
|
|
nonblocking, |
|
|
|
}; |
|
|
|
|
|
|
|
enum lock_mode { |
|
|
|
shared, |
|
|
|
exclusive, |
|
|
|
}; |
|
|
|
|
|
|
|
struct lock_data { |
|
|
|
wil::unique_handle file; |
|
|
|
|
|
|
|
bool do_lock(fail_mode fm, lock_mode lm, path_ref p) { |
|
|
|
auto lockflags = lm == exclusive ? LOCKFILE_EXCLUSIVE_LOCK : 0; |
|
|
|
auto failflags = fm == nonblocking ? LOCKFILE_FAIL_IMMEDIATELY : 0; |
|
|
|
auto flags = lockflags | failflags; |
|
|
|
const auto okay = ::LockFileEx(file.get(), flags, 0, 0, 0, nullptr); |
|
|
|
if (!okay) { |
|
|
|
cancellation_point(); |
|
|
|
if (::GetLastError() == ERROR_IO_PENDING) { |
|
|
|
return false; |
|
|
|
} |
|
|
|
throw std::system_error(std::error_code(errno, std::system_category()), |
|
|
|
fmt::format("Failed to modify file lock [{}]", p.string())); |
|
|
|
} |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
void unlock(path_ref p) { |
|
|
|
const auto okay = ::UnlockFileEx(file.get(), 0, 0, 0, nullptr); |
|
|
|
if (!okay) { |
|
|
|
cancellation_point(); |
|
|
|
throw std::system_error(std::error_code(::GetLastError(), std::system_category()), |
|
|
|
fmt::format("Failed to unlock file [{}]", p.string())); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
} // namespace |
|
|
|
|
|
|
|
#define THIS_DATA static_cast<lock_data*>(_lock_data) |
|
|
|
|
|
|
|
shared_file_mutex::shared_file_mutex(path_ref filepath) |
|
|
|
: _path{filepath} { |
|
|
|
auto h = ::CreateFileA(_path.string().c_str(), |
|
|
|
GENERIC_READ | GENERIC_WRITE, |
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, |
|
|
|
nullptr, |
|
|
|
CREATE_ALWAYS, |
|
|
|
FILE_ATTRIBUTE_NORMAL, |
|
|
|
nullptr); |
|
|
|
wil::unique_handle file{h}; |
|
|
|
|
|
|
|
if (!file) { |
|
|
|
throw std::system_error(std::error_code(::GetLastError(), std::system_category()), |
|
|
|
fmt::format("Failed to open file for locking [{}]", |
|
|
|
_path.string())); |
|
|
|
} |
|
|
|
|
|
|
|
_lock_data = new lock_data(lock_data{std::move(file)}); |
|
|
|
} |
|
|
|
|
|
|
|
#define MY_LOCK_DATA (*static_cast<lock_data*>(_lock_data)) |
|
|
|
|
|
|
|
shared_file_mutex::~shared_file_mutex() { |
|
|
|
assert(_lock_data); |
|
|
|
delete &MY_LOCK_DATA; |
|
|
|
_lock_data = nullptr; |
|
|
|
} |
|
|
|
|
|
|
|
bool shared_file_mutex::try_lock() noexcept { |
|
|
|
// Attempt to take an exclusive lock |
|
|
|
return MY_LOCK_DATA.do_lock(nonblocking, exclusive, _path); |
|
|
|
} |
|
|
|
|
|
|
|
bool shared_file_mutex::try_lock_shared() noexcept { |
|
|
|
// Take a non-exclusive lock |
|
|
|
return MY_LOCK_DATA.do_lock(nonblocking, shared, _path); |
|
|
|
} |
|
|
|
|
|
|
|
void shared_file_mutex::lock() { |
|
|
|
// Blocking exclusive lock |
|
|
|
MY_LOCK_DATA.do_lock(blocking, exclusive, _path); |
|
|
|
} |
|
|
|
|
|
|
|
void shared_file_mutex::lock_shared() { |
|
|
|
// Blocking shared lock |
|
|
|
MY_LOCK_DATA.do_lock(blocking, shared, _path); |
|
|
|
} |
|
|
|
|
|
|
|
void shared_file_mutex::unlock() { |
|
|
|
// Unlock |
|
|
|
MY_LOCK_DATA.unlock(_path); |
|
|
|
} |
|
|
|
|
|
|
|
void shared_file_mutex::unlock_shared() { unlock(); } |
|
|
|
|
|
|
|
#endif |