Skip to content

Commit fa0afe7

Browse files
author
MarcoFalke
committed
refactor: Return enum in LockDirectory
This makes it easier to add more Error cases in the future. Also, add missing util namespace.
1 parent 64879f4 commit fa0afe7

File tree

5 files changed

+48
-33
lines changed

5 files changed

+48
-33
lines changed

src/init.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,10 +1031,12 @@ static bool LockDataDirectory(bool probeOnly)
10311031
if (!DirIsWritable(datadir)) {
10321032
return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), fs::PathToString(datadir)));
10331033
}
1034-
if (!LockDirectory(datadir, ".lock", probeOnly)) {
1034+
switch (util::LockDirectory(datadir, ".lock", probeOnly)) {
1035+
case util::LockResult::ErrorLock:
10351036
return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), fs::PathToString(datadir), PACKAGE_NAME));
1036-
}
1037-
return true;
1037+
case util::LockResult::Success: return true;
1038+
} // no default case, so the compiler can warn about missing cases
1039+
assert(false);
10381040
}
10391041

10401042
bool AppInitSanityChecks(const kernel::Context& kernel)

src/test/util_tests.cpp

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,31 +1106,37 @@ BOOST_AUTO_TEST_CASE(test_ParseFixedPoint)
11061106
BOOST_CHECK(!ParseFixedPoint("31.999999999999999999999", 3, &amount));
11071107
}
11081108

1109-
static void TestOtherThread(fs::path dirname, fs::path lockname, bool *result)
1110-
{
1111-
*result = LockDirectory(dirname, lockname);
1112-
}
1113-
11141109
#ifndef WIN32 // Cannot do this test on WIN32 due to lack of fork()
11151110
static constexpr char LockCommand = 'L';
11161111
static constexpr char UnlockCommand = 'U';
11171112
static constexpr char ExitCommand = 'X';
1113+
enum : char {
1114+
ResSuccess = 2, // Start with 2 to avoid accidental collision with common values 0 and 1
1115+
ResErrorLock,
1116+
ResUnlockSuccess,
1117+
};
11181118

11191119
[[noreturn]] static void TestOtherProcess(fs::path dirname, fs::path lockname, int fd)
11201120
{
11211121
char ch;
11221122
while (true) {
11231123
int rv = read(fd, &ch, 1); // Wait for command
11241124
assert(rv == 1);
1125-
switch(ch) {
1125+
switch (ch) {
11261126
case LockCommand:
1127-
ch = LockDirectory(dirname, lockname);
1127+
ch = [&] {
1128+
switch (util::LockDirectory(dirname, lockname)) {
1129+
case util::LockResult::Success: return ResSuccess;
1130+
case util::LockResult::ErrorLock: return ResErrorLock;
1131+
} // no default case, so the compiler can warn about missing cases
1132+
assert(false);
1133+
}();
11281134
rv = write(fd, &ch, 1);
11291135
assert(rv == 1);
11301136
break;
11311137
case UnlockCommand:
11321138
ReleaseDirectoryLocks();
1133-
ch = true; // Always succeeds
1139+
ch = ResUnlockSuccess; // Always succeeds
11341140
rv = write(fd, &ch, 1);
11351141
assert(rv == 1);
11361142
break;
@@ -1167,51 +1173,51 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory)
11671173
BOOST_CHECK_EQUAL(close(fd[0]), 0); // Parent: close child end
11681174
#endif
11691175
// Lock on non-existent directory should fail
1170-
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname), false);
1176+
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname), util::LockResult::ErrorLock);
11711177

11721178
fs::create_directories(dirname);
11731179

11741180
// Probing lock on new directory should succeed
1175-
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
1181+
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::Success);
11761182

11771183
// Persistent lock on new directory should succeed
1178-
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname), true);
1184+
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname), util::LockResult::Success);
11791185

11801186
// Another lock on the directory from the same thread should succeed
1181-
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname), true);
1187+
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname), util::LockResult::Success);
11821188

11831189
// Another lock on the directory from a different thread within the same process should succeed
1184-
bool threadresult;
1185-
std::thread thr(TestOtherThread, dirname, lockname, &threadresult);
1190+
util::LockResult threadresult;
1191+
std::thread thr([&] { threadresult = util::LockDirectory(dirname, lockname); });
11861192
thr.join();
1187-
BOOST_CHECK_EQUAL(threadresult, true);
1193+
BOOST_CHECK_EQUAL(threadresult, util::LockResult::Success);
11881194
#ifndef WIN32
11891195
// Try to acquire lock in child process while we're holding it, this should fail.
11901196
char ch;
11911197
BOOST_CHECK_EQUAL(write(fd[1], &LockCommand, 1), 1);
11921198
BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1);
1193-
BOOST_CHECK_EQUAL((bool)ch, false);
1199+
BOOST_CHECK_EQUAL(ch, ResErrorLock);
11941200

11951201
// Give up our lock
11961202
ReleaseDirectoryLocks();
11971203
// Probing lock from our side now should succeed, but not hold on to the lock.
1198-
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
1204+
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::Success);
11991205

12001206
// Try to acquire the lock in the child process, this should be successful.
12011207
BOOST_CHECK_EQUAL(write(fd[1], &LockCommand, 1), 1);
12021208
BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1);
1203-
BOOST_CHECK_EQUAL((bool)ch, true);
1209+
BOOST_CHECK_EQUAL(ch, ResSuccess);
12041210

12051211
// When we try to probe the lock now, it should fail.
1206-
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), false);
1212+
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::ErrorLock);
12071213

12081214
// Unlock the lock in the child process
12091215
BOOST_CHECK_EQUAL(write(fd[1], &UnlockCommand, 1), 1);
12101216
BOOST_CHECK_EQUAL(read(fd[1], &ch, 1), 1);
1211-
BOOST_CHECK_EQUAL((bool)ch, true);
1217+
BOOST_CHECK_EQUAL(ch, ResUnlockSuccess);
12121218

12131219
// When we try to probe the lock now, it should succeed.
1214-
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
1220+
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::Success);
12151221

12161222
// Re-lock the lock in the child process, then wait for it to exit, check
12171223
// successful return. After that, we check that exiting the process
@@ -1221,7 +1227,7 @@ BOOST_AUTO_TEST_CASE(test_LockDirectory)
12211227
BOOST_CHECK_EQUAL(write(fd[1], &ExitCommand, 1), 1);
12221228
BOOST_CHECK_EQUAL(waitpid(pid, &processstatus, 0), pid);
12231229
BOOST_CHECK_EQUAL(processstatus, 0);
1224-
BOOST_CHECK_EQUAL(LockDirectory(dirname, lockname, true), true);
1230+
BOOST_CHECK_EQUAL(util::LockDirectory(dirname, lockname, true), util::LockResult::Success);
12251231

12261232
// Restore SIGCHLD
12271233
signal(SIGCHLD, old_handler);

src/util/fs_helpers.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -53,31 +53,32 @@ static GlobalMutex cs_dir_locks;
5353
* is called.
5454
*/
5555
static std::map<std::string, std::unique_ptr<fsbridge::FileLock>> dir_locks GUARDED_BY(cs_dir_locks);
56-
57-
bool LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only)
56+
namespace util {
57+
LockResult LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only)
5858
{
5959
LOCK(cs_dir_locks);
6060
fs::path pathLockFile = directory / lockfile_name;
6161

6262
// If a lock for this directory already exists in the map, don't try to re-lock it
6363
if (dir_locks.count(fs::PathToString(pathLockFile))) {
64-
return true;
64+
return LockResult::Success;
6565
}
6666

6767
// Create empty lock file if it doesn't exist.
6868
FILE* file = fsbridge::fopen(pathLockFile, "a");
6969
if (file) fclose(file);
7070
auto lock = std::make_unique<fsbridge::FileLock>(pathLockFile);
7171
if (!lock->TryLock()) {
72-
return error("Error while attempting to lock directory %s: %s", fs::PathToString(directory), lock->GetReason());
72+
error("Error while attempting to lock directory %s: %s", fs::PathToString(directory), lock->GetReason());
73+
return LockResult::ErrorLock;
7374
}
7475
if (!probe_only) {
7576
// Lock successful and we're not just probing, put it into the map
7677
dir_locks.emplace(fs::PathToString(pathLockFile), std::move(lock));
7778
}
78-
return true;
79+
return LockResult::Success;
7980
}
80-
81+
} // namespace util
8182
void UnlockDirectory(const fs::path& directory, const fs::path& lockfile_name)
8283
{
8384
LOCK(cs_dir_locks);

src/util/fs_helpers.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,13 @@ void AllocateFileRange(FILE* file, unsigned int offset, unsigned int length);
3535
*/
3636
[[nodiscard]] bool RenameOver(fs::path src, fs::path dest);
3737

38-
bool LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only = false);
38+
namespace util {
39+
enum class LockResult {
40+
Success,
41+
ErrorLock,
42+
};
43+
[[nodiscard]] LockResult LockDirectory(const fs::path& directory, const fs::path& lockfile_name, bool probe_only = false);
44+
} // namespace util
3945
void UnlockDirectory(const fs::path& directory, const fs::path& lockfile_name);
4046
bool DirIsWritable(const fs::path& directory);
4147
bool CheckDiskSpace(const fs::path& dir, uint64_t additional_bytes = 0);

src/wallet/bdb.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ bool BerkeleyEnvironment::Open(bilingual_str& err)
149149

150150
fs::path pathIn = fs::PathFromString(strPath);
151151
TryCreateDirectories(pathIn);
152-
if (!LockDirectory(pathIn, ".walletlock")) {
152+
if (util::LockDirectory(pathIn, ".walletlock") != util::LockResult::Success) {
153153
LogPrintf("Cannot obtain a lock on wallet directory %s. Another instance may be using it.\n", strPath);
154154
err = strprintf(_("Error initializing wallet database environment %s!"), fs::quoted(fs::PathToString(Directory())));
155155
return false;

0 commit comments

Comments
 (0)