blob: 7d8f922ddde8a69bde77f280007807e23a8bccdb [file]
#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