| ... | ... | @@ -1720,3 +1720,69 @@ test "" { |
| 1720 | 1720 | _ = @import("fs/get_app_data_dir.zig"); |
| 1721 | 1721 | _ = @import("fs/watch.zig"); |
| 1722 | 1722 | } |
| 1723 | |
| 1724 | const FILE_LOCK_TEST_SLEEP_TIME = 1 * std.time.ns_per_s; |
| 1725 | |
| 1726 | test "open file with lock twice, make sure it wasn't open at the same time" { |
| 1727 | const filename = "file_lock_test.txt"; |
| 1728 | |
| 1729 | if (builtin.os.tag == .windows) { |
| 1730 | var ctxs = [_]FileLockTestContext{ |
| 1731 | .{ .filename = filename }, |
| 1732 | .{ .filename = filename }, |
| 1733 | }; |
| 1734 | |
| 1735 | const threads = [_]*std.Thread{ |
| 1736 | try std.Thread.spawn(&ctxs[0], lock_file), |
| 1737 | try std.Thread.spawn(&ctxs[1], lock_file), |
| 1738 | }; |
| 1739 | |
| 1740 | for (threads[0..]) |thread| { |
| 1741 | thread.wait(); |
| 1742 | } |
| 1743 | |
| 1744 | std.debug.assert(!ctxs[0].overlaps(&ctxs[1])); |
| 1745 | } else { |
| 1746 | const shared_mem = try std.os.mmap(null, 2 * @sizeOf(FileLockTestContext), std.os.PROT_READ | std.os.PROT_WRITE, std.os.MAP_SHARED | std.os.MAP_ANONYMOUS, -1, 0); |
| 1747 | defer std.os.munmap(shared_mem); |
| 1748 | const ctxs = @ptrCast([*]FileLockTestContext, shared_mem.ptr); |
| 1749 | |
| 1750 | const childpid = try std.os.fork(); |
| 1751 | const ctx_idx: usize = if (childpid != 0) 0 else 1; |
| 1752 | |
| 1753 | ctxs[ctx_idx].filename = filename; |
| 1754 | lock_file_for_test(&ctxs[ctx_idx]); |
| 1755 | |
| 1756 | if (childpid != 0) { |
| 1757 | var status: u32 = 0; |
| 1758 | _ = std.os.linux.waitpid(childpid, &status, 0); |
| 1759 | |
| 1760 | std.debug.assert(!ctxs[0].overlaps(&ctxs[1])); |
| 1761 | } |
| 1762 | } |
| 1763 | |
| 1764 | cwd().deleteFile(filename) catch |err| switch (err) { |
| 1765 | error.FileNotFound => {}, |
| 1766 | else => return err, |
| 1767 | }; |
| 1768 | } |
| 1769 | |
| 1770 | const FileLockTestContext = struct { |
| 1771 | filename: []const u8, |
| 1772 | |
| 1773 | // Output variables |
| 1774 | start_time: u64 = 0, |
| 1775 | end_time: u64 = 0, |
| 1776 | |
| 1777 | fn overlaps(self: *const @This(), other: *const @This()) bool { |
| 1778 | return (self.start_time < other.end_time) and (self.end_time > other.start_time); |
| 1779 | } |
| 1780 | }; |
| 1781 | |
| 1782 | fn lock_file_for_test(ctx: *FileLockTestContext) void { |
| 1783 | const file = cwd().createFile(ctx.filename, .{ .lock = true }) catch unreachable; |
| 1784 | ctx.start_time = std.time.milliTimestamp(); |
| 1785 | std.time.sleep(FILE_LOCK_TEST_SLEEP_TIME); |
| 1786 | ctx.end_time = std.time.milliTimestamp(); |
| 1787 | file.close(); |
| 1788 | } |