authorgravatar for leroycepearson@geemili.xyzLeRoyce Pearson <leroycepearson@geemili.xyz> 2020-03-12 21:12:01-06:00
committergravatar for leroycepearson@geemili.xyzLeRoyce Pearson <leroycepearson@geemili.xyz> 2020-03-14 10:12:46-06:00
log43c4faba5516bed725cd058ced6f1a53e166c6af
treed70221468012d6868e9d9b5435c7c647bc0f8ee6
parenta636b59cb58caf86dacd9814116bb459075b4cae

Add test to check that locking works


1 files changed, 66 insertions(+), 0 deletions(-)

lib/std/fs.zig+66
...@@ -1720,3 +1720,69 @@ test "" {...@@ -1720,3 +1720,69 @@ test "" {
1720 _ = @import("fs/get_app_data_dir.zig");1720 _ = @import("fs/get_app_data_dir.zig");
1721 _ = @import("fs/watch.zig");1721 _ = @import("fs/watch.zig");
1722}1722}
1723
1724const FILE_LOCK_TEST_SLEEP_TIME = 1 * std.time.ns_per_s;
1725
1726test "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
1770const 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
1782fn 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}