mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-04-11 12:11:20 +00:00

On Windows we've observed that if you open a file, write to it, map it into memory and close the file handle, the contents of the memory mapping can sometimes be incorrect. That was what we did when adding an entry to the ThinLTO cache using the TempFile and MemoryBuffer classes, and it was causing intermittent build failures on Chromium's ThinLTO bots on Windows. More details are in the associated Chromium bug (crbug.com/786127). We can prevent this from happening by keeping a handle to the file open while the mapping is active. So this patch changes the mapped_file_region class to duplicate the file handle when mapping the file and close it upon unmapping it. One gotcha is that the file handle that we keep open must not have been created with FILE_FLAG_DELETE_ON_CLOSE, as otherwise the operating system will prevent other processes from opening the file. We can achieve this by avoiding the use of FILE_FLAG_DELETE_ON_CLOSE altogether. Instead, we use SetFileInformationByHandle with FileDispositionInfo to manage the delete-on-close bit. This lets us remove the hack that we used to use to clear the delete-on-close bit on a file opened with FILE_FLAG_DELETE_ON_CLOSE. A downside of using SetFileInformationByHandle/FileDispositionInfo as opposed to FILE_FLAG_DELETE_ON_CLOSE is that it prevents us from using CreateFile to open the file while the flag is set, even within the same process. This doesn't seem to matter for almost every client of TempFile, except for LockFileManager, which calls sys::fs::create_link to create a hard link from the lock file, and in the process of doing so tries to open the file. To prevent this change from breaking LockFileManager I changed it to stop using TempFile by effectively reverting r318550. Differential Revision: https://reviews.llvm.org/D48051 llvm-svn: 334630
100 lines
3.0 KiB
C++
100 lines
3.0 KiB
C++
//===--- LockFileManager.h - File-level locking utility ---------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#ifndef LLVM_SUPPORT_LOCKFILEMANAGER_H
|
|
#define LLVM_SUPPORT_LOCKFILEMANAGER_H
|
|
|
|
#include "llvm/ADT/Optional.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include <system_error>
|
|
#include <utility> // for std::pair
|
|
|
|
namespace llvm {
|
|
class StringRef;
|
|
|
|
/// Class that manages the creation of a lock file to aid
|
|
/// implicit coordination between different processes.
|
|
///
|
|
/// The implicit coordination works by creating a ".lock" file alongside
|
|
/// the file that we're coordinating for, using the atomicity of the file
|
|
/// system to ensure that only a single process can create that ".lock" file.
|
|
/// When the lock file is removed, the owning process has finished the
|
|
/// operation.
|
|
class LockFileManager {
|
|
public:
|
|
/// Describes the state of a lock file.
|
|
enum LockFileState {
|
|
/// The lock file has been created and is owned by this instance
|
|
/// of the object.
|
|
LFS_Owned,
|
|
/// The lock file already exists and is owned by some other
|
|
/// instance.
|
|
LFS_Shared,
|
|
/// An error occurred while trying to create or find the lock
|
|
/// file.
|
|
LFS_Error
|
|
};
|
|
|
|
/// Describes the result of waiting for the owner to release the lock.
|
|
enum WaitForUnlockResult {
|
|
/// The lock was released successfully.
|
|
Res_Success,
|
|
/// Owner died while holding the lock.
|
|
Res_OwnerDied,
|
|
/// Reached timeout while waiting for the owner to release the lock.
|
|
Res_Timeout
|
|
};
|
|
|
|
private:
|
|
SmallString<128> FileName;
|
|
SmallString<128> LockFileName;
|
|
SmallString<128> UniqueLockFileName;
|
|
|
|
Optional<std::pair<std::string, int> > Owner;
|
|
std::error_code ErrorCode;
|
|
std::string ErrorDiagMsg;
|
|
|
|
LockFileManager(const LockFileManager &) = delete;
|
|
LockFileManager &operator=(const LockFileManager &) = delete;
|
|
|
|
static Optional<std::pair<std::string, int> >
|
|
readLockFile(StringRef LockFileName);
|
|
|
|
static bool processStillExecuting(StringRef Hostname, int PID);
|
|
|
|
public:
|
|
|
|
LockFileManager(StringRef FileName);
|
|
~LockFileManager();
|
|
|
|
/// Determine the state of the lock file.
|
|
LockFileState getState() const;
|
|
|
|
operator LockFileState() const { return getState(); }
|
|
|
|
/// For a shared lock, wait until the owner releases the lock.
|
|
WaitForUnlockResult waitForUnlock();
|
|
|
|
/// Remove the lock file. This may delete a different lock file than
|
|
/// the one previously read if there is a race.
|
|
std::error_code unsafeRemoveLockFile();
|
|
|
|
/// Get error message, or "" if there is no error.
|
|
std::string getErrorMessage() const;
|
|
|
|
/// Set error and error message
|
|
void setError(const std::error_code &EC, StringRef ErrorMsg = "") {
|
|
ErrorCode = EC;
|
|
ErrorDiagMsg = ErrorMsg.str();
|
|
}
|
|
};
|
|
|
|
} // end namespace llvm
|
|
|
|
#endif // LLVM_SUPPORT_LOCKFILEMANAGER_H
|