Skip to content

Commit

Permalink
util: Fix multiple use of LockDirectory This commit fixes problems wi…
Browse files Browse the repository at this point in the history
…th calling LockDirectory multiple times on the same directory, or from multiple threads. It also fixes the build on OpenBSD.
  • Loading branch information
laanwj authored and furszy committed Jul 21, 2021
1 parent 9ae619a commit 16b4651
Showing 1 changed file with 20 additions and 6 deletions.
26 changes: 20 additions & 6 deletions src/util/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,32 @@ bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes)

bool LockDirectory(const fs::path& directory, const std::string& lockfile_name, bool probe_only)
{
// A map that contains all the currently held directory locks. After
// successful locking, these will be held here until the global
// destructor cleans them up and thus automatically unlocks them.
static std::map<std::string, std::unique_ptr<boost::interprocess::file_lock>> locks;
// Protect the map with a mutex
static std::mutex cs;
std::lock_guard<std::mutex> ulock(cs);
fs::path pathLockFile = directory / lockfile_name;
FILE* file = fsbridge::fopen(pathLockFile, "a"); // empty lock file; created if it doesn't exist.

// If a lock for this directory already exists in the map, don't try to re-lock it
if (locks.count(pathLockFile.string())) {
return true;
}

// Create empty lock file if it doesn't exist.
FILE* file = fsbridge::fopen(pathLockFile, "a");
if (file) fclose(file);

try {
static std::map<std::string, boost::interprocess::file_lock> locks;
boost::interprocess::file_lock& lock = locks.emplace(pathLockFile.string(), pathLockFile.string().c_str()).first->second;
if (!lock.try_lock()) {
auto lock = std::make_unique<boost::interprocess::file_lock>(pathLockFile.string().c_str());
if (!lock->try_lock()) {
return false;
}
if (probe_only) {
lock.unlock();
if (!probe_only) {
// Lock successful and we're not just probing, put it into the map
locks.emplace(pathLockFile.string(), std::move(lock));
}
} catch (const boost::interprocess::interprocess_exception& e) {
return error("Error while attempting to lock directory %s: %s", directory.string(), e.what());
Expand Down

0 comments on commit 16b4651

Please sign in to comment.