Skip to content

Commit a9969c4

Browse files
committed
[Support] Remove output file checks from LockFileManager
Currently, `LockFileManager` assumes the owner of the lock file creates an output file. This is problematic for at least three reasons: 1. It is orthogonal to the main purpose of this class - mutual exclusion. This makes creating an alternative implementation more complicated than it needs to be. 2. Some clients (like the upstream `AMDGPUSplitModule.cpp` file) assume the output file is not necessary. The owner of the lock file does not write the file expected by `LockFileManager` and processes waiting for the non-owned lock file therefore assume the owner has died. This means that the work gets repeated by each waiting process, serially. 3. The documentation makes it sound like successfully waiting for a non-owned lock file guarantees the output file to be present on the file system. Implicitly-built modules rely on this. However, the module file may disappear between `LockFileManager` performing the check and the compiler loading the module (for example due to module cache pruning with short intervals, or intervention from outside of Clang). The compiler assumes this cannot happen, and fails the build if it does. This PR solves this situation by removing the check, reflecting that in the `LockFileManager` documentation, and fixing the time-of-check time-of-use bug in implicit modules.
1 parent 7602d78 commit a9969c4

File tree

3 files changed

+27
-26
lines changed

3 files changed

+27
-26
lines changed

clang/lib/Frontend/CompilerInstance.cpp

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,7 +1406,7 @@ static bool readASTAfterCompileModule(CompilerInstance &ImportingInstance,
14061406
SourceLocation ImportLoc,
14071407
SourceLocation ModuleNameLoc,
14081408
Module *Module, StringRef ModuleFileName,
1409-
bool *OutOfDate) {
1409+
bool *OutOfDate, bool *Missing) {
14101410
DiagnosticsEngine &Diags = ImportingInstance.getDiagnostics();
14111411

14121412
unsigned ModuleLoadCapabilities = ASTReader::ARR_Missing;
@@ -1427,6 +1427,12 @@ static bool readASTAfterCompileModule(CompilerInstance &ImportingInstance,
14271427
return false;
14281428
}
14291429

1430+
// The caller wants to handle missing module files.
1431+
if (Missing && ReadResult == ASTReader::Missing) {
1432+
*Missing = true;
1433+
return false;
1434+
}
1435+
14301436
// The ASTReader didn't diagnose the error, so conservatively report it.
14311437
if (ReadResult == ASTReader::Missing || !Diags.hasErrorOccurred())
14321438
Diags.Report(ModuleNameLoc, diag::err_module_not_built)
@@ -1452,7 +1458,7 @@ static bool compileModuleAndReadASTImpl(CompilerInstance &ImportingInstance,
14521458

14531459
return readASTAfterCompileModule(ImportingInstance, ImportLoc, ModuleNameLoc,
14541460
Module, ModuleFileName,
1455-
/*OutOfDate=*/nullptr);
1461+
/*OutOfDate=*/nullptr, /*Missing=*/nullptr);
14561462
}
14571463

14581464
/// Compile a module in a separate compiler instance and read the AST,
@@ -1517,15 +1523,17 @@ static bool compileModuleAndReadASTBehindLock(
15171523

15181524
// Read the module that was just written by someone else.
15191525
bool OutOfDate = false;
1526+
bool Missing = false;
15201527
if (readASTAfterCompileModule(ImportingInstance, ImportLoc, ModuleNameLoc,
1521-
Module, ModuleFileName, &OutOfDate))
1528+
Module, ModuleFileName, &OutOfDate, &Missing))
15221529
return true;
1523-
if (!OutOfDate)
1530+
if (!OutOfDate && !Missing)
15241531
return false;
15251532

1526-
// The module may be out of date in the presence of file system races,
1527-
// or if one of its imports depends on header search paths that are not
1528-
// consistent with this ImportingInstance. Try again...
1533+
// The module may be missing or out of date in the presence of file system
1534+
// races. It may also be out of date if one of its imports depends on header
1535+
// search paths that are not consistent with this ImportingInstance.
1536+
// Try again...
15291537
}
15301538
}
15311539

llvm/include/llvm/Support/LockFileManager.h

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@
1616
namespace llvm {
1717
class StringRef;
1818

19-
/// Class that manages the creation of a lock file to aid
20-
/// implicit coordination between different processes.
19+
/// Class that manages the creation of a lock file to aid implicit coordination
20+
/// between different processes.
2121
///
22-
/// The implicit coordination works by creating a ".lock" file alongside
23-
/// the file that we're coordinating for, using the atomicity of the file
24-
/// system to ensure that only a single process can create that ".lock" file.
25-
/// When the lock file is removed, the owning process has finished the
26-
/// operation.
22+
/// The implicit coordination works by creating a ".lock" file, using the
23+
/// atomicity of the file system to ensure that only a single process can create
24+
/// that ".lock" file. When the lock file is removed, the owning process has
25+
/// finished the operation.
2726
class LockFileManager {
2827
public:
2928
/// Describes the state of a lock file.
@@ -50,7 +49,6 @@ class LockFileManager {
5049
};
5150

5251
private:
53-
SmallString<128> FileName;
5452
SmallString<128> LockFileName;
5553
SmallString<128> UniqueLockFileName;
5654

llvm/lib/Support/LockFileManager.cpp

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -157,16 +157,15 @@ class RemoveUniqueLockFileOnSignal {
157157

158158
} // end anonymous namespace
159159

160-
LockFileManager::LockFileManager(StringRef FileName)
161-
{
162-
this->FileName = FileName;
163-
if (std::error_code EC = sys::fs::make_absolute(this->FileName)) {
160+
LockFileManager::LockFileManager(StringRef FileName) {
161+
SmallString<128> AbsoluteFileName(FileName);
162+
if (std::error_code EC = sys::fs::make_absolute(AbsoluteFileName)) {
164163
std::string S("failed to obtain absolute path for ");
165-
S.append(std::string(this->FileName));
164+
S.append(std::string(AbsoluteFileName));
166165
setError(EC, S);
167166
return;
168167
}
169-
LockFileName = this->FileName;
168+
LockFileName = AbsoluteFileName;
170169
LockFileName += ".lock";
171170

172171
// If the lock file already exists, don't bother to try to create our own
@@ -307,12 +306,8 @@ LockFileManager::waitForUnlock(const unsigned MaxSeconds) {
307306
while (Backoff.waitForNextAttempt()) {
308307
// FIXME: implement event-based waiting
309308
if (sys::fs::access(LockFileName.c_str(), sys::fs::AccessMode::Exist) ==
310-
errc::no_such_file_or_directory) {
311-
// If the original file wasn't created, somone thought the lock was dead.
312-
if (!sys::fs::exists(FileName))
313-
return Res_OwnerDied;
309+
errc::no_such_file_or_directory)
314310
return Res_Success;
315-
}
316311

317312
// If the process owning the lock died without cleaning up, just bail out.
318313
if (!processStillExecuting((*Owner).first, (*Owner).second))

0 commit comments

Comments
 (0)