| ... | ... | @@ -597,10 +597,11 @@ pub const Dir = struct { |
| 597 | 597 | |
| 598 | 598 | // Use the O_ locking flags if the os supports them |
| 599 | 599 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK"); |
| 600 | const nonblocking_lock_flag = if (has_flock_open_flags and flags.lock_nonblocking) (os.O_NONBLOCK | os.O_SYNC) else @as(u32, 0); |
| 600 | 601 | const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { |
| 601 | 602 | .None => @as(u32, 0), |
| 602 | | .Shared => os.O_SHLOCK, |
| 603 | | .Exclusive => os.O_EXLOCK, |
| 603 | .Shared => os.O_SHLOCK | nonblocking_lock_flag, |
| 604 | .Exclusive => os.O_EXLOCK | nonblocking_lock_flag, |
| 604 | 605 | } else 0; |
| 605 | 606 | |
| 606 | 607 | const O_LARGEFILE = if (@hasDecl(os, "O_LARGEFILE")) os.O_LARGEFILE else 0; |
| ... | ... | @@ -617,10 +618,11 @@ pub const Dir = struct { |
| 617 | 618 | |
| 618 | 619 | if (!has_flock_open_flags and flags.lock != .None) { |
| 619 | 620 | // TODO: integrate async I/O |
| 621 | const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK_NB else @as(i32, 0); |
| 620 | 622 | try os.flock(fd, switch (flags.lock) { |
| 621 | 623 | .None => unreachable, |
| 622 | | .Shared => os.LOCK_SH, |
| 623 | | .Exclusive => os.LOCK_EX, |
| 624 | .Shared => os.LOCK_SH | lock_nonblocking, |
| 625 | .Exclusive => os.LOCK_EX | lock_nonblocking, |
| 624 | 626 | }); |
| 625 | 627 | } |
| 626 | 628 | |
| ... | ... | @@ -644,12 +646,12 @@ pub const Dir = struct { |
| 644 | 646 | |
| 645 | 647 | const share_access = switch (flags.lock) { |
| 646 | 648 | .None => @as(?w.ULONG, null), |
| 647 | | .Shared => w.FILE_SHARE_READ, |
| 648 | | .Exclusive => @as(?w.ULONG, 0), |
| 649 | .Shared => w.FILE_SHARE_READ | w.FILE_SHARE_DELETE, |
| 650 | .Exclusive => w.FILE_SHARE_DELETE, |
| 649 | 651 | }; |
| 650 | 652 | |
| 651 | 653 | return @as(File, .{ |
| 652 | | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, w.FILE_OPEN), |
| 654 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, flags.lock_nonblocking, w.FILE_OPEN), |
| 653 | 655 | .io_mode = .blocking, |
| 654 | 656 | }); |
| 655 | 657 | } |
| ... | ... | @@ -677,6 +679,7 @@ pub const Dir = struct { |
| 677 | 679 | |
| 678 | 680 | // Use the O_ locking flags if the os supports them |
| 679 | 681 | const has_flock_open_flags = @hasDecl(os, "O_EXLOCK"); |
| 682 | const nonblocking_lock_flag = if (has_flock_open_flags and flags.lock_nonblocking) (os.O_NONBLOCK | os.O_SYNC) else @as(u32, 0); |
| 680 | 683 | const lock_flag: u32 = if (has_flock_open_flags) switch (flags.lock) { |
| 681 | 684 | .None => @as(u32, 0), |
| 682 | 685 | .Shared => os.O_SHLOCK, |
| ... | ... | @@ -695,10 +698,11 @@ pub const Dir = struct { |
| 695 | 698 | |
| 696 | 699 | if (!has_flock_open_flags and flags.lock != .None) { |
| 697 | 700 | // TODO: integrate async I/O |
| 701 | const lock_nonblocking = if (flags.lock_nonblocking) os.LOCK_NB else @as(i32, 0); |
| 698 | 702 | try os.flock(fd, switch (flags.lock) { |
| 699 | 703 | .None => unreachable, |
| 700 | | .Shared => os.LOCK_SH, |
| 701 | | .Exclusive => os.LOCK_EX, |
| 704 | .Shared => os.LOCK_SH | lock_nonblocking, |
| 705 | .Exclusive => os.LOCK_EX | lock_nonblocking, |
| 702 | 706 | }); |
| 703 | 707 | } |
| 704 | 708 | |
| ... | ... | @@ -720,12 +724,12 @@ pub const Dir = struct { |
| 720 | 724 | |
| 721 | 725 | const share_access = switch (flags.lock) { |
| 722 | 726 | .None => @as(?w.ULONG, null), |
| 723 | | .Shared => w.FILE_SHARE_READ, |
| 724 | | .Exclusive => @as(?w.ULONG, 0), |
| 727 | .Shared => w.FILE_SHARE_READ | w.FILE_SHARE_DELETE, |
| 728 | .Exclusive => w.FILE_SHARE_DELETE, |
| 725 | 729 | }; |
| 726 | 730 | |
| 727 | 731 | return @as(File, .{ |
| 728 | | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, creation), |
| 732 | .handle = try os.windows.OpenFileW(self.fd, sub_path_w, null, access_mask, share_access, flags.lock_nonblocking, creation), |
| 729 | 733 | .io_mode = .blocking, |
| 730 | 734 | }); |
| 731 | 735 | } |
| ... | ... | @@ -1680,6 +1684,21 @@ test "" { |
| 1680 | 1684 | |
| 1681 | 1685 | const FILE_LOCK_TEST_SLEEP_TIME = 1 * std.time.ns_per_s; |
| 1682 | 1686 | |
| 1687 | test "open file with exclusive nonblocking lock twice" { |
| 1688 | const dir = cwd(); |
| 1689 | const filename = "file_nonblocking_lock_test.txt"; |
| 1690 | |
| 1691 | const file1 = try dir.createFile(filename, .{ .lock = .Exclusive, .lock_nonblocking = true }); |
| 1692 | |
| 1693 | const file2 = dir.createFile(filename, .{ .lock = .Exclusive, .lock_nonblocking = true }); |
| 1694 | std.debug.assert(std.meta.eql(file2, error.WouldBlock)); |
| 1695 | |
| 1696 | dir.deleteFile(filename) catch |err| switch (err) { |
| 1697 | error.FileNotFound => {}, |
| 1698 | else => return err, |
| 1699 | }; |
| 1700 | } |
| 1701 | |
| 1683 | 1702 | test "open file with lock twice, make sure it wasn't open at the same time" { |
| 1684 | 1703 | if (builtin.single_threaded) return; |
| 1685 | 1704 | |