mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-26 02:11:18 +00:00
Hold the POSIX Lock With flock and Leave a Moved-Aside File to the User
An fcntl lock belongs to the process and goes with the first close of any other descriptor to the lock file, so a backup or an export walking the data dir could drop the guard's lock without a trace. On POSIX the guard holds a flock on its own open file instead, which nothing else in the process can release; Windows keeps LockFileEx. The Windows write probe opened the target for writing and took a sharing violation for a refusal, so a file another process merely held open was not saved at all; only a real denial refuses now, since the rename that follows moves an open destination aside. A file moved aside by a refused rename may be the last copy of a file or a file since deleted on purpose, so the sweep logs it and leaves it to the user rather than removing or restoring it. The sweep throttles itself per directory, so a load followed by a save reads each directory once, and the identity check on the lock file runs at most once a second, so a scan of hundreds of presets pays for it once. A config that stays unwritable backs off for longer with each failure in a row, and its backup copy is written after the config, never before. The Windows identity helper is shared with the rename that already computed it, and the header comment that had lost its indentation and its neighbour's description is whole again.
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <fcntl.h>
|
||||
#include <sys/file.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
@@ -149,9 +150,9 @@ TEST_CASE("InstanceLock serialises the threads of one process", "[InstanceLock]"
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
// The cross-process side of the lock is a POSIX fcntl write lock, which a
|
||||
// child process takes here directly; the same primitive backs the guard on
|
||||
// Windows through LockFileEx, but spawning a child there is not worth a test.
|
||||
// The cross-process side of the lock is a POSIX flock, which a child process
|
||||
// takes here directly; LockFileEx backs the guard on Windows, but spawning a
|
||||
// child there is not worth a test.
|
||||
TEST_CASE("InstanceLock yields to another process and reports it", "[InstanceLock]")
|
||||
{
|
||||
ScopedTemporaryFile lock_file(".lock");
|
||||
@@ -164,11 +165,8 @@ TEST_CASE("InstanceLock yields to another process and reports it", "[InstanceLoc
|
||||
const pid_t child = ::fork();
|
||||
REQUIRE(child >= 0);
|
||||
if (child == 0) {
|
||||
int fd = ::open(path.c_str(), O_RDWR | O_CREAT, 0644);
|
||||
struct flock lock{};
|
||||
lock.l_type = F_WRLCK;
|
||||
lock.l_whence = SEEK_SET;
|
||||
char byte = ::fcntl(fd, F_SETLK, &lock) == 0 ? '1' : '0';
|
||||
int fd = ::open(path.c_str(), O_RDWR | O_CREAT, 0644);
|
||||
char byte = ::flock(fd, LOCK_EX | LOCK_NB) == 0 ? '1' : '0';
|
||||
if (::write(child_holds[1], &byte, 1) != 1 || ::read(child_may_exit[0], &byte, 1) != 1)
|
||||
::_exit(1);
|
||||
::_exit(0);
|
||||
|
||||
Reference in New Issue
Block a user