Skip to content

Commit ad33f34

Browse files
[next] Add change from upstream llvm#114098
Update the downstream code to use upstreamed content.
1 parent ddcc7e9 commit ad33f34

File tree

8 files changed

+141
-33
lines changed

8 files changed

+141
-33
lines changed

llvm/include/llvm/Support/FileSystem.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1176,6 +1176,12 @@ LLVM_ABI Expected<file_t>
11761176
openNativeFileForRead(const Twine &Name, OpenFlags Flags = OF_None,
11771177
SmallVectorImpl<char> *RealPath = nullptr);
11781178

1179+
/// An enumeration for the lock kind.
1180+
enum class LockKind {
1181+
Exclusive, // Exclusive/writer lock
1182+
Shared // Shared/reader lock
1183+
};
1184+
11791185
/// Try to locks the file during the specified time.
11801186
///
11811187
/// This function implements advisory locking on entire file. If it returns
@@ -1189,6 +1195,7 @@ openNativeFileForRead(const Twine &Name, OpenFlags Flags = OF_None,
11891195
/// @param Timeout Time in milliseconds that the process should wait before
11901196
/// reporting lock failure. Zero value means try to get lock only
11911197
/// once.
1198+
/// @param Kind The kind of the lock used (exclusive/shared).
11921199
/// @returns errc::success if lock is successfully obtained,
11931200
/// errc::no_lock_available if the file cannot be locked, or platform-specific
11941201
/// error_code otherwise.
@@ -1200,7 +1207,7 @@ openNativeFileForRead(const Twine &Name, OpenFlags Flags = OF_None,
12001207
LLVM_ABI std::error_code
12011208
tryLockFile(int FD,
12021209
std::chrono::milliseconds Timeout = std::chrono::milliseconds(0),
1203-
bool Exclusive = true);
1210+
LockKind Kind = LockKind::Exclusive);
12041211

12051212
/// Get RealPath from file handle.
12061213
///
@@ -1214,9 +1221,8 @@ std::error_code getRealPathFromHandle(file_t Handle,
12141221
///
12151222
/// This function acts as @ref tryLockFile but it waits infinitely.
12161223
/// \param FD file descriptor to use for locking.
1217-
/// \param Exclusive if \p true use exclusive/writer lock, otherwise use
1218-
/// shared/reader lock.
1219-
LLVM_ABI std::error_code lockFile(int FD, bool Exclusive = true);
1224+
/// \param Kind of lock to used (exclusive/shared).
1225+
LLVM_ABI std::error_code lockFile(int FD, LockKind Kind = LockKind::Exclusive);
12201226

12211227
/// Unlock the file.
12221228
///

llvm/lib/CAS/MappedFileRegionBumpPtr.cpp

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,13 @@ namespace {
7676
struct FileLockRAII {
7777
std::string Path;
7878
int FD;
79-
enum LockKind { Shared, Exclusive };
80-
std::optional<LockKind> Locked;
79+
std::optional<sys::fs::LockKind> Locked;
8180

8281
FileLockRAII(std::string Path, int FD) : Path(std::move(Path)), FD(FD) {}
8382
~FileLockRAII() { consumeError(unlock()); }
8483

85-
Error lock(LockKind LK) {
86-
if (std::error_code EC = lockFileThreadSafe(FD, LK == Exclusive))
84+
Error lock(sys::fs::LockKind LK) {
85+
if (std::error_code EC = lockFileThreadSafe(FD, LK))
8786
return createFileError(Path, EC);
8887
Locked = LK;
8988
return Error::success();
@@ -134,12 +133,12 @@ Expected<MappedFileRegionBumpPtr> MappedFileRegionBumpPtr::create(
134133
// Take shared/reader lock that will be held until we close the file; unlocked
135134
// by destroyImpl.
136135
if (std::error_code EC =
137-
lockFileThreadSafe(SharedLockFD, /*Exclusive=*/false))
136+
lockFileThreadSafe(SharedLockFD, sys::fs::LockKind::Shared))
138137
return createFileError(Path, EC);
139138

140139
// Take shared/reader lock for initialization.
141140
FileLockRAII InitLock(Result.Path, FD);
142-
if (Error E = InitLock.lock(FileLockRAII::Shared))
141+
if (Error E = InitLock.lock(sys::fs::LockKind::Shared))
143142
return std::move(E);
144143

145144
sys::fs::file_t File = sys::fs::convertFDToNativeFile(FD);
@@ -151,7 +150,7 @@ Expected<MappedFileRegionBumpPtr> MappedFileRegionBumpPtr::create(
151150
// Lock the file exclusively so only one process will do the initialization.
152151
if (Error E = InitLock.unlock())
153152
return std::move(E);
154-
if (Error E = InitLock.lock(FileLockRAII::Exclusive))
153+
if (Error E = InitLock.lock(sys::fs::LockKind::Exclusive))
155154
return std::move(E);
156155
// Retrieve the current size now that we have exclusive access.
157156
FileSize = FileSizeInfo::get(File);
@@ -166,7 +165,7 @@ Expected<MappedFileRegionBumpPtr> MappedFileRegionBumpPtr::create(
166165
// We are initializing the file; it may be empty, or may have been shrunk
167166
// during a previous close.
168167
// FIXME: Detect a case where someone opened it with a smaller capacity.
169-
assert(InitLock.Locked == FileLockRAII::Exclusive);
168+
assert(InitLock.Locked == sys::fs::LockKind::Exclusive);
170169
if (std::error_code EC = sys::fs::resize_file_sparse(FD, Capacity))
171170
return createFileError(Result.Path, EC);
172171

@@ -189,7 +188,7 @@ Expected<MappedFileRegionBumpPtr> MappedFileRegionBumpPtr::create(
189188
}
190189

191190
if (FileSize->Size == 0) {
192-
assert(InitLock.Locked == FileLockRAII::Exclusive);
191+
assert(InitLock.Locked == sys::fs::LockKind::Exclusive);
193192
// We are creating a new file; run the constructor.
194193
if (Error E = NewFileConstructor(Result))
195194
return std::move(E);
@@ -203,7 +202,7 @@ Expected<MappedFileRegionBumpPtr> MappedFileRegionBumpPtr::create(
203202
FileSize = FileSizeInfo::get(File);
204203
if (!FileSize)
205204
return createFileError(Result.Path, FileSize.getError());
206-
assert(InitLock.Locked == FileLockRAII::Exclusive);
205+
assert(InitLock.Locked == sys::fs::LockKind::Exclusive);
207206
Result.H->AllocatedSize.exchange(FileSize->AllocatedSize);
208207
}
209208

llvm/lib/CAS/OnDiskCommon.cpp

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,14 +63,15 @@ void cas::ondisk::setMaxMappingSize(uint64_t Size) {
6363
OnDiskCASMaxMappingSize = Size;
6464
}
6565

66-
std::error_code cas::ondisk::lockFileThreadSafe(int FD, bool Exclusive) {
66+
std::error_code cas::ondisk::lockFileThreadSafe(int FD,
67+
sys::fs::LockKind Kind) {
6768
#if HAVE_FLOCK
68-
if (flock(FD, Exclusive ? LOCK_EX : LOCK_SH) == 0)
69+
if (flock(FD, Kind == sys::fs::LockKind::Exclusive ? LOCK_EX : LOCK_SH) == 0)
6970
return std::error_code();
7071
return std::error_code(errno, std::generic_category());
7172
#elif defined(_WIN32)
7273
// On Windows this implementation is thread-safe.
73-
return sys::fs::lockFile(FD, Exclusive);
74+
return sys::fs::lockFile(FD, Kind);
7475
#else
7576
return make_error_code(std::errc::no_lock_available);
7677
#endif
@@ -91,12 +92,13 @@ std::error_code cas::ondisk::unlockFileThreadSafe(int FD) {
9192

9293
std::error_code
9394
cas::ondisk::tryLockFileThreadSafe(int FD, std::chrono::milliseconds Timeout,
94-
bool Exclusive) {
95+
sys::fs::LockKind Kind) {
9596
#if HAVE_FLOCK
9697
auto Start = std::chrono::steady_clock::now();
9798
auto End = Start + Timeout;
9899
do {
99-
if (flock(FD, (Exclusive ? LOCK_EX : LOCK_SH) | LOCK_NB) == 0)
100+
if (flock(FD, (Kind == sys::fs::LockKind::Exclusive ? LOCK_EX : LOCK_SH) |
101+
LOCK_NB) == 0)
100102
return std::error_code();
101103
int Error = errno;
102104
if (Error == EWOULDBLOCK) {
@@ -109,7 +111,7 @@ cas::ondisk::tryLockFileThreadSafe(int FD, std::chrono::milliseconds Timeout,
109111
return make_error_code(std::errc::no_lock_available);
110112
#elif defined(_WIN32)
111113
// On Windows this implementation is thread-safe.
112-
return sys::fs::tryLockFile(FD, Timeout, Exclusive);
114+
return sys::fs::tryLockFile(FD, Timeout, Kind);
113115
#else
114116
return make_error_code(std::errc::no_lock_available);
115117
#endif

llvm/lib/CAS/OnDiskCommon.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#define LLVM_LIB_CAS_ONDISKCOMMON_H
1111

1212
#include "llvm/Support/Error.h"
13+
#include "llvm/Support/FileSystem.h"
1314
#include <chrono>
1415
#include <optional>
1516

@@ -29,7 +30,8 @@ void setMaxMappingSize(uint64_t Size);
2930
/// Thread-safe alternative to \c sys::fs::lockFile. This does not support all
3031
/// the platforms that \c sys::fs::lockFile does, so keep it in the CAS library
3132
/// for now.
32-
std::error_code lockFileThreadSafe(int FD, bool Exclusive = true);
33+
std::error_code lockFileThreadSafe(
34+
int FD, llvm::sys::fs::LockKind Kind = llvm::sys::fs::LockKind::Exclusive);
3335

3436
/// Thread-safe alternative to \c sys::fs::unlockFile. This does not support all
3537
/// the platforms that \c sys::fs::lockFile does, so keep it in the CAS library
@@ -41,7 +43,7 @@ std::error_code unlockFileThreadSafe(int FD);
4143
/// library for now.
4244
std::error_code tryLockFileThreadSafe(
4345
int FD, std::chrono::milliseconds Timeout = std::chrono::milliseconds(0),
44-
bool Exclusive = true);
46+
llvm::sys::fs::LockKind Kind = llvm::sys::fs::LockKind::Exclusive);
4547

4648
/// Allocate space for the file \p FD on disk, if the filesystem supports it.
4749
///

llvm/lib/CAS/UnifiedOnDiskCache.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ UnifiedOnDiskCache::validateIfNeeded(StringRef RootPath, StringRef HashName,
348348
sys::fs::file_t File = sys::fs::convertFDToNativeFile(FD);
349349
auto CloseFile = make_scope_exit([&]() { sys::fs::closeFile(File); });
350350

351-
if (std::error_code EC = lockFileThreadSafe(FD, /*Exclusive=*/true))
351+
if (std::error_code EC = lockFileThreadSafe(FD, sys::fs::LockKind::Exclusive))
352352
return createFileError(PathBuf, EC);
353353
auto UnlockFD = make_scope_exit([&]() { unlockFileThreadSafe(FD); });
354354

@@ -490,7 +490,7 @@ UnifiedOnDiskCache::open(StringRef RootPath, std::optional<uint64_t> SizeLimit,
490490
// from creating a new chain (essentially while a \p UnifiedOnDiskCache
491491
// instance holds a shared lock the storage for the primary directory will
492492
// grow unrestricted).
493-
if (std::error_code EC = lockFileThreadSafe(LockFD, /*Exclusive=*/false))
493+
if (std::error_code EC = lockFileThreadSafe(LockFD, sys::fs::LockKind::Shared))
494494
return createFileError(PathBuf, EC);
495495

496496
SmallVector<std::string, 4> DBDirs;
@@ -630,7 +630,7 @@ Error UnifiedOnDiskCache::close(bool CheckSizeLimit) {
630630
// this \p UnifiedOnDiskCache path is opened.
631631

632632
if (std::error_code EC = tryLockFileThreadSafe(
633-
LockFD, std::chrono::milliseconds(0), /*Exclusive=*/true)) {
633+
LockFD, std::chrono::milliseconds(0), sys::fs::LockKind::Exclusive)) {
634634
if (EC == errc::no_lock_available)
635635
return Error::success(); // couldn't get exclusive lock, give up.
636636
return createFileError(RootPath, EC);

llvm/lib/Support/Unix/Path.inc

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1265,13 +1265,21 @@ Expected<size_t> readNativeFileSlice(file_t FD, MutableArrayRef<char> Buf,
12651265
return NumRead;
12661266
}
12671267

1268-
std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout, bool Exclusive) {
1268+
std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout,
1269+
LockKind Kind) {
12691270
auto Start = std::chrono::steady_clock::now();
12701271
auto End = Start + Timeout;
12711272
do {
12721273
struct flock Lock;
12731274
memset(&Lock, 0, sizeof(Lock));
1274-
Lock.l_type = Exclusive ? F_WRLCK : F_RDLCK;
1275+
switch (Kind) {
1276+
case LockKind::Exclusive:
1277+
Lock.l_type = F_WRLCK;
1278+
break;
1279+
case LockKind::Shared:
1280+
Lock.l_type = F_RDLCK;
1281+
break;
1282+
}
12751283
Lock.l_whence = SEEK_SET;
12761284
Lock.l_start = 0;
12771285
Lock.l_len = 0;
@@ -1287,10 +1295,17 @@ std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout, bool Excl
12871295
return make_error_code(errc::no_lock_available);
12881296
}
12891297

1290-
std::error_code lockFile(int FD, bool Exclusive) {
1298+
std::error_code lockFile(int FD, LockKind Kind) {
12911299
struct flock Lock;
12921300
memset(&Lock, 0, sizeof(Lock));
1293-
Lock.l_type = Exclusive ? F_WRLCK : F_RDLCK;
1301+
switch (Kind) {
1302+
case LockKind::Exclusive:
1303+
Lock.l_type = F_WRLCK;
1304+
break;
1305+
case LockKind::Shared:
1306+
Lock.l_type = F_RDLCK;
1307+
break;
1308+
}
12941309
Lock.l_whence = SEEK_SET;
12951310
Lock.l_start = 0;
12961311
Lock.l_len = 0;

llvm/lib/Support/Windows/Path.inc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,8 +1371,9 @@ std::error_code getRealPathFromHandle(file_t Handle,
13711371
return realPathFromHandle(Handle, RealPath);
13721372
}
13731373

1374-
std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout, bool Exclusive) {
1375-
DWORD Flags = Exclusive ? LOCKFILE_EXCLUSIVE_LOCK : 0;
1374+
std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout,
1375+
LockKind Kind) {
1376+
DWORD Flags = Kind == LockKind::Exclusive ? LOCKFILE_EXCLUSIVE_LOCK : 0;
13761377
Flags |= LOCKFILE_FAIL_IMMEDIATELY;
13771378
OVERLAPPED OV = {};
13781379
file_t File = convertFDToNativeFile(FD);
@@ -1393,8 +1394,8 @@ std::error_code tryLockFile(int FD, std::chrono::milliseconds Timeout, bool Excl
13931394
return mapWindowsError(ERROR_LOCK_VIOLATION);
13941395
}
13951396

1396-
std::error_code lockFile(int FD, bool Exclusive) {
1397-
DWORD Flags = Exclusive ? LOCKFILE_EXCLUSIVE_LOCK : 0;
1397+
std::error_code lockFile(int FD, LockKind Kind) {
1398+
DWORD Flags = Kind == LockKind::Exclusive ? LOCKFILE_EXCLUSIVE_LOCK : 0;
13981399
OVERLAPPED OV = {};
13991400
file_t File = convertFDToNativeFile(FD);
14001401
if (::LockFileEx(File, Flags, 0, MAXDWORD, MAXDWORD, &OV))

llvm/unittests/Support/ProgramTest.cpp

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "llvm/Config/llvm-config.h"
1111
#include "llvm/Support/CommandLine.h"
1212
#include "llvm/Support/ConvertUTF.h"
13+
#include "llvm/Support/ExponentialBackoff.h"
1314
#include "llvm/Support/FileSystem.h"
1415
#include "llvm/Support/Path.h"
1516
#include "llvm/Support/Signals.h"
@@ -573,6 +574,88 @@ TEST_F(ProgramEnvTest, TestLockFile) {
573574
sys::fs::remove(LockedFile);
574575
}
575576

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+
576659
TEST_F(ProgramEnvTest, TestExecuteWithNoStacktraceHandler) {
577660
using namespace llvm::sys;
578661

0 commit comments

Comments
 (0)