Przeglądaj źródła

File locking on Windows

default_compile_flags
vector-of-bool 5 lat temu
rodzic
commit
6a82439e27
1 zmienionych plików z 112 dodań i 0 usunięć
  1. +112
    -0
      src/dds/util/flock.win.cpp

+ 112
- 0
src/dds/util/flock.win.cpp Wyświetl plik

@@ -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

Ładowanie…
Anuluj
Zapisz