mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-10 22:18:54 +01:00
refactor: Return enum in LockDirectory
This makes it easier to add more Error cases in the future. Also, add missing util namespace.
This commit is contained in:
@@ -1106,15 +1106,15 @@ BOOST_AUTO_TEST_CASE(test_ParseFixedPoint)
|
||||
BOOST_CHECK(!ParseFixedPoint("31.999999999999999999999", 3, &amount));
|
||||
}
|
||||
|
||||
static void TestOtherThread(fs::path dirname, fs::path lockname, bool *result)
|
||||
{
|
||||
*result = LockDirectory(dirname, lockname);
|
||||
}
|
||||
|
||||
#ifndef WIN32 // Cannot do this test on WIN32 due to lack of fork()
|
||||
static constexpr char LockCommand = 'L';
|
||||
static constexpr char UnlockCommand = 'U';
|
||||
static constexpr char ExitCommand = 'X';
|
||||
enum : char {
|
||||
ResSuccess = 2, // Start with 2 to avoid accidental collision with common values 0 and 1
|
||||
ResErrorLock,
|
||||
ResUnlockSuccess,
|
||||
};
|
||||
|
||||
[[noreturn]] static void TestOtherProcess(fs::path dirname, fs::path lockname, int fd)
|
||||
{
|
||||
@@ -1122,15 +1122,21 @@ static constexpr char ExitCommand = 'X';
|
||||
while (true) {
|
||||
int rv = read(fd, &ch, 1); // Wait for command
|
||||
assert(rv == 1);
|
||||
switch(ch) {
|
||||
switch (ch) {
|
||||
case LockCommand:
|
||||
ch = LockDirectory(dirname, lockname);
|
||||
ch = [&] {
|
||||
switch (util::LockDirectory(dirname, lockname)) {
|
||||
case util::LockResult::Success: return ResSuccess;
|
||||
case util::LockResult::ErrorLock: return ResErrorLock;
|
||||
} // no default case, so the compiler can warn about missing cases
|
||||
assert(false);
|
||||
}();
|
||||
rv = write(fd, &ch, 1);
|
||||
assert(rv == 1);
|
||||
break;
|
||||
case UnlockCommand:
|
||||
ReleaseDirectoryLocks();
|
||||
ch = true; // Always succeeds
|
||||
ch = ResUnlockSuccess; // Always succeeds
|
||||
rv = write(fd, &ch, 1);
|
||||
assert(rv == 1);
|
||||
break;
|
||||
@@ -1167,51 +1173,51 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory)
|
||||
BOOST_CHECK_EQUAL(close(fd[0]), 0); // Parent: close child end
|
||||
#endif
|
||||
// Lock on non-existent directory should fail
|
||||
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname), false);
|
||||
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname), util::LockResult::ErrorLock);
|
||||
|
||||
fs::create_directories(dirname);
|
||||
|
||||
// Probing lock on new directory should succeed
|
||||
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
|
||||
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::Success);
|
||||
|
||||
// Persistent lock on new directory should succeed
|
||||
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname), true);
|
||||
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname), util::LockResult::Success);
|
||||
|
||||
// Another lock on the directory from the same thread should succeed
|
||||
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname), true);
|
||||
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname), util::LockResult::Success);
|
||||
|
||||
// Another lock on the directory from a different thread within the same process should succeed
|
||||
bool threadresult;
|
||||
std::thread thr(TestOtherThread, dirname, lockname, &threadresult);
|
||||
util::LockResult threadresult;
|
||||
std::thread thr([&] { threadresult = util::LockDirectory(dirname, lockname); });
|
||||
thr.join();
|
||||
BOOST_CHECK_EQUAL(threadresult, true);
|
||||
BOOST_CHECK_EQUAL(threadresult, util::LockResult::Success);
|
||||
#ifndef WIN32
|
||||
// Try to acquire lock in child process while we're holding it, this should fail.
|
||||
char ch;
|
||||
BOOST_CHECK_EQUAL(write(fd[1], &LockCommand, 1), 1);
|
||||
BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1);
|
||||
BOOST_CHECK_EQUAL((bool)ch, false);
|
||||
BOOST_CHECK_EQUAL(ch, ResErrorLock);
|
||||
|
||||
// Give up our lock
|
||||
ReleaseDirectoryLocks();
|
||||
// Probing lock from our side now should succeed, but not hold on to the lock.
|
||||
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
|
||||
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::Success);
|
||||
|
||||
// Try to acquire the lock in the child process, this should be successful.
|
||||
BOOST_CHECK_EQUAL(write(fd[1], &LockCommand, 1), 1);
|
||||
BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1);
|
||||
BOOST_CHECK_EQUAL((bool)ch, true);
|
||||
BOOST_CHECK_EQUAL(ch, ResSuccess);
|
||||
|
||||
// When we try to probe the lock now, it should fail.
|
||||
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), false);
|
||||
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::ErrorLock);
|
||||
|
||||
// Unlock the lock in the child process
|
||||
BOOST_CHECK_EQUAL(write(fd[1], &UnlockCommand, 1), 1);
|
||||
BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1);
|
||||
BOOST_CHECK_EQUAL((bool)ch, true);
|
||||
BOOST_CHECK_EQUAL(ch, ResUnlockSuccess);
|
||||
|
||||
// When we try to probe the lock now, it should succeed.
|
||||
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
|
||||
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::Success);
|
||||
|
||||
// Re-lock the lock in the child process, then wait for it to exit, check
|
||||
// successful return. After that, we check that exiting the process
|
||||
@@ -1221,7 +1227,7 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory)
|
||||
BOOST_CHECK_EQUAL(write(fd[1], &ExitCommand, 1), 1);
|
||||
BOOST_CHECK_EQUAL(waitpid(pid, &processstatus, 0), pid);
|
||||
BOOST_CHECK_EQUAL(processstatus, 0);
|
||||
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
|
||||
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::Success);
|
||||
|
||||
// Restore SIGCHLD
|
||||
signal(SIGCHLD, old_handler);
|
||||
|
||||
Reference in New Issue
Block a user