Skip to content

Commit

Permalink
test: Add function for explicit release of locks before cleanup
Browse files Browse the repository at this point in the history
This fixes the LockDirectory test cleanup on windows (and makes it more
self-contained generally). It won't let the test delete the directory
while there is a locked file in there.
  • Loading branch information
laanwj committed Feb 14, 2018
1 parent 20cc4b3 commit 6a0a3d7
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 9 deletions.
1 change: 1 addition & 0 deletions src/test/util_tests.cpp
Expand Up @@ -669,6 +669,7 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory)
BOOST_CHECK_EQUAL(processstatus, (int)false);
#endif
// Clean up
ReleaseDirectoryLocks();
fs::remove_all(dirname);
}

Expand Down
27 changes: 18 additions & 9 deletions src/util.cpp
Expand Up @@ -373,19 +373,22 @@ int LogPrintStr(const std::string &str)
return ret;
}

/** 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, or ReleaseDirectoryLocks
* is called.
*/
static std::map<std::string, std::unique_ptr<boost::interprocess::file_lock>> dir_locks;
/** Mutex to protect dir_locks. */
static std::mutex cs_dir_locks;

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);
std::lock_guard<std::mutex> ulock(cs_dir_locks);
fs::path pathLockFile = directory / lockfile_name;

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

Expand All @@ -400,14 +403,20 @@ bool LockDirectory(const fs::path& directory, const std::string lockfile_name, b
}
if (!probe_only) {
// Lock successful and we're not just probing, put it into the map
locks.emplace(pathLockFile.string(), std::move(lock));
dir_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());
}
return true;
}

void ReleaseDirectoryLocks()
{
std::lock_guard<std::mutex> ulock(cs_dir_locks);
dir_locks.clear();
}

/** Interpret string as boolean, for argument parsing */
static bool InterpretBool(const std::string& strValue)
{
Expand Down
6 changes: 6 additions & 0 deletions src/util.h
Expand Up @@ -174,6 +174,12 @@ int RaiseFileDescriptorLimit(int nMinFD);
void AllocateFileRange(FILE *file, unsigned int offset, unsigned int length);
bool RenameOver(fs::path src, fs::path dest);
bool LockDirectory(const fs::path& directory, const std::string lockfile_name, bool probe_only=false);

/** Release all directory locks. This is used for unit testing only, at runtime
* the global destructor will take care of the locks.
*/
void ReleaseDirectoryLocks();

bool TryCreateDirectories(const fs::path& p);
fs::path GetDefaultDataDir();
const fs::path &GetDataDir(bool fNetSpecific = true);
Expand Down

0 comments on commit 6a0a3d7

Please sign in to comment.