Skip to content

Commit 8a983fc

Browse files
committed
Keep more state, add asserts, update tests
1 parent 45975fe commit 8a983fc

File tree

3 files changed

+38
-18
lines changed

3 files changed

+38
-18
lines changed

llvm/include/llvm/Support/LockFileManager.h

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,19 +42,26 @@ class LockFileManager {
4242
SmallString<128> LockFileName;
4343
SmallString<128> UniqueLockFileName;
4444

45-
std::optional<std::pair<std::string, int>> Owner;
45+
struct OwnerUnknown {};
46+
struct OwnedByUs{};
47+
struct OwnedByAnother {
48+
std::string OwnerHostName;
49+
int OwnerPID;
50+
};
51+
std::variant<OwnerUnknown, OwnedByUs, OwnedByAnother> Owner;
4652

4753
LockFileManager(const LockFileManager &) = delete;
4854
LockFileManager &operator=(const LockFileManager &) = delete;
4955

50-
static std::optional<std::pair<std::string, int>>
51-
readLockFile(StringRef LockFileName);
56+
static std::optional<OwnedByAnother> readLockFile(StringRef LockFileName);
5257

5358
static bool processStillExecuting(StringRef Hostname, int PID);
5459

5560
public:
56-
61+
/// Does not try to acquire the lock.
5762
LockFileManager(StringRef FileName);
63+
64+
/// Unlocks the lock if previously acquired by \c tryLock().
5865
~LockFileManager();
5966

6067
/// Tries to acquire the lock without blocking.

llvm/lib/Support/LockFileManager.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ using namespace llvm;
5151
/// \param LockFileName The name of the lock file to read.
5252
///
5353
/// \returns The process ID of the process that owns this lock file
54-
std::optional<std::pair<std::string, int>>
54+
std::optional<LockFileManager::OwnedByAnother>
5555
LockFileManager::readLockFile(StringRef LockFileName) {
5656
// Read the owning host and PID out of the lock file. If it appears that the
5757
// owning process is dead, the lock file is invalid.
@@ -69,8 +69,10 @@ LockFileManager::readLockFile(StringRef LockFileName) {
6969
PIDStr = PIDStr.substr(PIDStr.find_first_not_of(' '));
7070
int PID;
7171
if (!PIDStr.getAsInteger(10, PID)) {
72-
auto Owner = std::make_pair(std::string(Hostname), PID);
73-
if (processStillExecuting(Owner.first, Owner.second))
72+
OwnedByAnother Owner;
73+
Owner.OwnerHostName = Hostname;
74+
Owner.OwnerPID = PID;
75+
if (processStillExecuting(Owner.OwnerHostName, Owner.OwnerPID))
7476
return Owner;
7577
}
7678

@@ -157,9 +159,13 @@ class RemoveUniqueLockFileOnSignal {
157159

158160
} // end anonymous namespace
159161

160-
LockFileManager::LockFileManager(StringRef FileName) : FileName(FileName) {}
162+
LockFileManager::LockFileManager(StringRef FileName)
163+
: FileName(FileName), Owner(OwnerUnknown{}) {}
161164

162165
Expected<bool> LockFileManager::tryLock() {
166+
assert(std::holds_alternative<OwnerUnknown>(Owner) &&
167+
"lock has already been attempted");
168+
163169
SmallString<128> AbsoluteFileName(FileName);
164170
if (std::error_code EC = sys::fs::make_absolute(AbsoluteFileName))
165171
return createStringError("failed to obtain absolute path for " +
@@ -169,8 +175,10 @@ Expected<bool> LockFileManager::tryLock() {
169175

170176
// If the lock file already exists, don't bother to try to create our own
171177
// lock file; it won't work anyway. Just figure out who owns this lock file.
172-
if ((Owner = readLockFile(LockFileName)))
178+
if (auto LockFileOwner = readLockFile(LockFileName)) {
179+
Owner = std::move(*LockFileOwner);
173180
return false;
181+
}
174182

175183
// Create a lock file that is unique to this instance.
176184
UniqueLockFileName = LockFileName;
@@ -213,6 +221,7 @@ Expected<bool> LockFileManager::tryLock() {
213221
sys::fs::create_link(UniqueLockFileName, LockFileName);
214222
if (!EC) {
215223
RemoveUniqueFile.lockAcquired();
224+
Owner = OwnedByUs{};
216225
return true;
217226
}
218227

@@ -222,9 +231,10 @@ Expected<bool> LockFileManager::tryLock() {
222231

223232
// Someone else managed to create the lock file first. Read the process ID
224233
// from the lock file.
225-
if ((Owner = readLockFile(LockFileName))) {
234+
if (auto LockFileOwner = readLockFile(LockFileName)) {
226235
// Wipe out our unique lock file (it's useless now)
227236
sys::fs::remove(UniqueLockFileName);
237+
Owner = std::move(*LockFileOwner);
228238
return false;
229239
}
230240

@@ -243,7 +253,7 @@ Expected<bool> LockFileManager::tryLock() {
243253
}
244254

245255
LockFileManager::~LockFileManager() {
246-
if (Owner)
256+
if (!std::holds_alternative<OwnedByUs>(Owner))
247257
return;
248258

249259
// Since we own the lock, remove the lock file and our own unique lock file.
@@ -256,8 +266,9 @@ LockFileManager::~LockFileManager() {
256266

257267
LockFileManager::WaitForUnlockResult
258268
LockFileManager::waitForUnlock(const unsigned MaxSeconds) {
259-
if (!Owner)
260-
return Res_Success;
269+
auto *LockFileOwner = std::get_if<OwnedByAnother>(&Owner);
270+
assert(LockFileOwner &&
271+
"waiting for lock to be unlocked without knowing the owner");
261272

262273
// Since we don't yet have an event-based method to wait for the lock file,
263274
// use randomized exponential backoff, similar to Ethernet collision
@@ -278,7 +289,8 @@ LockFileManager::waitForUnlock(const unsigned MaxSeconds) {
278289
}
279290

280291
// If the process owning the lock died without cleaning up, just bail out.
281-
if (!processStillExecuting((*Owner).first, (*Owner).second))
292+
if (!processStillExecuting(LockFileOwner->OwnerHostName,
293+
LockFileOwner->OwnerPID))
282294
return Res_OwnerDied;
283295
}
284296

llvm/unittests/Support/LockFileManagerTest.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "llvm/Support/LockFileManager.h"
1010
#include "llvm/Support/FileSystem.h"
1111
#include "llvm/Support/Path.h"
12+
#include "llvm/Testing/Support/Error.h"
1213
#include "llvm/Testing/Support/SupportHelpers.h"
1314
#include "gtest/gtest.h"
1415
#include <memory>
@@ -27,12 +28,12 @@ TEST(LockFileManagerTest, Basic) {
2728
{
2829
// The lock file should not exist, so we should successfully acquire it.
2930
LockFileManager Locked1(LockedFile);
30-
EXPECT_EQ(LockFileManager::LFS_Owned, Locked1.getState());
31+
EXPECT_THAT_EXPECTED(Locked1.tryLock(), HasValue(true));
3132

3233
// Attempting to reacquire the lock should fail. Waiting on it would cause
3334
// deadlock, so don't try that.
3435
LockFileManager Locked2(LockedFile);
35-
EXPECT_NE(LockFileManager::LFS_Owned, Locked2.getState());
36+
EXPECT_THAT_EXPECTED(Locked2.tryLock(), HasValue(false));
3637
}
3738

3839
// Now that the lock is out of scope, the file should be gone.
@@ -68,7 +69,7 @@ TEST(LockFileManagerTest, LinkLockExists) {
6869
// The lock file doesn't point to a real file, so we should successfully
6970
// acquire it.
7071
LockFileManager Locked(LockedFile);
71-
EXPECT_EQ(LockFileManager::LFS_Owned, Locked.getState());
72+
EXPECT_THAT_EXPECTED(Locked.tryLock(), HasValue(true));
7273
}
7374

7475
// Now that the lock is out of scope, the file should be gone.
@@ -93,7 +94,7 @@ TEST(LockFileManagerTest, RelativePath) {
9394
{
9495
// The lock file should not exist, so we should successfully acquire it.
9596
LockFileManager Locked(LockedFile);
96-
EXPECT_EQ(LockFileManager::LFS_Owned, Locked.getState());
97+
EXPECT_THAT_EXPECTED(Locked.tryLock(), HasValue(true));
9798
EXPECT_TRUE(sys::fs::exists(FileLock.str()));
9899
}
99100

0 commit comments

Comments
 (0)