| #pragma once |
| |
| #include <fcntl.h> |
| #include <sys/file.h> |
| #include <unistd.h> |
| |
| #include <chrono> |
| #include <iostream> |
| #include <stdexcept> |
| #include <string> |
| #include <thread> |
| |
| namespace pldm |
| { |
| namespace responder |
| { |
| |
| class FileLock |
| { |
| public: |
| explicit FileLock(const std::string& lockFilePath, |
| int timeoutSeconds = 10) : lockFilePath(lockFilePath) |
| { |
| lockFd = open(lockFilePath.c_str(), O_RDWR | O_CREAT, 0666); |
| if (lockFd == -1) |
| { |
| throw std::runtime_error( |
| "Failed to open lock file: " + lockFilePath + |
| " errno: " + std::to_string(errno)); |
| } |
| |
| auto startTime = std::chrono::steady_clock::now(); |
| while (true) |
| { |
| if (flock(lockFd, LOCK_EX | LOCK_NB) == 0) |
| { |
| // Lock acquired |
| return; |
| } |
| |
| if (errno != EWOULDBLOCK) |
| { |
| // An error other than the lock being held |
| close(lockFd); |
| throw std::runtime_error( |
| "Failed to acquire lock on file: " + lockFilePath + |
| " errno: " + std::to_string(errno)); |
| } |
| |
| // Check for timeout |
| auto currentTime = std::chrono::steady_clock::now(); |
| auto elapsedTime = std::chrono::duration_cast<std::chrono::seconds>( |
| currentTime - startTime) |
| .count(); |
| if (elapsedTime >= timeoutSeconds) |
| { |
| close(lockFd); |
| throw std::runtime_error( |
| "Timeout acquiring lock on file: " + lockFilePath); |
| } |
| |
| // Wait before retrying |
| std::this_thread::sleep_for(std::chrono::milliseconds(100)); |
| } |
| } |
| |
| ~FileLock() |
| { |
| if (lockFd != -1) |
| { |
| flock(lockFd, LOCK_UN); |
| close(lockFd); |
| } |
| } |
| |
| // Disable copy and move operations |
| FileLock(const FileLock&) = delete; |
| FileLock& operator=(const FileLock&) = delete; |
| FileLock(FileLock&&) = delete; |
| FileLock& operator=(FileLock&&) = delete; |
| |
| private: |
| std::string lockFilePath; |
| int lockFd = -1; |
| }; |
| |
| } // namespace responder |
| } // namespace pldm |