From 93bda02b786f73acc8c109aa7f1616872980b735 Mon Sep 17 00:00:00 2001 From: Adam Williamson Date: Wed, 4 Jan 2017 09:46:28 -0800 Subject: [PATCH] Use `flock` not `fcntl` locking for portability (POO #13822) The structure used by `fcntl` to define the type, location, and length of the desired lock uses integer types - `off_t` and `pid_t` - that are platform dependent. When writing C you can just create a structure using those types, but when writing perl, there doesn't seem to be any terribly easy way to find out what `off_t` and `pid_t` actually are, in `pack()` terms. There's a fairly good discussion here: https://www.perlmonks.org/bare/index.pl?node_id=920008 The code we currently have will work only on platforms where `off_t` happens to be a signed quad and `pid_t` happens to be a signed long. This seems to be the case for Fedora and SUSE 64-bit arches, but certainly isn't the case for Fedora 32-bit arches (where `off_t` is a signed long instead), and it may differ in other scenarios too. So I suggest we just use perl `flock` to lock the file before writing instead. I've looked into it quite a lot, and AFAICS, none of the differences between `fcntl` and `flock` should be a problem for us. I don't think `vars.json` is ever likely to be on an NFS share (`flock` doesn't work over NFS), we don't need to lock a specific area of the file, and the fact that flock is an advisory file descriptor lock rather than a filesystem lock record should not be a problem, as AFAICS, this is the *only* code we ever use to write to `vars.json`, and it will certainly respect its own lock. --- bmwqemu.pm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bmwqemu.pm b/bmwqemu.pm index 4f12b30..e07b5ae 100755 --- a/bmwqemu.pm +++ b/bmwqemu.pm @@ -19,6 +19,7 @@ use strict; use warnings; use Time::HiRes qw(sleep gettimeofday); use IO::Socket; +use Fcntl ':flock'; use Thread::Queue; use POSIX; @@ -80,7 +81,7 @@ sub save_vars() { my $fn = "vars.json"; unlink "vars.json" if -e "vars.json"; open(my $fd, ">", $fn); - fcntl($fd, F_SETLKW, pack('ssqql', F_WRLCK, 0, 0, 0, $$)) or die "cannot lock vars.json: $!\n"; + flock($fd, LOCK_EX) or die "cannot lock vars.json: $!\n"; truncate($fd, 0) or die "cannot truncate vars.json: $!\n"; # make sure the JSON is sorted