Files
lix/lix/libstore/pathlocks.hh
T
eldritch horrors 7f95f9a85c libstore: mark blocking file locks as never async
Change-Id: Icf4633b5cd540cb777004c3dce6aa9d79a7f4063
2025-02-16 14:59:32 +00:00

97 lines
3.0 KiB
C++

#pragma once
///@file
#include "lix/libutil/error.hh"
#include "lix/libutil/file-descriptor.hh"
#include "lix/libutil/result.hh"
#include "lix/libutil/types.hh"
#include <chrono>
#include <kj/async.h>
#include <kj/common.h>
namespace nix {
/**
* Open (possibly create) a lock file and return the file descriptor.
* -1 is returned if create is false and the lock could not be opened
* because it doesn't exist. Any other error throws an exception.
*/
AutoCloseFD openLockFile(const Path & path, bool create);
enum LockType { ltRead, ltWrite };
void lockFile(int fd, LockType lockType, NeverAsync = {});
kj::Promise<Result<void>> lockFileAsync(int fd, LockType lockType);
/**
* Same as `lockFile`, but with a timeout. This timeout uses the POSIX `alarm`
* facility and a `SIGALRM` handler. Using this function from multiple threads
* in the same process is not safe: all `SIGALRM` handlers set previously will
* be overwritten while this function is executing and are restored on return.
*/
bool unsafeLockFileSingleThreaded(int fd, LockType lockType, std::chrono::seconds timeout);
bool tryLockFile(int fd, LockType lockType);
void unlockFile(int fd);
class PathLock
{
friend kj::Promise<Result<PathLock>> lockPathAsync(const Path & path, std::string_view waitMsg);
friend PathLock lockPath(const Path & path, std::string_view waitMsg, NeverAsync);
friend std::optional<PathLock> tryLockPath(const Path & path);
AutoCloseFD fd;
Path path;
PathLock(AutoCloseFD fd, const Path & path): fd(std::move(fd)), path(path) {}
static std::optional<PathLock>
lockImpl(const Path & path, std::string_view waitMsg, bool wait, NeverAsync = {});
public:
PathLock(PathLock &&) = default;
PathLock & operator=(PathLock &&) = default;
~PathLock();
void unlock();
};
kj::Promise<Result<PathLock>> lockPathAsync(const Path & path, std::string_view waitMsg = "");
PathLock lockPath(const Path & path, std::string_view waitMsg = "", NeverAsync = {});
std::optional<PathLock> tryLockPath(const Path & path);
using PathLocks = std::list<PathLock>;
PathLocks lockPaths(const PathSet & paths, std::string_view waitMsg = "", NeverAsync = {});
std::optional<PathLocks> tryLockPaths(const PathSet & paths);
class FdLock
{
struct Unlocker
{
void operator()(AutoCloseFD * fd)
{
try {
unlockFile(fd->get());
} catch (SysError &) {
ignoreExceptionInDestructor();
}
}
};
std::unique_ptr<AutoCloseFD, Unlocker> fd;
explicit FdLock(AutoCloseFD & fd): fd(&fd) {}
public:
static constexpr struct DontWait { explicit DontWait() = default; } dont_wait;
FdLock(AutoCloseFD & fd, LockType lockType, DontWait);
FdLock(AutoCloseFD & fd, LockType lockType, std::string_view waitMsg, NeverAsync = {});
static kj::Promise<Result<FdLock>>
lockAsync(AutoCloseFD & fd, LockType lockType, std::string_view waitMsg);
bool valid() const { return bool(fd); }
};
}