diff --git a/Source/cmFileLock.cxx b/Source/cmFileLock.cxx index 548e3279b0..64fbc1f4f6 100644 --- a/Source/cmFileLock.cxx +++ b/Source/cmFileLock.cxx @@ -14,6 +14,9 @@ cmFileLock::cmFileLock(cmFileLock&& other) noexcept this->File = other.File; other.File = (decltype(other.File))-1; this->Filename = std::move(other.Filename); +#if defined(_WIN32) + this->Overlapped = std::move(other.Overlapped); +#endif } cmFileLock::~cmFileLock() @@ -30,6 +33,9 @@ cmFileLock& cmFileLock::operator=(cmFileLock&& other) noexcept this->File = other.File; other.File = (decltype(other.File))-1; this->Filename = std::move(other.Filename); +#if defined(_WIN32) + this->Overlapped = std::move(other.Overlapped); +#endif return *this; } diff --git a/Source/cmFileLock.h b/Source/cmFileLock.h index 0f2e7d9986..e17f8bc87e 100644 --- a/Source/cmFileLock.h +++ b/Source/cmFileLock.h @@ -7,6 +7,7 @@ #include #if defined(_WIN32) +# include using HANDLE = void*; #endif @@ -54,6 +55,7 @@ private: #if defined(_WIN32) HANDLE File = (HANDLE)-1; + std::unique_ptr Overlapped; int LockFile(int flags); #else int File = -1; diff --git a/Source/cmFileLockWin32.cxx b/Source/cmFileLockWin32.cxx index 244ade2a02..8a4dadc57f 100644 --- a/Source/cmFileLockWin32.cxx +++ b/Source/cmFileLockWin32.cxx @@ -1,12 +1,18 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ -#include // CreateFileW +#include + +#include #include "cmFileLock.h" #include "cmSystemTools.h" +static const unsigned long LOCK_LEN = static_cast(-1); + cmFileLock::cmFileLock() + : Overlapped(cm::make_unique()) { + ZeroMemory(this->Overlapped.get(), sizeof(*this->Overlapped)); } cmFileLockResult cmFileLock::Release() @@ -14,15 +20,16 @@ cmFileLockResult cmFileLock::Release() if (this->Filename.empty()) { return cmFileLockResult::MakeOk(); } - const unsigned long len = static_cast(-1); - static OVERLAPPED overlapped; const DWORD reserved = 0; + ZeroMemory(this->Overlapped.get(), sizeof(*this->Overlapped)); + const BOOL unlockResult = - UnlockFileEx(File, reserved, len, len, &overlapped); + UnlockFileEx(File, reserved, LOCK_LEN, LOCK_LEN, this->Overlapped.get()); this->Filename = ""; CloseHandle(this->File); + this->File = INVALID_HANDLE_VALUE; if (unlockResult) { @@ -51,37 +58,63 @@ cmFileLockResult cmFileLock::OpenFile() cmFileLockResult cmFileLock::LockWithoutTimeout() { + cmFileLockResult lock_result = cmFileLockResult::MakeOk(); if (!this->LockFile(LOCKFILE_EXCLUSIVE_LOCK)) { - return cmFileLockResult::MakeSystem(); - } else { - return cmFileLockResult::MakeOk(); + lock_result = cmFileLockResult::MakeSystem(); } + CloseHandle(this->Overlapped->hEvent); + return lock_result; } cmFileLockResult cmFileLock::LockWithTimeout(unsigned long seconds) { + cmFileLockResult lock_result = cmFileLockResult::MakeOk(); const DWORD flags = LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY; - while (true) { - const BOOL result = this->LockFile(flags); - if (result) { - return cmFileLockResult::MakeOk(); + bool in_time = true; + while (in_time && !this->LockFile(flags)) { + switch (GetLastError()) { + case ERROR_INVALID_HANDLE: + lock_result = cmFileLockResult::MakeSystem(); + break; + case ERROR_LOCK_VIOLATION: + if (seconds == 0) { + in_time = false; + lock_result = cmFileLockResult::MakeTimeout(); + continue; + } + --seconds; + cmSystemTools::Delay(1000); + continue; + case ERROR_IO_PENDING: + switch ( + WaitForSingleObject(this->Overlapped->hEvent, seconds * 1000)) { + case WAIT_OBJECT_0: + break; + case WAIT_TIMEOUT: + lock_result = cmFileLockResult::MakeTimeout(); + break; + default: + lock_result = cmFileLockResult::MakeSystem(); + break; + } + break; + default: + lock_result = cmFileLockResult::MakeSystem(); + break; } - const DWORD error = GetLastError(); - if (error != ERROR_LOCK_VIOLATION) { - return cmFileLockResult::MakeSystem(); - } - if (seconds == 0) { - return cmFileLockResult::MakeTimeout(); - } - --seconds; - cmSystemTools::Delay(1000); } + CloseHandle(this->Overlapped->hEvent); + return lock_result; } int cmFileLock::LockFile(int flags) { const DWORD reserved = 0; - const unsigned long len = static_cast(-1); - static OVERLAPPED overlapped; - return LockFileEx(this->File, flags, reserved, len, len, &overlapped); + + this->Overlapped->hEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr); + if (this->Overlapped->hEvent == nullptr) { + return false; + } + return LockFileEx(this->File, flags, reserved, LOCK_LEN, LOCK_LEN, + this->Overlapped.get()); }