|
10 | 10 | #include "llvm/Config/llvm-config.h" |
11 | 11 | #include "llvm/Support/CommandLine.h" |
12 | 12 | #include "llvm/Support/ConvertUTF.h" |
| 13 | +#include "llvm/Support/ExponentialBackoff.h" |
13 | 14 | #include "llvm/Support/FileSystem.h" |
14 | 15 | #include "llvm/Support/Path.h" |
15 | 16 | #include "llvm/Support/Signals.h" |
@@ -573,6 +574,88 @@ TEST_F(ProgramEnvTest, TestLockFile) { |
573 | 574 | sys::fs::remove(LockedFile); |
574 | 575 | } |
575 | 576 |
|
| 577 | +TEST_F(ProgramEnvTest, TestLockFileExclusive) { |
| 578 | + using namespace llvm::sys; |
| 579 | + using namespace std::chrono_literals; |
| 580 | + |
| 581 | + if (const char *LockedFile = getenv("LLVM_PROGRAM_TEST_LOCKED_FILE")) { |
| 582 | + // Child process. |
| 583 | + int FD2; |
| 584 | + ASSERT_NO_ERROR(fs::openFileForReadWrite(LockedFile, FD2, |
| 585 | + fs::CD_OpenExisting, fs::OF_None)); |
| 586 | + |
| 587 | + // File should currently be non-exclusive locked by the main process, thus |
| 588 | + // trying to acquire exclusive lock will fail and trying to acquire |
| 589 | + // non-exclusive will succeed. |
| 590 | + EXPECT_TRUE( |
| 591 | + fs::tryLockFile(FD2, std::chrono::seconds(0), fs::LockKind::Exclusive)); |
| 592 | + |
| 593 | + EXPECT_FALSE( |
| 594 | + fs::tryLockFile(FD2, std::chrono::seconds(0), fs::LockKind::Shared)); |
| 595 | + |
| 596 | + close(FD2); |
| 597 | + // Write a file to indicate just finished. |
| 598 | + std::string FinishFile = std::string(LockedFile) + "-finished"; |
| 599 | + int FD3; |
| 600 | + ASSERT_NO_ERROR(fs::openFileForReadWrite(FinishFile, FD3, fs::CD_CreateNew, |
| 601 | + fs::OF_None)); |
| 602 | + close(FD3); |
| 603 | + exit(0); |
| 604 | + } |
| 605 | + |
| 606 | + // Create file that will be locked. |
| 607 | + SmallString<64> LockedFile; |
| 608 | + int FD1; |
| 609 | + ASSERT_NO_ERROR( |
| 610 | + fs::createUniqueDirectory("TestLockFileExclusive", LockedFile)); |
| 611 | + sys::path::append(LockedFile, "file"); |
| 612 | + ASSERT_NO_ERROR( |
| 613 | + fs::openFileForReadWrite(LockedFile, FD1, fs::CD_CreateNew, fs::OF_None)); |
| 614 | + |
| 615 | + std::string Executable = |
| 616 | + sys::fs::getMainExecutable(TestMainArgv0, &ProgramTestStringArg1); |
| 617 | + StringRef argv[] = {Executable, |
| 618 | + "--gtest_filter=ProgramEnvTest.TestLockFileExclusive"}; |
| 619 | + |
| 620 | + // Add LLVM_PROGRAM_TEST_LOCKED_FILE to the environment of the child. |
| 621 | + std::string EnvVar = "LLVM_PROGRAM_TEST_LOCKED_FILE="; |
| 622 | + EnvVar += LockedFile.str(); |
| 623 | + addEnvVar(EnvVar); |
| 624 | + |
| 625 | + // Lock the file. |
| 626 | + ASSERT_NO_ERROR( |
| 627 | + fs::tryLockFile(FD1, std::chrono::seconds(0), fs::LockKind::Exclusive)); |
| 628 | + |
| 629 | + std::string Error; |
| 630 | + bool ExecutionFailed; |
| 631 | + ProcessInfo PI2 = ExecuteNoWait(Executable, argv, getEnviron(), {}, 0, &Error, |
| 632 | + &ExecutionFailed); |
| 633 | + ASSERT_FALSE(ExecutionFailed) << Error; |
| 634 | + ASSERT_TRUE(Error.empty()); |
| 635 | + ASSERT_NE(PI2.Pid, ProcessInfo::InvalidPid) << "Invalid process id"; |
| 636 | + |
| 637 | + std::string FinishFile = std::string(LockedFile) + "-finished"; |
| 638 | + // Wait till child process writes the file to indicate the job finished. |
| 639 | + bool Finished = false; |
| 640 | + ExponentialBackoff Backoff(5s); // timeout 5s. |
| 641 | + do { |
| 642 | + if (fs::exists(FinishFile)) { |
| 643 | + Finished = true; |
| 644 | + break; |
| 645 | + } |
| 646 | + } while (Backoff.waitForNextAttempt()); |
| 647 | + |
| 648 | + ASSERT_TRUE(Finished); |
| 649 | + ASSERT_NO_ERROR(fs::unlockFile(FD1)); |
| 650 | + ProcessInfo WaitResult = llvm::sys::Wait(PI2, /*SecondsToWait=*/1, &Error); |
| 651 | + ASSERT_TRUE(Error.empty()); |
| 652 | + ASSERT_EQ(0, WaitResult.ReturnCode); |
| 653 | + ASSERT_EQ(WaitResult.Pid, PI2.Pid); |
| 654 | + sys::fs::remove(LockedFile); |
| 655 | + sys::fs::remove(FinishFile); |
| 656 | + sys::fs::remove_directories(sys::path::parent_path(LockedFile)); |
| 657 | +} |
| 658 | + |
576 | 659 | TEST_F(ProgramEnvTest, TestExecuteWithNoStacktraceHandler) { |
577 | 660 | using namespace llvm::sys; |
578 | 661 |
|
|
0 commit comments