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 "" {...@@ -1723,50 +1723,70 @@ test "" {
17231723
1724const FILE_LOCK_TEST_SLEEP_TIME = 1 * std.time.ns_per_s;1724const 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" {1726test "open file with lock twice, make sure it wasn't open at the same time" {
1727// const filename = "file_lock_test.txt";1727 const filename = "file_lock_test.txt";
1728//1728
1729// if (builtin.os.tag == .windows) {1729 var contexts = [_]FileLockTestContext{
1730// var ctxs = [_]FileLockTestContext{1730 .{ .filename = filename, .create = true, .exclusive = true },
1731// .{ .filename = filename },1731 .{ .filename = filename, .create = true, .exclusive = true },
1732// .{ .filename = filename },1732 };
1733// };1733 try run_lock_file_test(&contexts);
1734//1734
1735// const threads = [_]*std.Thread{1735 // Check for an error
1736// try std.Thread.spawn(&ctxs[0], lock_file_for_test),1736 var was_error = false;
1737// try std.Thread.spawn(&ctxs[1], lock_file_for_test),1737 for (contexts) |context, idx| {
1738// };1738 if (context.err) |err| {
1739//1739 was_error = true;
1740// for (threads[0..]) |thread| {1740 std.debug.warn("\nError in context {}: {}\n", .{ idx, err });
1741// thread.wait();1741 }
1742// }1742 }
1743//1743 if (was_error) builtin.panic("There was an error in contexts", null);
1744// std.debug.assert(!ctxs[0].overlaps(&ctxs[1]));1744
1745// } else {1745 std.debug.assert(!contexts[0].overlaps(&contexts[1]));
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);1746
1747// defer std.os.munmap(shared_mem);1747 cwd().deleteFile(filename) catch |err| switch (err) {
1748// const ctxs = @ptrCast([*]FileLockTestContext, shared_mem.ptr);1748 error.FileNotFound => {},
1749//1749 else => return err,
1750// const childpid = try std.os.fork();1750 };
1751// const ctx_idx: usize = if (childpid != 0) 0 else 1;1751}
1752//1752
1753// ctxs[ctx_idx].filename = filename;1753test "create file, lock and read from multiple process at once" {
1754// lock_file_for_test(&ctxs[ctx_idx]);1754 const filename = "file_read_lock_test.txt";
1755//1755 const filedata = "Hello, world!\n";
1756// if (childpid != 0) {1756
1757// _ = std.os.waitpid(childpid, 0);1757 try std.fs.cwd().writeFile(filename, filedata);
1758//1758
1759// std.debug.assert(!ctxs[0].overlaps(&ctxs[1]));1759 var contexts = [_]FileLockTestContext{
1760// } else {1760 .{ .filename = filename, .create = false, .exclusive = false },
1761// std.os.exit(0);1761 .{ .filename = filename, .create = false, .exclusive = false },
1762// }1762 .{ .filename = filename, .create = false, .exclusive = true },
1763// }1763 };
1764//1764
1765// cwd().deleteFile(filename) catch |err| switch (err) {1765 try run_lock_file_test(&contexts);
1766// error.FileNotFound => {},1766
1767// else => return err,1767 var was_error = false;
1768// };1768 for (contexts) |context, idx| {
1769//}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
1771const FileLockTestContext = struct {1791const FileLockTestContext = struct {
1772 filename: []const u8,1792 filename: []const u8,
...@@ -1778,6 +1798,7 @@ const FileLockTestContext = struct {...@@ -1778,6 +1798,7 @@ const FileLockTestContext = struct {
1778 exclusive: bool,1798 exclusive: bool,
17791799
1780 // Output variables1800 // Output variables
1801 err: ?(File.OpenError || std.os.ReadError) = null,
1781 start_time: u64 = 0,1802 start_time: u64 = 0,
1782 end_time: u64 = 0,1803 end_time: u64 = 0,
1783 bytes_read: ?usize = null,1804 bytes_read: ?usize = null,
...@@ -1789,69 +1810,65 @@ const FileLockTestContext = struct {...@@ -1789,69 +1810,65 @@ const FileLockTestContext = struct {
1789 fn run(ctx: *@This()) void {1810 fn run(ctx: *@This()) void {
1790 var file: File = undefined;1811 var file: File = undefined;
1791 if (ctx.create) {1812 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 };
1793 } else {1817 } 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 };
1795 }1822 }
1823 defer file.close();
17961824
1797 ctx.start_time = std.time.milliTimestamp();1825 ctx.start_time = std.time.milliTimestamp();
17981826
1799 var buffer: [100]u8 = undefined;1827 if (!ctx.create) {
1800 ctx.bytes_read = 0;1828 var buffer: [100]u8 = undefined;
1801 while (true) {1829 ctx.bytes_read = 0;
1802 const amt = file.read(buffer[0..]) catch unreachable;1830 while (true) {
1803 if (amt == 0) break;1831 const amt = file.read(buffer[0..]) catch |err| {
1804 ctx.bytes_read.? += amt;1832 ctx.err = err;
1833 return;
1834 };
1835 if (amt == 0) break;
1836 ctx.bytes_read.? += amt;
1837 }
1805 }1838 }
1839
1806 std.time.sleep(FILE_LOCK_TEST_SLEEP_TIME);1840 std.time.sleep(FILE_LOCK_TEST_SLEEP_TIME);
18071841
1808 ctx.end_time = std.time.milliTimestamp();1842 ctx.end_time = std.time.milliTimestamp();
1809 file.close();
1810 }1843 }
1811};1844};
18121845
1813test "create file, lock and read from multiple process at once" {1846fn run_lock_file_test(contexts: []FileLockTestContext) !void {
1814 const filename = "file_read_lock_test.txt";1847 var shared_mem: if (builtin.os.tag == .windows) void else []align(mem.page_size) u8 = undefined;
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;
18211848
1822 var ctxs: []FileLockTestContext = undefined;1849 var ctxs: []FileLockTestContext = undefined;
1823 if (builtin.os.tag == .windows) {1850 if (builtin.os.tag == .windows) {
1824 ctxs = shared_mem[0..NUM_PROCESSES];1851 ctxs = contexts;
1825 } else {1852 } 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);
1827 const ctxs_ptr = @ptrCast([*]FileLockTestContext, shared_mem.ptr);1854 const ctxs_ptr = @ptrCast([*]FileLockTestContext, shared_mem.ptr);
1828 ctxs = ctxs_ptr[0..NUM_PROCESSES];1855 ctxs = ctxs_ptr[0..contexts.len];
1829 }
18301856
1831 ctxs[0] = .{1857 for (contexts) |context, idx| {
1832 .filename = filename,1858 ctxs[idx] = context;
1833 .create = false,1859 }
1834 .exclusive = false,1860 }
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 };
18461861
1847 if (builtin.os.tag == .windows) {1862 if (builtin.os.tag == .windows) {
1848 const threads: [NUM_PROCESSES]*std.Thread = undefined;1863 const threads = std.ArrayList(*std.Thread).init(testing.allocator);
1849 for (ctxs) |*ctx, idx| {1864 defer {
1850 threads[idx] = try std.Thread.spawn(ctx, Context.run);1865 for (threads.toSlice()) |thread| {
1866 thread.wait();
1867 }
1868 threads.deinit();
1851 }1869 }
18521870 for (ctxs) |*ctx, idx| {
1853 for (threads[0..]) |thread| {1871 threads.append(try std.Thread.spawn(ctx, Context.run));
1854 thread.wait();
1855 }1872 }
1856 } else {1873 } else {
1857 var ctx_opt: ?*FileLockTestContext = null;1874 var ctx_opt: ?*FileLockTestContext = null;
...@@ -1875,21 +1892,11 @@ test "create file, lock and read from multiple process at once" {...@@ -1875,21 +1892,11 @@ test "create file, lock and read from multiple process at once" {
1875 }1892 }
1876 }1893 }
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
1887 if (builtin.os.tag != .windows) {1895 if (builtin.os.tag != .windows) {
1896 // Copy contexts out of shared memory
1897 for (ctxs) |ctx, idx| {
1898 contexts[idx] = ctx;
1899 }
1888 std.os.munmap(shared_mem);1900 std.os.munmap(shared_mem);
1889 }1901 }
1890
1891 cwd().deleteFile(filename) catch |err| switch (err) {
1892 error.FileNotFound => {},
1893 else => return err,
1894 };
1895}1902}