diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2018-02-13 14:12:30 +0100 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2018-02-15 22:38:08 +0100 |
commit | 32a726846d191796ba76e844a9aa1e7da0a9ed13 (patch) | |
tree | 94ae9fa442fd52c1b72c587335326285acc64e06 /src/util.cpp | |
parent | 5e40e64face29169ef355856dc0db46a98061046 (diff) | |
download | bitcoin-32a726846d191796ba76e844a9aa1e7da0a9ed13.tar.xz |
util: Fix multiple use of LockDirectory
This commit fixes problems with calling LockDirectory multiple times on
the same directory, or from multiple threads. It also fixes the build on
OpenBSD.
- Wrap the boost::interprocess::file_lock in a std::unique_ptr inside
the map that keeps track of per-directory locks. This fixes a build
issue with the clang 4.0.0+boost-1.58.0p8 version combo on OpenBSD
6.2, and should have no observable effect otherwise.
- Protect the locks map using a mutex.
- Make sure that only locks that are successfully acquired are inserted
in the map.
- Open the lock file for appending only if we know we don't have the
lock yet - The `FILE* file = fsbridge::fopen(pathLockFile, "a");`
wipes the 'we own this lock' administration, likely because it opens
a new fd for the locked file then closes it.
Github-Pull: #12422
Rebased-From: fc888bfcacb875c45bc8f9d7ca1357ab70a30490
Tree-SHA512: c8b8942fad9ea9d9e55f8e5e360f7cf3a8b00cd17e6bc5ec5895e1e6ddcbca796e62e82856e82f0562869a624d75ad510e108077461bb47a87b2b52be0aba866
Diffstat (limited to 'src/util.cpp')
-rw-r--r-- | src/util.cpp | 26 |
1 files changed, 20 insertions, 6 deletions
diff --git a/src/util.cpp b/src/util.cpp index 80eed24ffd..0769df4b3b 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -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()); |