Commit 078aa5f7b2
Changed files (17)
lib/std/c/darwin.zig
@@ -357,11 +357,11 @@ pub const off_t = i64;
pub const ino_t = u64;
pub const Flock = extern struct {
- l_start: off_t,
- l_len: off_t,
- l_pid: pid_t,
- l_type: i16,
- l_whence: i16,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
+ type: i16,
+ whence: i16,
};
pub const Stat = extern struct {
lib/std/c/dragonfly.zig
@@ -929,11 +929,11 @@ pub const LOCK = struct {
};
pub const Flock = extern struct {
- l_start: off_t,
- l_len: off_t,
- l_pid: pid_t,
- l_type: c_short,
- l_whence: c_short,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
+ type: c_short,
+ whence: c_short,
};
pub const addrinfo = extern struct {
lib/std/c/freebsd.zig
@@ -193,12 +193,12 @@ pub const dl_phdr_info = extern struct {
};
pub const Flock = extern struct {
- l_start: off_t,
- l_len: off_t,
- l_pid: pid_t,
- l_type: i16,
- l_whence: i16,
- l_sysid: i32,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
+ type: i16,
+ whence: i16,
+ sysid: i32,
__unused: [4]u8,
};
lib/std/c/haiku.zig
@@ -159,11 +159,11 @@ pub const dl_phdr_info = extern struct {
};
pub const Flock = extern struct {
- l_type: c_short,
- l_whence: c_short,
- l_start: off_t,
- l_len: off_t,
- l_pid: pid_t,
+ type: c_short,
+ whence: c_short,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
};
pub const msghdr = extern struct {
lib/std/c/netbsd.zig
@@ -169,11 +169,11 @@ pub const dl_phdr_info = extern struct {
};
pub const Flock = extern struct {
- l_start: off_t,
- l_len: off_t,
- l_pid: pid_t,
- l_type: i16,
- l_whence: i16,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
+ type: i16,
+ whence: i16,
};
pub const addrinfo = extern struct {
lib/std/c/openbsd.zig
@@ -94,11 +94,11 @@ pub const dl_phdr_info = extern struct {
};
pub const Flock = extern struct {
- l_start: off_t,
- l_len: off_t,
- l_pid: pid_t,
- l_type: c_short,
- l_whence: c_short,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
+ type: c_short,
+ whence: c_short,
};
pub const addrinfo = extern struct {
lib/std/c/solaris.zig
@@ -116,13 +116,13 @@ pub const RTLD = struct {
};
pub const Flock = extern struct {
- l_type: c_short,
- l_whence: c_short,
- l_start: off_t,
+ type: c_short,
+ whence: c_short,
+ start: off_t,
// len == 0 means until end of file.
- l_len: off_t,
- l_sysid: c_int,
- l_pid: pid_t,
+ len: off_t,
+ sysid: c_int,
+ pid: pid_t,
__pad: [4]c_long,
};
lib/std/os/linux/arm-eabi.zig
@@ -638,12 +638,12 @@ pub const HWCAP = struct {
};
pub const Flock = extern struct {
- l_type: i16,
- l_whence: i16,
+ type: i16,
+ whence: i16,
__pad0: [4]u8,
- l_start: off_t,
- l_len: off_t,
- l_pid: pid_t,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
__unused: [4]u8,
};
lib/std/os/linux/arm64.zig
@@ -490,11 +490,11 @@ pub const VDSO = struct {
};
pub const Flock = extern struct {
- l_type: i16,
- l_whence: i16,
- l_start: off_t,
- l_len: off_t,
- l_pid: pid_t,
+ type: i16,
+ whence: i16,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
__unused: [4]u8,
};
lib/std/os/linux/mips.zig
@@ -707,12 +707,12 @@ pub const VDSO = struct {
};
pub const Flock = extern struct {
- l_type: i16,
- l_whence: i16,
+ type: i16,
+ whence: i16,
__pad0: [4]u8,
- l_start: off_t,
- l_len: off_t,
- l_pid: pid_t,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
__unused: [4]u8,
};
lib/std/os/linux/powerpc.zig
@@ -643,11 +643,11 @@ pub const VDSO = struct {
};
pub const Flock = extern struct {
- l_type: i16,
- l_whence: i16,
- l_start: off_t,
- l_len: off_t,
- l_pid: pid_t,
+ type: i16,
+ whence: i16,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
};
pub const msghdr = extern struct {
lib/std/os/linux/powerpc64.zig
@@ -617,11 +617,11 @@ pub const VDSO = struct {
};
pub const Flock = extern struct {
- l_type: i16,
- l_whence: i16,
- l_start: off_t,
- l_len: off_t,
- l_pid: pid_t,
+ type: i16,
+ whence: i16,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
__unused: [4]u8,
};
lib/std/os/linux/riscv64.zig
@@ -480,11 +480,11 @@ pub const timeval = extern struct {
};
pub const Flock = extern struct {
- l_type: i16,
- l_whence: i16,
- l_start: off_t,
- l_len: off_t,
- l_pid: pid_t,
+ type: i16,
+ whence: i16,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
__unused: [4]u8,
};
lib/std/os/linux/sparc64.zig
@@ -648,11 +648,11 @@ pub const VDSO = struct {
};
pub const Flock = extern struct {
- l_type: i16,
- l_whence: i16,
- l_start: off_t,
- l_len: off_t,
- l_pid: pid_t,
+ type: i16,
+ whence: i16,
+ start: off_t,
+ len: off_t,
+ pid: pid_t,
};
pub const msghdr = extern struct {
lib/std/os/test.zig
@@ -821,3 +821,60 @@ test "writev longer than IOV_MAX" {
const amt = try file.writev(&iovecs);
try testing.expectEqual(@as(usize, os.IOV_MAX), amt);
}
+
+test "POSIX file locking with fcntl" {
+ if (native_os == .windows or native_os == .wasi) return error.SkipZigTest;
+
+ var tmp = std.testing.tmpDir(.{});
+ defer tmp.cleanup();
+
+ // Create a temporary lock file
+ var file = try tmp.dir.createFile("lock", .{ .read = true });
+ defer file.close();
+ try file.setEndPos(2);
+ const fd = file.handle;
+
+ // Place an exclusive lock on the first byte, and a shared lock on the second byte:
+ var struct_flock = std.mem.zeroInit(std.os.Flock, .{ .type = std.os.F.WRLCK });
+ _ = try std.os.fcntl(fd, std.os.F.SETLK, @ptrToInt(&struct_flock));
+ struct_flock.start = 1;
+ struct_flock.type = std.os.F.RDLCK;
+ _ = try std.os.fcntl(fd, std.os.F.SETLK, @ptrToInt(&struct_flock));
+
+ // Check the locks in a child process:
+ const pid = try std.os.fork();
+ if (pid == 0) {
+ // child expects be denied the exclusive lock:
+ struct_flock.start = 0;
+ struct_flock.type = std.os.F.WRLCK;
+ try expectError(error.Locked, std.os.fcntl(fd, std.os.F.SETLK, @ptrToInt(&struct_flock)));
+ // child expects to get the shared lock:
+ struct_flock.start = 1;
+ struct_flock.type = std.os.F.RDLCK;
+ _ = try std.os.fcntl(fd, std.os.F.SETLK, @ptrToInt(&struct_flock));
+ // child waits for the exclusive lock in order to test deadlock:
+ struct_flock.start = 0;
+ struct_flock.type = std.os.F.WRLCK;
+ _ = try std.os.fcntl(fd, std.os.F.SETLKW, @ptrToInt(&struct_flock));
+ // child exits without continuing:
+ std.os.exit(0);
+ } else {
+ // parent waits for child to get shared lock:
+ std.time.sleep(1 * std.time.ns_per_ms);
+ // parent expects deadlock when attempting to upgrade the shared lock to exclusive:
+ struct_flock.start = 1;
+ struct_flock.type = std.os.F.WRLCK;
+ try expectError(error.DeadLock, std.os.fcntl(fd, std.os.F.SETLKW, @ptrToInt(&struct_flock)));
+ // parent releases exclusive lock:
+ struct_flock.start = 0;
+ struct_flock.type = std.os.F.UNLCK;
+ _ = try std.os.fcntl(fd, std.os.F.SETLK, @ptrToInt(&struct_flock));
+ // parent releases shared lock:
+ struct_flock.start = 1;
+ struct_flock.type = std.os.F.UNLCK;
+ _ = try std.os.fcntl(fd, std.os.F.SETLK, @ptrToInt(&struct_flock));
+ // parent waits for child:
+ const result = std.os.waitpid(pid, 0);
+ try expect(result.status == 0 * 256);
+ }
+}
lib/std/fs.zig
@@ -1045,6 +1045,8 @@ pub const Dir = struct {
error.FileBusy => unreachable,
error.Locked => unreachable,
error.PermissionDenied => unreachable,
+ error.DeadLock => unreachable,
+ error.LockedRegionLimitExceeded => unreachable,
else => |e| return e,
};
fl_flags &= ~@as(usize, os.O.NONBLOCK);
@@ -1052,6 +1054,8 @@ pub const Dir = struct {
error.FileBusy => unreachable,
error.Locked => unreachable,
error.PermissionDenied => unreachable,
+ error.DeadLock => unreachable,
+ error.LockedRegionLimitExceeded => unreachable,
else => |e| return e,
};
}
@@ -1197,6 +1201,8 @@ pub const Dir = struct {
error.FileBusy => unreachable,
error.Locked => unreachable,
error.PermissionDenied => unreachable,
+ error.DeadLock => unreachable,
+ error.LockedRegionLimitExceeded => unreachable,
else => |e| return e,
};
fl_flags &= ~@as(usize, os.O.NONBLOCK);
@@ -1204,6 +1210,8 @@ pub const Dir = struct {
error.FileBusy => unreachable,
error.Locked => unreachable,
error.PermissionDenied => unreachable,
+ error.DeadLock => unreachable,
+ error.LockedRegionLimitExceeded => unreachable,
else => |e| return e,
};
}
lib/std/os.zig
@@ -4513,6 +4513,8 @@ pub const FcntlError = error{
FileBusy,
ProcessFdQuotaExceeded,
Locked,
+ DeadLock,
+ LockedRegionLimitExceeded,
} || UnexpectedError;
pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize {
@@ -4521,13 +4523,15 @@ pub fn fcntl(fd: fd_t, cmd: i32, arg: usize) FcntlError!usize {
switch (errno(rc)) {
.SUCCESS => return @intCast(usize, rc),
.INTR => continue,
- .ACCES => return error.Locked,
+ .AGAIN, .ACCES => return error.Locked,
.BADF => unreachable,
.BUSY => return error.FileBusy,
.INVAL => unreachable, // invalid parameters
.PERM => return error.PermissionDenied,
.MFILE => return error.ProcessFdQuotaExceeded,
.NOTDIR => unreachable, // invalid parameter
+ .DEADLK => return error.DeadLock,
+ .NOLCK => return error.LockedRegionLimitExceeded,
else => |err| return unexpectedErrno(err),
}
}
@@ -4542,6 +4546,8 @@ fn setSockFlags(sock: socket_t, flags: u32) !void {
error.FileBusy => unreachable,
error.Locked => unreachable,
error.PermissionDenied => unreachable,
+ error.DeadLock => unreachable,
+ error.LockedRegionLimitExceeded => unreachable,
else => |e| return e,
};
fd_flags |= FD_CLOEXEC;
@@ -4549,6 +4555,8 @@ fn setSockFlags(sock: socket_t, flags: u32) !void {
error.FileBusy => unreachable,
error.Locked => unreachable,
error.PermissionDenied => unreachable,
+ error.DeadLock => unreachable,
+ error.LockedRegionLimitExceeded => unreachable,
else => |e| return e,
};
}
@@ -4570,6 +4578,8 @@ fn setSockFlags(sock: socket_t, flags: u32) !void {
error.FileBusy => unreachable,
error.Locked => unreachable,
error.PermissionDenied => unreachable,
+ error.DeadLock => unreachable,
+ error.LockedRegionLimitExceeded => unreachable,
else => |e| return e,
};
fl_flags |= O.NONBLOCK;
@@ -4577,6 +4587,8 @@ fn setSockFlags(sock: socket_t, flags: u32) !void {
error.FileBusy => unreachable,
error.Locked => unreachable,
error.PermissionDenied => unreachable,
+ error.DeadLock => unreachable,
+ error.LockedRegionLimitExceeded => unreachable,
else => |e| return e,
};
}