Skip to content

Commit dafb566

Browse files
authored
[Support] Return LockFileManager errors right away (#130627)
This patch removes some internal state out of `LockFileManager` by moving the locking code from the constructor into new member function `tryLock()` which returns the errors right away. This simplifies and modernizes the interface.
1 parent 7573ee1 commit dafb566

File tree

6 files changed

+95
-140
lines changed

6 files changed

+95
-140
lines changed

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1483,29 +1483,28 @@ static bool compileModuleAndReadASTBehindLock(
14831483
llvm::sys::fs::create_directories(Dir);
14841484

14851485
while (true) {
1486-
llvm::LockFileManager Locked(ModuleFileName);
1487-
switch (Locked) {
1488-
case llvm::LockFileManager::LFS_Error:
1486+
llvm::LockFileManager Lock(ModuleFileName);
1487+
bool Owned;
1488+
if (llvm::Error Err = Lock.tryLock().moveInto(Owned)) {
14891489
// ModuleCache takes care of correctness and locks are only necessary for
14901490
// performance. Fallback to building the module in case of any lock
14911491
// related errors.
14921492
Diags.Report(ModuleNameLoc, diag::remark_module_lock_failure)
1493-
<< Module->Name << Locked.getErrorMessage();
1493+
<< Module->Name << toString(std::move(Err));
14941494
// Clear out any potential leftover.
1495-
Locked.unsafeRemoveLockFile();
1496-
[[fallthrough]];
1497-
case llvm::LockFileManager::LFS_Owned:
1495+
Lock.unsafeRemoveLockFile();
1496+
return compileModuleAndReadASTImpl(ImportingInstance, ImportLoc,
1497+
ModuleNameLoc, Module, ModuleFileName);
1498+
}
1499+
if (Owned) {
14981500
// We're responsible for building the module ourselves.
14991501
return compileModuleAndReadASTImpl(ImportingInstance, ImportLoc,
15001502
ModuleNameLoc, Module, ModuleFileName);
1501-
1502-
case llvm::LockFileManager::LFS_Shared:
1503-
break; // The interesting case.
15041503
}
15051504

15061505
// Someone else is responsible for building the module. Wait for them to
15071506
// finish.
1508-
switch (Locked.waitForUnlock()) {
1507+
switch (Lock.waitForUnlock()) {
15091508
case llvm::LockFileManager::Res_Success:
15101509
break; // The interesting case.
15111510
case llvm::LockFileManager::Res_OwnerDied:
@@ -1517,7 +1516,7 @@ static bool compileModuleAndReadASTBehindLock(
15171516
Diags.Report(ModuleNameLoc, diag::remark_module_lock_timeout)
15181517
<< Module->Name;
15191518
// Clear the lock file so that future invocations can make progress.
1520-
Locked.unsafeRemoveLockFile();
1519+
Lock.unsafeRemoveLockFile();
15211520
continue;
15221521
}
15231522

clang/lib/Serialization/GlobalModuleIndex.cpp

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -849,22 +849,21 @@ GlobalModuleIndex::writeIndex(FileManager &FileMgr,
849849

850850
// Coordinate building the global index file with other processes that might
851851
// try to do the same.
852-
llvm::LockFileManager Locked(IndexPath);
853-
switch (Locked) {
854-
case llvm::LockFileManager::LFS_Error:
852+
llvm::LockFileManager Lock(IndexPath);
853+
bool Owned;
854+
if (llvm::Error Err = Lock.tryLock().moveInto(Owned)) {
855+
llvm::consumeError(std::move(Err));
855856
return llvm::createStringError(std::errc::io_error, "LFS error");
856-
857-
case llvm::LockFileManager::LFS_Owned:
858-
// We're responsible for building the index ourselves. Do so below.
859-
break;
860-
861-
case llvm::LockFileManager::LFS_Shared:
857+
}
858+
if (!Owned) {
862859
// Someone else is responsible for building the index. We don't care
863860
// when they finish, so we're done.
864861
return llvm::createStringError(std::errc::device_or_resource_busy,
865862
"someone else is building the index");
866863
}
867864

865+
// We're responsible for building the index ourselves.
866+
868867
// The module index builder.
869868
GlobalModuleIndexBuilder Builder(FileMgr, PCHContainerRdr);
870869

llvm/include/llvm/Support/LockFileManager.h

Lines changed: 18 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@
99
#define LLVM_SUPPORT_LOCKFILEMANAGER_H
1010

1111
#include "llvm/ADT/SmallString.h"
12+
#include "llvm/Support/Error.h"
1213
#include <optional>
14+
#include <string>
1315
#include <system_error>
14-
#include <utility> // for std::pair
16+
#include <variant>
1517

1618
namespace llvm {
1719
class StringRef;
@@ -25,19 +27,6 @@ class StringRef;
2527
/// finished the operation.
2628
class LockFileManager {
2729
public:
28-
/// Describes the state of a lock file.
29-
enum LockFileState {
30-
/// The lock file has been created and is owned by this instance
31-
/// of the object.
32-
LFS_Owned,
33-
/// The lock file already exists and is owned by some other
34-
/// instance.
35-
LFS_Shared,
36-
/// An error occurred while trying to create or find the lock
37-
/// file.
38-
LFS_Error
39-
};
40-
4130
/// Describes the result of waiting for the owner to release the lock.
4231
enum WaitForUnlockResult {
4332
/// The lock was released successfully.
@@ -53,27 +42,32 @@ class LockFileManager {
5342
SmallString<128> LockFileName;
5443
SmallString<128> UniqueLockFileName;
5544

56-
std::optional<std::pair<std::string, int>> Owner;
57-
std::error_code ErrorCode;
58-
std::string ErrorDiagMsg;
45+
struct OwnerUnknown {};
46+
struct OwnedByUs {};
47+
struct OwnedByAnother {
48+
std::string OwnerHostName;
49+
int OwnerPID;
50+
};
51+
std::variant<OwnerUnknown, OwnedByUs, OwnedByAnother> Owner;
5952

6053
LockFileManager(const LockFileManager &) = delete;
6154
LockFileManager &operator=(const LockFileManager &) = delete;
6255

63-
static std::optional<std::pair<std::string, int>>
64-
readLockFile(StringRef LockFileName);
56+
static std::optional<OwnedByAnother> readLockFile(StringRef LockFileName);
6557

6658
static bool processStillExecuting(StringRef Hostname, int PID);
6759

6860
public:
69-
61+
/// Does not try to acquire the lock.
7062
LockFileManager(StringRef FileName);
71-
~LockFileManager();
7263

73-
/// Determine the state of the lock file.
74-
LockFileState getState() const;
64+
/// Unlocks the lock if previously acquired by \c tryLock().
65+
~LockFileManager();
7566

76-
operator LockFileState() const { return getState(); }
67+
/// Tries to acquire the lock without blocking.
68+
/// \returns true if the lock was successfully acquired, false if the lock is
69+
/// already held by someone else, or \c Error in case of unexpected failure.
70+
Expected<bool> tryLock();
7771

7872
/// For a shared lock, wait until the owner releases the lock.
7973
/// Total timeout for the file to appear is ~1.5 minutes.
@@ -83,15 +77,6 @@ class LockFileManager {
8377
/// Remove the lock file. This may delete a different lock file than
8478
/// the one previously read if there is a race.
8579
std::error_code unsafeRemoveLockFile();
86-
87-
/// Get error message, or "" if there is no error.
88-
std::string getErrorMessage() const;
89-
90-
/// Set error and error message
91-
void setError(const std::error_code &EC, StringRef ErrorMsg = "") {
92-
ErrorCode = EC;
93-
ErrorDiagMsg = ErrorMsg.str();
94-
}
9580
};
9681

9782
} // end namespace llvm

llvm/lib/Support/LockFileManager.cpp

Lines changed: 45 additions & 70 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

@@ -158,41 +160,40 @@ class RemoveUniqueLockFileOnSignal {
158160
} // end anonymous namespace
159161

160162
LockFileManager::LockFileManager(StringRef FileName)
161-
{
162-
this->FileName = FileName;
163-
if (std::error_code EC = sys::fs::make_absolute(this->FileName)) {
164-
std::string S("failed to obtain absolute path for ");
165-
S.append(std::string(this->FileName));
166-
setError(EC, S);
167-
return;
168-
}
169-
LockFileName = this->FileName;
163+
: FileName(FileName), Owner(OwnerUnknown{}) {}
164+
165+
Expected<bool> LockFileManager::tryLock() {
166+
assert(std::holds_alternative<OwnerUnknown>(Owner) &&
167+
"lock has already been attempted");
168+
169+
SmallString<128> AbsoluteFileName(FileName);
170+
if (std::error_code EC = sys::fs::make_absolute(AbsoluteFileName))
171+
return createStringError(EC, "failed to obtain absolute path for " +
172+
AbsoluteFileName);
173+
LockFileName = AbsoluteFileName;
170174
LockFileName += ".lock";
171175

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

177183
// Create a lock file that is unique to this instance.
178184
UniqueLockFileName = LockFileName;
179185
UniqueLockFileName += "-%%%%%%%%";
180186
int UniqueLockFileID;
181187
if (std::error_code EC = sys::fs::createUniqueFile(
182-
UniqueLockFileName, UniqueLockFileID, UniqueLockFileName)) {
183-
std::string S("failed to create unique file ");
184-
S.append(std::string(UniqueLockFileName));
185-
setError(EC, S);
186-
return;
187-
}
188+
UniqueLockFileName, UniqueLockFileID, UniqueLockFileName))
189+
return createStringError(EC, "failed to create unique file " +
190+
UniqueLockFileName);
188191

189192
// Write our process ID to our unique lock file.
190193
{
191194
SmallString<256> HostID;
192-
if (auto EC = getHostID(HostID)) {
193-
setError(EC, "failed to get host id");
194-
return;
195-
}
195+
if (auto EC = getHostID(HostID))
196+
return createStringError(EC, "failed to get host id");
196197

197198
raw_fd_ostream Out(UniqueLockFileID, /*shouldClose=*/true);
198199
Out << HostID << ' ' << sys::Process::getProcessId();
@@ -201,13 +202,12 @@ LockFileManager::LockFileManager(StringRef FileName)
201202
if (Out.has_error()) {
202203
// We failed to write out PID, so report the error, remove the
203204
// unique lock file, and fail.
204-
std::string S("failed to write to ");
205-
S.append(std::string(UniqueLockFileName));
206-
setError(Out.error(), S);
205+
Error Err = createStringError(Out.error(),
206+
"failed to write to " + UniqueLockFileName);
207207
sys::fs::remove(UniqueLockFileName);
208208
// Don't call report_fatal_error.
209209
Out.clear_error();
210-
return;
210+
return std::move(Err);
211211
}
212212
}
213213

@@ -221,23 +221,21 @@ LockFileManager::LockFileManager(StringRef FileName)
221221
sys::fs::create_link(UniqueLockFileName, LockFileName);
222222
if (!EC) {
223223
RemoveUniqueFile.lockAcquired();
224-
return;
224+
Owner = OwnedByUs{};
225+
return true;
225226
}
226227

227-
if (EC != errc::file_exists) {
228-
std::string S("failed to create link ");
229-
raw_string_ostream OSS(S);
230-
OSS << LockFileName.str() << " to " << UniqueLockFileName.str();
231-
setError(EC, S);
232-
return;
233-
}
228+
if (EC != errc::file_exists)
229+
return createStringError(EC, "failed to create link " + LockFileName +
230+
" to " + UniqueLockFileName);
234231

235232
// Someone else managed to create the lock file first. Read the process ID
236233
// from the lock file.
237-
if ((Owner = readLockFile(LockFileName))) {
234+
if (auto LockFileOwner = readLockFile(LockFileName)) {
238235
// Wipe out our unique lock file (it's useless now)
239236
sys::fs::remove(UniqueLockFileName);
240-
return;
237+
Owner = std::move(*LockFileOwner);
238+
return false;
241239
}
242240

243241
if (!sys::fs::exists(LockFileName)) {
@@ -248,39 +246,14 @@ LockFileManager::LockFileManager(StringRef FileName)
248246

249247
// There is a lock file that nobody owns; try to clean it up and get
250248
// ownership.
251-
if ((EC = sys::fs::remove(LockFileName))) {
252-
std::string S("failed to remove lockfile ");
253-
S.append(std::string(UniqueLockFileName));
254-
setError(EC, S);
255-
return;
256-
}
257-
}
258-
}
259-
260-
LockFileManager::LockFileState LockFileManager::getState() const {
261-
if (Owner)
262-
return LFS_Shared;
263-
264-
if (ErrorCode)
265-
return LFS_Error;
266-
267-
return LFS_Owned;
268-
}
269-
270-
std::string LockFileManager::getErrorMessage() const {
271-
if (ErrorCode) {
272-
std::string Str(ErrorDiagMsg);
273-
std::string ErrCodeMsg = ErrorCode.message();
274-
raw_string_ostream OSS(Str);
275-
if (!ErrCodeMsg.empty())
276-
OSS << ": " << ErrCodeMsg;
277-
return Str;
249+
if ((EC = sys::fs::remove(LockFileName)))
250+
return createStringError(EC, "failed to remove lockfile " +
251+
UniqueLockFileName);
278252
}
279-
return "";
280253
}
281254

282255
LockFileManager::~LockFileManager() {
283-
if (getState() != LFS_Owned)
256+
if (!std::holds_alternative<OwnedByUs>(Owner))
284257
return;
285258

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

294267
LockFileManager::WaitForUnlockResult
295268
LockFileManager::waitForUnlock(const unsigned MaxSeconds) {
296-
if (getState() != LFS_Shared)
297-
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");
298272

299273
// Since we don't yet have an event-based method to wait for the lock file,
300274
// use randomized exponential backoff, similar to Ethernet collision
@@ -311,7 +285,8 @@ LockFileManager::waitForUnlock(const unsigned MaxSeconds) {
311285
return Res_Success;
312286

313287
// If the process owning the lock died without cleaning up, just bail out.
314-
if (!processStillExecuting((*Owner).first, (*Owner).second))
288+
if (!processStillExecuting(LockFileOwner->OwnerHostName,
289+
LockFileOwner->OwnerPID))
315290
return Res_OwnerDied;
316291
}
317292

0 commit comments

Comments
 (0)