Index: include/lldb/Host/LockFile.h =================================================================== --- /dev/null +++ include/lldb/Host/LockFile.h @@ -0,0 +1,27 @@ +//===-- LockFile.h ----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_LockFile_h_ +#define liblldb_Host_LockFile_h_ + +#if defined(_WIN32) +#include "lldb/Host/windows/LockFileWindows.h" +namespace lldb_private +{ +typedef LockFileWindows LockFile; +} +#else +#include "lldb/Host/posix/LockFilePosix.h" +namespace lldb_private +{ +typedef LockFilePosix LockFile; +} +#endif + +#endif // liblldb_Host_LockFile_h_ Index: include/lldb/Host/LockFileBase.h =================================================================== --- /dev/null +++ include/lldb/Host/LockFileBase.h @@ -0,0 +1,73 @@ +//===-- LockFileBase.h ------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_LockFileBase_h_ +#define liblldb_Host_LockFileBase_h_ + +#include "lldb/Core/Error.h" + +#include + +namespace lldb_private +{ + +class LockFileBase +{ +public: + virtual ~LockFileBase () = default; + + bool + IsLocked () const; + + Error + WriteLock (const uint64_t start, const uint64_t len); + Error + TryWriteLock (const uint64_t start, const uint64_t len); + + Error + ReadLock (const uint64_t start, const uint64_t len); + Error + TryReadLock (const uint64_t start, const uint64_t len); + + Error + Unlock (); + +protected: + using Locker = std::function; + + LockFileBase (int fd); + + virtual bool + IsValidFile () const; + + virtual Error + DoWriteLock (const uint64_t start, const uint64_t len) = 0; + virtual Error + DoTryWriteLock (const uint64_t start, const uint64_t len) = 0; + + virtual Error + DoReadLock (const uint64_t start, const uint64_t len) = 0; + virtual Error + DoTryReadLock (const uint64_t start, const uint64_t len) = 0; + + virtual Error + DoUnlock () = 0; + + Error + DoLock (const Locker &locker, const uint64_t start, const uint64_t len); + + int m_fd; // not owned. + bool m_locked; + uint64_t m_start; + uint64_t m_len; +}; + +} + +#endif Index: include/lldb/Host/posix/LockFilePosix.h =================================================================== --- /dev/null +++ include/lldb/Host/posix/LockFilePosix.h @@ -0,0 +1,42 @@ +//===-- LockFilePosix.h -----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_posix_LockFilePosix_h_ +#define liblldb_Host_posix_LockFilePosix_h_ + +#include "lldb/Host/LockFileBase.h" + +namespace lldb_private { + +class LockFilePosix : public LockFileBase +{ +public: + explicit LockFilePosix (int fd); + ~LockFilePosix (); + +protected: + Error + DoWriteLock (const uint64_t start, const uint64_t len) override; + + Error + DoTryWriteLock (const uint64_t start, const uint64_t len) override; + + Error + DoReadLock (const uint64_t start, const uint64_t len) override; + + Error + DoTryReadLock (const uint64_t start, const uint64_t len) override; + + Error + DoUnlock () override; +}; + +} // namespace lldb_private + +#endif // liblldb_Host_posix_LockFilePosix_h_ Index: include/lldb/Host/windows/LockFileWindows.h =================================================================== --- /dev/null +++ include/lldb/Host/windows/LockFileWindows.h @@ -0,0 +1,49 @@ +//===-- LockFileWindows.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_Host_posix_LockFileWindows_h_ +#define liblldb_Host_posix_LockFileWindows_h_ + +#include "lldb/Host/LockFileBase.h" +#include "lldb/Host/windows/windows.h" + +namespace lldb_private { + +class LockFileWindows : public LockFileBase +{ +public: + explicit LockFileWindows (int fd); + ~LockFileWindows (); + +protected: + Error + DoWriteLock (const uint64_t start, const uint64_t len) override; + + Error + DoTryWriteLock (const uint64_t start, const uint64_t len) override; + + Error + DoReadLock (const uint64_t start, const uint64_t len) override; + + Error + DoTryReadLock (const uint64_t start, const uint64_t len) override; + + Error + DoUnlock () override; + + bool + IsValidFile () const override; + +private: + HANDLE m_file; +}; + +} // namespace lldb_private + +#endif // liblldb_Host_posix_LockFileWindows_h_ Index: lldb.xcodeproj/project.pbxproj =================================================================== --- lldb.xcodeproj/project.pbxproj +++ lldb.xcodeproj/project.pbxproj @@ -109,6 +109,8 @@ 256CBDC11ADD11C000BC6CDC /* RegisterContextPOSIX_arm.h in Headers */ = {isa = PBXBuildFile; fileRef = 256CBDBF1ADD11C000BC6CDC /* RegisterContextPOSIX_arm.h */; }; 257E47171AA56C2000A62F81 /* ModuleCache.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 257E47151AA56C2000A62F81 /* ModuleCache.cpp */; }; 257E47181AA56C2000A62F81 /* ModuleCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 257E47161AA56C2000A62F81 /* ModuleCache.h */; }; + 25B67C041AE01C910000D19B /* LockFileBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25B67C031AE01C910000D19B /* LockFileBase.cpp */; }; + 25B67C081AE01CDA0000D19B /* LockFilePosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25B67C071AE01CDA0000D19B /* LockFilePosix.cpp */; }; 25EF23781AC09B3700908DF0 /* AdbClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 25EF23751AC09AD800908DF0 /* AdbClient.cpp */; }; 25EF23791AC09B4200908DF0 /* AdbClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 25EF23761AC09AD800908DF0 /* AdbClient.h */; }; 260157C61885F51C00F875CF /* libpanel.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 260157C41885F4FF00F875CF /* libpanel.dylib */; }; @@ -1254,6 +1256,10 @@ 256CBDBF1ADD11C000BC6CDC /* RegisterContextPOSIX_arm.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RegisterContextPOSIX_arm.h; path = Utility/RegisterContextPOSIX_arm.h; sourceTree = ""; }; 257E47151AA56C2000A62F81 /* ModuleCache.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ModuleCache.cpp; path = source/Utility/ModuleCache.cpp; sourceTree = ""; }; 257E47161AA56C2000A62F81 /* ModuleCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ModuleCache.h; path = source/Utility/ModuleCache.h; sourceTree = ""; }; + 25B67C031AE01C910000D19B /* LockFileBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LockFileBase.cpp; sourceTree = ""; }; + 25B67C051AE01CC10000D19B /* LockFile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LockFile.h; path = include/lldb/Host/LockFile.h; sourceTree = ""; }; + 25B67C061AE01CC10000D19B /* LockFileBase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = LockFileBase.h; path = include/lldb/Host/LockFileBase.h; sourceTree = ""; }; + 25B67C071AE01CDA0000D19B /* LockFilePosix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LockFilePosix.cpp; sourceTree = ""; }; 25EF23751AC09AD800908DF0 /* AdbClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AdbClient.cpp; sourceTree = ""; }; 25EF23761AC09AD800908DF0 /* AdbClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AdbClient.h; sourceTree = ""; }; 260157C41885F4FF00F875CF /* libpanel.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpanel.dylib; path = /usr/lib/libpanel.dylib; sourceTree = ""; }; @@ -4352,6 +4358,8 @@ 26BC7DD010F1B7C100F91463 /* Host */ = { isa = PBXGroup; children = ( + 25B67C051AE01CC10000D19B /* LockFile.h */, + 25B67C061AE01CC10000D19B /* LockFileBase.h */, 6D55B29B1A8CCFF000A70529 /* android */, 33E5E8451A6736D30024ED68 /* StringConvert.h */, 69A01E1A1236C5D400C660B5 /* common */, @@ -4854,6 +4862,7 @@ 3FDFDDC4199D37BE009756A7 /* posix */ = { isa = PBXGroup; children = ( + 25B67C071AE01CDA0000D19B /* LockFilePosix.cpp */, AFDFDFD019E34D3400EAE509 /* ConnectionFileDescriptorPosix.cpp */, 3FDFDDC5199D37ED009756A7 /* FileSystem.cpp */, 3FDFE53019A292F0009756A7 /* HostInfoPosix.cpp */, @@ -5012,6 +5021,7 @@ 69A01E1A1236C5D400C660B5 /* common */ = { isa = PBXGroup; children = ( + 25B67C031AE01C910000D19B /* LockFileBase.cpp */, 250D6AE11A9679270049CC70 /* FileSystem.cpp */, 33E5E8411A672A240024ED68 /* StringConvert.cpp */, 25420ED11A649D88009ADBCB /* PipeBase.cpp */, @@ -6096,6 +6106,7 @@ 2689006113353E0E00698AC0 /* ClangExpressionParser.cpp in Sources */, 2689006213353E0E00698AC0 /* ClangExpressionVariable.cpp in Sources */, 2689006313353E0E00698AC0 /* ClangPersistentVariables.cpp in Sources */, + 25B67C041AE01C910000D19B /* LockFileBase.cpp in Sources */, 2689006413353E0E00698AC0 /* ClangUserExpression.cpp in Sources */, 4C3ADCD61810D88B00357218 /* BreakpointResolverFileRegex.cpp in Sources */, 2689006513353E0E00698AC0 /* ClangUtilityFunction.cpp in Sources */, @@ -6329,6 +6340,7 @@ 263E949F13661AEA00E7D1CE /* UnwindAssembly-x86.cpp in Sources */, E7723D481AC4A8C8002BA082 /* RegisterContextFreeBSD_arm64.cpp in Sources */, 3FDFDDBD199C3A06009756A7 /* FileAction.cpp in Sources */, + 25B67C081AE01CDA0000D19B /* LockFilePosix.cpp in Sources */, 264D8D5013661BD7003A368F /* UnwindAssembly.cpp in Sources */, AF23B4DB19009C66003E2A58 /* FreeBSDSignals.cpp in Sources */, 26ECA04313665FED008D1F18 /* ARM_DWARF_Registers.cpp in Sources */, Index: source/Host/CMakeLists.txt =================================================================== --- source/Host/CMakeLists.txt +++ source/Host/CMakeLists.txt @@ -15,6 +15,7 @@ common/HostProcess.cpp common/HostThread.cpp common/IOObject.cpp + common/LockFileBase.cpp common/Mutex.cpp common/MonitoringProcessLauncher.cpp common/NativeBreakpoint.cpp @@ -58,6 +59,7 @@ windows/HostInfoWindows.cpp windows/HostProcessWindows.cpp windows/HostThreadWindows.cpp + windows/LockFileWindows.cpp windows/Mutex.cpp windows/PipeWindows.cpp windows/ProcessLauncherWindows.cpp @@ -72,6 +74,7 @@ posix/HostInfoPosix.cpp posix/HostProcessPosix.cpp posix/HostThreadPosix.cpp + posix/LockFilePosix.cpp posix/PipePosix.cpp ) Index: source/Host/common/LockFileBase.cpp =================================================================== --- /dev/null +++ source/Host/common/LockFileBase.cpp @@ -0,0 +1,124 @@ +//===-- LockFileBase.cpp ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/LockFileBase.h" + +using namespace lldb; +using namespace lldb_private; + +namespace +{ + +Error +AlreadyLocked () +{ + return Error ("Already locked"); +} + +Error +NotLocked () +{ + return Error ("Not locked"); +} + +} + +LockFileBase::LockFileBase (int fd) : + m_fd (fd), + m_locked (false), + m_start (0), + m_len (0) +{ + +} + +bool +LockFileBase::IsLocked () const +{ + return m_locked; +} + +Error +LockFileBase::WriteLock (const uint64_t start, const uint64_t len) +{ + return DoLock ([&] (const uint64_t start, const uint64_t len) + { + return DoWriteLock (start, len); + }, start, len); +} + +Error +LockFileBase::TryWriteLock (const uint64_t start, const uint64_t len) +{ + return DoLock ([&] (const uint64_t start, const uint64_t len) + { + return DoTryWriteLock (start, len); + }, start, len); +} + +Error +LockFileBase::ReadLock (const uint64_t start, const uint64_t len) +{ + return DoLock ([&] (const uint64_t start, const uint64_t len) + { + return DoReadLock (start, len); + }, start, len); +} + +Error +LockFileBase::TryReadLock (const uint64_t start, const uint64_t len) +{ + return DoLock ([&] (const uint64_t start, const uint64_t len) + { + return DoTryReadLock (start, len); + }, start, len); + +} + +Error +LockFileBase::Unlock () +{ + if (!IsLocked ()) + return NotLocked (); + + const auto error = DoUnlock (); + if (error.Success ()) + { + m_locked = false; + m_start = 0; + m_len = 0; + } + return error; +} + +bool +LockFileBase::IsValidFile () const +{ + return m_fd != -1; +} + +Error +LockFileBase::DoLock (const Locker &locker, const uint64_t start, const uint64_t len) +{ + if (!IsValidFile ()) + return Error("File is invalid"); + + if (IsLocked ()) + return AlreadyLocked (); + + const auto error = locker (start, len); + if (error.Success ()) + { + m_locked = true; + m_start = start; + m_len = len; + } + + return error; +} Index: source/Host/posix/LockFilePosix.cpp =================================================================== --- /dev/null +++ source/Host/posix/LockFilePosix.cpp @@ -0,0 +1,77 @@ +//===-- LockFilePosix.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/posix/LockFilePosix.h" + +#include + +using namespace lldb; +using namespace lldb_private; + +namespace +{ + +Error fileLock (int fd, int cmd, int lock_type, const uint64_t start, const uint64_t len) +{ + struct flock fl; + + fl.l_type = lock_type; + fl.l_whence = SEEK_SET; + fl.l_start = start; + fl.l_len = len; + fl.l_pid = ::getpid (); + + Error error; + if (::fcntl (fd, cmd, &fl) == -1) + error.SetErrorToErrno (); + + return error; +} + +} // namespace + +LockFilePosix::LockFilePosix (int fd) + : LockFileBase (fd) +{ +} + +LockFilePosix::~LockFilePosix () +{ + Unlock (); +} + +Error +LockFilePosix::DoWriteLock (const uint64_t start, const uint64_t len) +{ + return fileLock (m_fd, F_SETLKW, F_WRLCK, start, len); +} + +Error +LockFilePosix::DoTryWriteLock (const uint64_t start, const uint64_t len) +{ + return fileLock (m_fd, F_SETLK, F_WRLCK, start, len); +} + +Error +LockFilePosix::DoReadLock (const uint64_t start, const uint64_t len) +{ + return fileLock (m_fd, F_SETLKW, F_RDLCK, start, len); +} + +Error +LockFilePosix::DoTryReadLock (const uint64_t start, const uint64_t len) +{ + return fileLock (m_fd, F_SETLK, F_RDLCK, start, len); +} + +Error +LockFilePosix::DoUnlock () +{ + return fileLock (m_fd, F_SETLK, F_UNLCK, m_start, m_len); +} Index: source/Host/windows/LockFileWindows.cpp =================================================================== --- /dev/null +++ source/Host/windows/LockFileWindows.cpp @@ -0,0 +1,102 @@ +//===-- LockFileWindows.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/windows/LockFileWindows.h" + +#include "lldb/Host/windows/AutoHandle.h" + +#include + +using namespace lldb; +using namespace lldb_private; + +namespace +{ + +Error fileLock (HANDLE file_handle, DWORD flags, const uint64_t start, const uint64_t len) +{ + if (start != 0) + return Error ("Non-zero start lock regions are not supported"); + + OVERLAPPED overlapped = {0}; + const AutoHandle event_handle (::CreateEvent (nullptr, TRUE, FALSE, nullptr)); + overlapped.hEvent = event_handle.get (); + + if (!::LockFileEx (file_handle, flags, 0, len, 0, &overlapped) && ::GetLastError () != ERROR_IO_PENDING) + return Error (::GetLastError (), eErrorTypeWin32); + + if (::WaitForSingleObject (overlapped.hEvent, INFINITE) != WAIT_OBJECT_0) + return Error (::GetLastError (), eErrorTypeWin32); + + return Error (); +} + +} // namespace + +LockFileWindows::LockFileWindows (int fd) + : LockFileBase (fd), + m_file (reinterpret_cast (_get_osfhandle (fd))) +{ +} + +LockFileWindows::~LockFileWindows () +{ + Unlock (); + if (m_file != INVALID_HANDLE_VALUE) + { + _close (reinterpret_cast (m_file)); + m_file = INVALID_HANDLE_VALUE; + } +} + +bool +LockFileWindows::IsValidFile () const +{ + return LockFileBase::IsValidFile() && m_file != INVALID_HANDLE_VALUE; +} + +Error +LockFileWindows::DoWriteLock (const uint64_t start, const uint64_t len) +{ + return fileLock (m_file, LOCKFILE_EXCLUSIVE_LOCK, start, len); +} + +Error +LockFileWindows::DoTryWriteLock (const uint64_t start, const uint64_t len) +{ + return fileLock (m_file, LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY, start, len); +} + +Error +LockFileWindows::DoReadLock (const uint64_t start, const uint64_t len) +{ + return fileLock (m_file, 0, start, len); +} + +Error +LockFileWindows::DoTryReadLock (const uint64_t start, const uint64_t len) +{ + return fileLock (m_file, LOCKFILE_FAIL_IMMEDIATELY, start, len); +} + +Error +LockFileWindows::DoUnlock () +{ + OVERLAPPED overlapped = {0}; + const AutoHandle event_handle (::CreateEvent (nullptr, TRUE, FALSE, nullptr)); + overlapped.hEvent = event_handle.get (); + + if (!::UnlockFileEx (file_handle, 0, m_len, 0, &overlapped) && ::GetLastError () != ERROR_IO_PENDING) + return Error (::GetLastError (), eErrorTypeWin32); + + if (::WaitForSingleObject (overlapped.hEvent, INFINITE) != WAIT_OBJECT_0) + return Error (::GetLastError (), eErrorTypeWin32); + + return Error (); +} Index: source/Utility/ModuleCache.h =================================================================== --- source/Utility/ModuleCache.h +++ source/Utility/ModuleCache.h @@ -72,6 +72,9 @@ static FileSpec GetModuleDirectory (const FileSpec &root_dir_spec, const UUID &uuid); + static Error + GetModuleLockFilePath (const FileSpec &root_dir_spec, const UUID &uuid, FileSpec &lock_file_path); + static FileSpec GetHostSysRootModulePath (const FileSpec &root_dir_spec, const char *hostname, const FileSpec &platform_module_spec); Index: source/Utility/ModuleCache.cpp =================================================================== --- source/Utility/ModuleCache.cpp +++ source/Utility/ModuleCache.cpp @@ -11,7 +11,9 @@ #include "lldb/Core/Module.h" #include "lldb/Core/ModuleSpec.h" +#include "lldb/Host/File.h" #include "lldb/Host/FileSystem.h" +#include "lldb/Host/LockFile.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/FileUtilities.h" @@ -25,6 +27,7 @@ namespace { const char* kModulesSubdir = ".cache"; +const char* kLockSubDir = ".lock"; FileSpec JoinPath (const FileSpec &path1, const char* path2) @@ -136,6 +139,28 @@ if (error.Success ()) return error; + FileSpec lock_file_path; + error = GetModuleLockFilePath (root_dir_spec, module_spec.GetUUID (), lock_file_path); + if (error.Fail ()) + return Error("Failed to get module lock path: %s", error.AsCString ()); + + File lock_file (lock_file_path, File::eOpenOptionWrite | File::eOpenOptionCanCreate); + if (!lock_file.IsValid ()) + { + error.SetErrorToErrno (); + return Error("Failed to open lock file %s: %s", lock_file_path.GetPath ().c_str (), error.AsCString ()); + } + llvm::FileRemover lock_file_remover (lock_file_path.GetPath ().c_str ()); + LockFile lock (lock_file.GetDescriptor ()); + error = lock.WriteLock (0, 1); + if (error.Fail ()) + return Error("Failed to lock file %s:%s", lock_file_path.GetPath ().c_str (), error.AsCString ()); + + // Check local cache for a module again. + error = Get (root_dir_spec, hostname, module_spec, cached_module_sp, did_create_ptr); + if (error.Success ()) + return error; + FileSpec tmp_download_file_spec; error = downloader (module_spec, tmp_download_file_spec); llvm::FileRemover tmp_file_remover (tmp_download_file_spec.GetPath ().c_str ()); @@ -164,6 +189,18 @@ return JoinPath (modules_dir_spec, uuid.GetAsString ().c_str ()); } +Error +ModuleCache::GetModuleLockFilePath (const FileSpec &root_dir_spec, const UUID &uuid, FileSpec &lock_file_path) +{ + const auto lock_dir_spec = JoinPath (root_dir_spec, kLockSubDir); + auto error = MakeDirectory (lock_dir_spec); + if (error.Fail ()) + return error; + + lock_file_path = JoinPath (lock_dir_spec, uuid.GetAsString ().c_str ()); + return error; +} + FileSpec ModuleCache::GetHostSysRootModulePath (const FileSpec &root_dir_spec, const char *hostname, const FileSpec &platform_module_spec) {