authorgravatar for leroycepearson@geemili.xyzLeRoyce Pearson <leroycepearson@geemili.xyz> 2020-03-14 13:29:49-06:00
committergravatar for leroycepearson@geemili.xyzLeRoyce Pearson <leroycepearson@geemili.xyz> 2020-03-14 13:29:49-06:00
log873c7a59e9943a944cf157345e9e27275b9069ba
treef8d70b7d6d2f3ad4c8091c302c6251343826fba6
parent72eb9933fd9ab4a7cb19185fce6c06331a325327

Add multiple read lock test


1 files changed, 70 insertions(+), 2 deletions(-)

lib/std/fs.zig+70-2
......@@ -1733,8 +1733,8 @@ test "open file with lock twice, make sure it wasn't open at the same time" {
17331733 };
17341734
17351735 const threads = [_]*std.Thread{
1736 try std.Thread.spawn(&ctxs[0], lock_file),
1737 try std.Thread.spawn(&ctxs[1], lock_file),
1736 try std.Thread.spawn(&ctxs[0], lock_file_for_test),
1737 try std.Thread.spawn(&ctxs[1], lock_file_for_test),
17381738 };
17391739
17401740 for (threads[0..]) |thread| {
......@@ -1772,6 +1772,7 @@ const FileLockTestContext = struct {
17721772 // Output variables
17731773 start_time: u64 = 0,
17741774 end_time: u64 = 0,
1775 bytes_read: ?usize = null,
17751776
17761777 fn overlaps(self: *const @This(), other: *const @This()) bool {
17771778 return (self.start_time < other.end_time) and (self.end_time > other.start_time);
......@@ -1785,3 +1786,70 @@ fn lock_file_for_test(ctx: *FileLockTestContext) void {
17851786 ctx.end_time = std.time.milliTimestamp();
17861787 file.close();
17871788}
1789
1790test "create file, lock and read from multiple process at once" {
1791 const filename = "file_read_lock_test.txt";
1792 const filedata = "Hello, world!\n";
1793
1794 try std.fs.cwd().writeFile(filename, filedata);
1795
1796 if (builtin.os.tag == .windows) {
1797 var ctxs = [_]FileLockTestContext{
1798 .{ .filename = filename },
1799 .{ .filename = filename },
1800 };
1801
1802 const threads = [_]*std.Thread{
1803 try std.Thread.spawn(&ctxs[0], lock_file_for_read_test),
1804 try std.Thread.spawn(&ctxs[1], lock_file_for_read_test),
1805 };
1806
1807 for (threads[0..]) |thread| {
1808 thread.wait();
1809 }
1810
1811 std.debug.assert(ctxs[0].overlaps(&ctxs[1]));
1812 std.debug.assert(ctxs[0].bytes_read.? == filedata.len);
1813 std.debug.assert(ctxs[1].bytes_read.? == filedata.len);
1814 } else {
1815 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);
1816 defer std.os.munmap(shared_mem);
1817 const ctxs = @ptrCast([*]FileLockTestContext, shared_mem.ptr);
1818
1819 const childpid = try std.os.fork();
1820 const ctx_idx: usize = if (childpid != 0) 0 else 1;
1821
1822 ctxs[ctx_idx].filename = filename;
1823 lock_file_for_read_test(&ctxs[ctx_idx]);
1824
1825 if (childpid != 0) {
1826 _ = std.os.waitpid(childpid, 0);
1827
1828 std.debug.assert(ctxs[0].overlaps(&ctxs[1]));
1829 std.debug.assert(ctxs[0].bytes_read.? == filedata.len);
1830 std.debug.assert(ctxs[1].bytes_read.? == filedata.len);
1831 }
1832 }
1833
1834 cwd().deleteFile(filename) catch |err| switch (err) {
1835 error.FileNotFound => {},
1836 else => return err,
1837 };
1838}
1839
1840fn lock_file_for_read_test(ctx: *FileLockTestContext) void {
1841 const file = cwd().openFile(ctx.filename, .{ .lock = true }) catch unreachable;
1842 ctx.start_time = std.time.milliTimestamp();
1843
1844 var buffer: [100]u8 = undefined;
1845 ctx.bytes_read = 0;
1846 while (true) {
1847 const amt = file.read(buffer[0..]) catch unreachable;
1848 if (amt == 0) break;
1849 ctx.bytes_read.? += amt;
1850 }
1851 std.time.sleep(FILE_LOCK_TEST_SLEEP_TIME);
1852
1853 ctx.end_time = std.time.milliTimestamp();
1854 file.close();
1855}