From: Joel Rosdahl Date: Sun, 10 Nov 2024 10:36:37 +0000 (+0100) Subject: enhance: Add util::FileLock X-Git-Tag: v4.11~40 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=d7d4d21dfbf0994fb4a6a9acf2dbe3059efabdc2;p=thirdparty%2Fccache.git enhance: Add util::FileLock --- diff --git a/src/ccache/util/CMakeLists.txt b/src/ccache/util/CMakeLists.txt index 4983bedc..5d5a68ce 100644 --- a/src/ccache/util/CMakeLists.txt +++ b/src/ccache/util/CMakeLists.txt @@ -7,6 +7,7 @@ set( environment.cpp error.cpp file.cpp + filelock.cpp filesystem.cpp lockfile.cpp logging.cpp diff --git a/src/ccache/util/filelock.cpp b/src/ccache/util/filelock.cpp new file mode 100644 index 00000000..e6874966 --- /dev/null +++ b/src/ccache/util/filelock.cpp @@ -0,0 +1,107 @@ +// Copyright (C) 2024 Joel Rosdahl and other contributors +// +// See doc/AUTHORS.adoc for a complete list of contributors. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the Free Software Foundation, Inc., 51 +// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#include "filelock.hpp" + +#include +#include + +#ifdef _WIN32 +# include +# include +#else +# include +# include +# include +#endif + +namespace util { + +FileLock::FileLock(int fd) : m_fd(fd) +{ +} + +FileLock::FileLock(FileLock&& other) noexcept + : m_fd(other.m_fd), + m_acquired(other.m_acquired) +{ + other.m_fd = -1; + other.m_acquired = false; +} + +FileLock& +FileLock::operator=(FileLock&& other) noexcept +{ + if (&other != this) { + m_fd = other.m_fd; + m_acquired = other.m_acquired; + other.m_fd = -1; + other.m_acquired = false; + } + return *this; +} + +bool +FileLock::acquire() +{ +#ifdef _WIN32 + HANDLE handle = reinterpret_cast(_get_osfhandle(m_fd)); + if (handle == INVALID_HANDLE_VALUE) { + return false; + } + m_acquired = LockFile(handle, 0, 0, MAXDWORD, MAXDWORD) != 0; +#else + struct flock lock; + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_WRLCK; + lock.l_whence = SEEK_SET; + int result; + do { + result = fcntl(m_fd, F_SETLKW, &lock); + } while (result != 0 && errno == EINTR); + m_acquired = result == 0; +#endif + return m_acquired; +} + +void +FileLock::release() +{ + if (!acquired()) { + return; + } + +#ifdef _WIN32 + HANDLE handle = reinterpret_cast(_get_osfhandle(m_fd)); + if (handle != INVALID_HANDLE_VALUE) { + UnlockFile(handle, 0, 0, MAXDWORD, MAXDWORD); + } +#else + struct flock lock; + memset(&lock, 0, sizeof(lock)); + lock.l_type = F_UNLCK; + lock.l_whence = SEEK_SET; + int result; + do { + result = fcntl(m_fd, F_SETLK, &lock); + } while (result != 0 && errno == EINTR); +#endif + m_acquired = false; +} + +} // namespace util diff --git a/src/ccache/util/filelock.hpp b/src/ccache/util/filelock.hpp new file mode 100644 index 00000000..806784fd --- /dev/null +++ b/src/ccache/util/filelock.hpp @@ -0,0 +1,61 @@ +// Copyright (C) 2024 Joel Rosdahl and other contributors +// +// See doc/AUTHORS.adoc for a complete list of contributors. +// +// This program is free software; you can redistribute it and/or modify it +// under the terms of the GNU General Public License as published by the Free +// Software Foundation; either version 3 of the License, or (at your option) +// any later version. +// +// This program is distributed in the hope that it will be useful, but WITHOUT +// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for +// more details. +// +// You should have received a copy of the GNU General Public License along with +// this program; if not, write to the Free Software Foundation, Inc., 51 +// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +#pragma once + +#include + +namespace util { + +class FileLock : util::NonCopyable +{ +public: + explicit FileLock(int fd); + FileLock(FileLock&& other) noexcept; + + FileLock& operator=(FileLock&& other) noexcept; + + // Release the lock if previously acquired. + ~FileLock(); + + // Acquire lock, blocking. Returns true if acquired, otherwise false. + [[nodiscard]] bool acquire(); + + // Release lock early. If not previously acquired, nothing happens. + void release(); + + // Return whether the lock is acquired successfully. + bool acquired() const; + +private: + int m_fd = -1; + bool m_acquired = false; +}; + +inline FileLock::~FileLock() +{ + release(); +} + +inline bool +FileLock::acquired() const +{ + return m_acquired; +} + +} // namespace util