|
|
@@ -378,18 +378,32 @@ int LogPrintStr(const std::string &str) |
|
|
|
|
|
|
|
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 = MakeUnique<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()); |