|
36 | 36 | #include "llvm/Support/Errc.h"
|
37 | 37 | #include "llvm/Support/Regex.h"
|
38 | 38 | #include "llvm/Support/StringSaver.h"
|
| 39 | +#include "llvm/Support/LockFileManager.h" |
39 | 40 |
|
40 | 41 | using namespace swift;
|
41 | 42 | using FileDependency = SerializationOptions::FileDependency;
|
@@ -240,7 +241,7 @@ bool ModuleInterfaceBuilder::collectDepsForSerialization(
|
240 | 241 | return false;
|
241 | 242 | }
|
242 | 243 |
|
243 |
| -bool ModuleInterfaceBuilder::buildSwiftModule( |
| 244 | +bool ModuleInterfaceBuilder::buildSwiftModuleInternal( |
244 | 245 | StringRef OutPath, bool ShouldSerializeDeps,
|
245 | 246 | std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer) {
|
246 | 247 | bool SubError = false;
|
@@ -384,3 +385,71 @@ bool ModuleInterfaceBuilder::buildSwiftModule(
|
384 | 385 | });
|
385 | 386 | return !RunSuccess || SubError;
|
386 | 387 | }
|
| 388 | + |
| 389 | +bool ModuleInterfaceBuilder::buildSwiftModule(StringRef OutPath, |
| 390 | + bool ShouldSerializeDeps, |
| 391 | + std::unique_ptr<llvm::MemoryBuffer> *ModuleBuffer, |
| 392 | + llvm::function_ref<void()> RemarkRebuild) { |
| 393 | + |
| 394 | + while (1) { |
| 395 | + // Attempt to lock the interface file. Only one process is allowed to build |
| 396 | + // module from the interface so we don't consume too much memory when multiple |
| 397 | + // processes are doing the same. |
| 398 | + // FIXME: We should surface the module building step to the build system so |
| 399 | + // we don't need to synchronize here. |
| 400 | + llvm::LockFileManager Locked(interfacePath); |
| 401 | + switch (Locked) { |
| 402 | + case llvm::LockFileManager::LFS_Error:{ |
| 403 | + // ModuleInterfaceBuilder takes care of correctness and locks are only |
| 404 | + // necessary for performance. Fallback to building the module in case of any lock |
| 405 | + // related errors. |
| 406 | + if (RemarkRebuild) { |
| 407 | + diags.diagnose(SourceLoc(), diag::interface_file_lock_failure, |
| 408 | + interfacePath); |
| 409 | + } |
| 410 | + // Clear out any potential leftover. |
| 411 | + Locked.unsafeRemoveLockFile(); |
| 412 | + LLVM_FALLTHROUGH; |
| 413 | + } |
| 414 | + case llvm::LockFileManager::LFS_Owned: { |
| 415 | + if (RemarkRebuild) { |
| 416 | + RemarkRebuild(); |
| 417 | + } |
| 418 | + return buildSwiftModuleInternal(OutPath, ShouldSerializeDeps, ModuleBuffer); |
| 419 | + } |
| 420 | + case llvm::LockFileManager::LFS_Shared: { |
| 421 | + // Someone else is responsible for building the module. Wait for them to |
| 422 | + // finish. |
| 423 | + switch (Locked.waitForUnlock()) { |
| 424 | + case llvm::LockFileManager::Res_Success: { |
| 425 | + // This process may have a different module output path. If the other |
| 426 | + // process doesn't build the interface to this output path, we should try |
| 427 | + // building ourselves. |
| 428 | + auto bufferOrError = llvm::MemoryBuffer::getFile(OutPath); |
| 429 | + if (!bufferOrError) |
| 430 | + continue; |
| 431 | + if (ModuleBuffer) |
| 432 | + *ModuleBuffer = std::move(bufferOrError.get()); |
| 433 | + return false; |
| 434 | + } |
| 435 | + case llvm::LockFileManager::Res_OwnerDied: { |
| 436 | + continue; // try again to get the lock. |
| 437 | + } |
| 438 | + case llvm::LockFileManager::Res_Timeout: { |
| 439 | + // Since ModuleInterfaceBuilder takes care of correctness, we try waiting for |
| 440 | + // another process to complete the build so swift does not do it done |
| 441 | + // twice. If case of timeout, build it ourselves. |
| 442 | + if (RemarkRebuild) { |
| 443 | + diags.diagnose(SourceLoc(), diag::interface_file_lock_timed_out, |
| 444 | + interfacePath); |
| 445 | + } |
| 446 | + // Clear the lock file so that future invocations can make progress. |
| 447 | + Locked.unsafeRemoveLockFile(); |
| 448 | + continue; |
| 449 | + } |
| 450 | + } |
| 451 | + break; |
| 452 | + } |
| 453 | + } |
| 454 | + } |
| 455 | +} |
0 commit comments