authorgravatar for leroycepearson@geemili.xyzLeRoyce Pearson <leroycepearson@geemili.xyz> 2020-03-14 15:31:54-06:00
committergravatar for leroycepearson@geemili.xyzLeRoyce Pearson <leroycepearson@geemili.xyz> 2020-03-14 15:31:54-06:00
log49128c86f8eb6cc42f55b6a7a9d0aa66d222b1a6
tree0454c3e9390bd6bf56508fcd8baa56955bcfae13
parent7ab77685a8eb69293fc0229f7b01a6a67332740a

Extract `run_lock_file_test`


1 files changed, 107 insertions(+), 100 deletions(-)

lib/std/fs.zig+107-100
......@@ -1723,50 +1723,70 @@ test "" {
17231723
17241724const FILE_LOCK_TEST_SLEEP_TIME = 1 * std.time.ns_per_s;
17251725
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_for_test),
1737// try std.Thread.spawn(&ctxs[1], lock_file_for_test),
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// _ = std.os.waitpid(childpid, 0);
1758//
1759// std.debug.assert(!ctxs[0].overlaps(&ctxs[1]));
1760// } else {
1761// std.os.exit(0);
1762// }
1763// }
1764//
1765// cwd().deleteFile(filename) catch |err| switch (err) {
1766// error.FileNotFound => {},
1767// else => return err,
1768// };
1769//}
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 var contexts = [_]FileLockTestContext{
1730 .{ .filename = filename, .create = true, .exclusive = true },
1731 .{ .filename = filename, .create = true, .exclusive = true },
1732 };
1733 try run_lock_file_test(&contexts);
1734
1735 // Check for an error
1736 var was_error = false;
1737 for (contexts) |context, idx| {
1738 if (context.err) |err| {
1739 was_error = true;
1740 std.debug.warn("\nError in context {}: {}\n", .{ idx, err });
1741 }
1742 }
1743 if (was_error) builtin.panic("There was an error in contexts", null);
1744
1745 std.debug.assert(!contexts[0].overlaps(&contexts[1]));
1746
1747 cwd().deleteFile(filename) catch |err| switch (err) {
1748 error.FileNotFound => {},
1749 else => return err,
1750 };
1751}
1752
1753test "create file, lock and read from multiple process at once" {
1754 const filename = "file_read_lock_test.txt";
1755 const filedata = "Hello, world!\n";
1756
1757 try std.fs.cwd().writeFile(filename, filedata);
1758
1759 var contexts = [_]FileLockTestContext{
1760 .{ .filename = filename, .create = false, .exclusive = false },
1761 .{ .filename = filename, .create = false, .exclusive = false },
1762 .{ .filename = filename, .create = false, .exclusive = true },
1763 };
1764
1765 try run_lock_file_test(&contexts);
1766
1767 var was_error = false;
1768 for (contexts) |context, idx| {
1769 if (context.err) |err| {
1770 was_error = true;
1771 std.debug.warn("\nError in context {}: {}\n", .{ idx, err });
1772 }
1773 }
1774 if (was_error) builtin.panic("There was an error in contexts", null);
1775
1776 std.debug.assert(contexts[0].overlaps(&contexts[1]));
1777 std.debug.assert(!contexts[2].overlaps(&contexts[0]));
1778 std.debug.assert(!contexts[2].overlaps(&contexts[1]));
1779 if (contexts[0].bytes_read.? != filedata.len) {
1780 std.debug.warn("\n bytes_read: {}, expected: {} \n", .{ contexts[0].bytes_read, filedata.len });
1781 }
1782 std.debug.assert(contexts[0].bytes_read.? == filedata.len);
1783 std.debug.assert(contexts[1].bytes_read.? == filedata.len);
1784
1785 cwd().deleteFile(filename) catch |err| switch (err) {
1786 error.FileNotFound => {},
1787 else => return err,
1788 };
1789}
17701790
17711791const FileLockTestContext = struct {
17721792 filename: []const u8,
......@@ -1778,6 +1798,7 @@ const FileLockTestContext = struct {
17781798 exclusive: bool,
17791799
17801800 // Output variables
1801 err: ?(File.OpenError || std.os.ReadError) = null,
17811802 start_time: u64 = 0,
17821803 end_time: u64 = 0,
17831804 bytes_read: ?usize = null,
......@@ -1789,69 +1810,65 @@ const FileLockTestContext = struct {
17891810 fn run(ctx: *@This()) void {
17901811 var file: File = undefined;
17911812 if (ctx.create) {
1792 file = cwd().createFile(ctx.filename, .{ .lock = true }) catch unreachable;
1813 file = cwd().createFile(ctx.filename, .{ .lock = true }) catch |err| {
1814 ctx.err = err;
1815 return;
1816 };
17931817 } else {
1794 file = cwd().openFile(ctx.filename, .{ .lock = true, .write = ctx.exclusive }) catch unreachable;
1818 file = cwd().openFile(ctx.filename, .{ .lock = true, .write = ctx.exclusive }) catch |err| {
1819 ctx.err = err;
1820 return;
1821 };
17951822 }
1823 defer file.close();
17961824
17971825 ctx.start_time = std.time.milliTimestamp();
17981826
1799 var buffer: [100]u8 = undefined;
1800 ctx.bytes_read = 0;
1801 while (true) {
1802 const amt = file.read(buffer[0..]) catch unreachable;
1803 if (amt == 0) break;
1804 ctx.bytes_read.? += amt;
1827 if (!ctx.create) {
1828 var buffer: [100]u8 = undefined;
1829 ctx.bytes_read = 0;
1830 while (true) {
1831 const amt = file.read(buffer[0..]) catch |err| {
1832 ctx.err = err;
1833 return;
1834 };
1835 if (amt == 0) break;
1836 ctx.bytes_read.? += amt;
1837 }
18051838 }
1839
18061840 std.time.sleep(FILE_LOCK_TEST_SLEEP_TIME);
18071841
18081842 ctx.end_time = std.time.milliTimestamp();
1809 file.close();
18101843 }
18111844};
18121845
1813test "create file, lock and read from multiple process at once" {
1814 const filename = "file_read_lock_test.txt";
1815 const filedata = "Hello, world!\n";
1816
1817 try std.fs.cwd().writeFile(filename, filedata);
1818
1819 const NUM_PROCESSES = 3;
1820 var shared_mem: if (builtin.os.tag == .windows) [NUM_PROCESSES]FileLockTestContext else []align(mem.page_size) u8 = undefined;
1846fn run_lock_file_test(contexts: []FileLockTestContext) !void {
1847 var shared_mem: if (builtin.os.tag == .windows) void else []align(mem.page_size) u8 = undefined;
18211848
18221849 var ctxs: []FileLockTestContext = undefined;
18231850 if (builtin.os.tag == .windows) {
1824 ctxs = shared_mem[0..NUM_PROCESSES];
1851 ctxs = contexts;
18251852 } else {
1826 shared_mem = try std.os.mmap(null, NUM_PROCESSES * @sizeOf(FileLockTestContext), std.os.PROT_READ | std.os.PROT_WRITE, std.os.MAP_SHARED | std.os.MAP_ANONYMOUS, -1, 0);
1853 shared_mem = try std.os.mmap(null, contexts.len * @sizeOf(FileLockTestContext), std.os.PROT_READ | std.os.PROT_WRITE, std.os.MAP_SHARED | std.os.MAP_ANONYMOUS, -1, 0);
18271854 const ctxs_ptr = @ptrCast([*]FileLockTestContext, shared_mem.ptr);
1828 ctxs = ctxs_ptr[0..NUM_PROCESSES];
1829 }
1855 ctxs = ctxs_ptr[0..contexts.len];
18301856
1831 ctxs[0] = .{
1832 .filename = filename,
1833 .create = false,
1834 .exclusive = false,
1835 };
1836 ctxs[1] = .{
1837 .filename = filename,
1838 .create = false,
1839 .exclusive = false,
1840 };
1841 ctxs[2] = .{
1842 .filename = filename,
1843 .create = false,
1844 .exclusive = true,
1845 };
1857 for (contexts) |context, idx| {
1858 ctxs[idx] = context;
1859 }
1860 }
18461861
18471862 if (builtin.os.tag == .windows) {
1848 const threads: [NUM_PROCESSES]*std.Thread = undefined;
1849 for (ctxs) |*ctx, idx| {
1850 threads[idx] = try std.Thread.spawn(ctx, Context.run);
1863 const threads = std.ArrayList(*std.Thread).init(testing.allocator);
1864 defer {
1865 for (threads.toSlice()) |thread| {
1866 thread.wait();
1867 }
1868 threads.deinit();
18511869 }
1852
1853 for (threads[0..]) |thread| {
1854 thread.wait();
1870 for (ctxs) |*ctx, idx| {
1871 threads.append(try std.Thread.spawn(ctx, Context.run));
18551872 }
18561873 } else {
18571874 var ctx_opt: ?*FileLockTestContext = null;
......@@ -1875,21 +1892,11 @@ test "create file, lock and read from multiple process at once" {
18751892 }
18761893 }
18771894
1878 std.debug.assert(ctxs[0].overlaps(&ctxs[1]));
1879 std.debug.assert(!ctxs[2].overlaps(&ctxs[0]));
1880 std.debug.assert(!ctxs[2].overlaps(&ctxs[1]));
1881 if (ctxs[0].bytes_read.? != filedata.len) {
1882 std.debug.warn("\n bytes_read: {}, expected: {} \n", .{ ctxs[0].bytes_read, filedata.len });
1883 }
1884 std.debug.assert(ctxs[0].bytes_read.? == filedata.len);
1885 std.debug.assert(ctxs[1].bytes_read.? == filedata.len);
1886
18871895 if (builtin.os.tag != .windows) {
1896 // Copy contexts out of shared memory
1897 for (ctxs) |ctx, idx| {
1898 contexts[idx] = ctx;
1899 }
18881900 std.os.munmap(shared_mem);
18891901 }
1890
1891 cwd().deleteFile(filename) catch |err| switch (err) {
1892 error.FileNotFound => {},
1893 else => return err,
1894 };
18951902}