Commit 7ab77685a8
Changed files (1)
lib
std
lib/std/fs.zig
@@ -1723,51 +1723,59 @@ test "" {
const FILE_LOCK_TEST_SLEEP_TIME = 1 * std.time.ns_per_s;
-test "open file with lock twice, make sure it wasn't open at the same time" {
- const filename = "file_lock_test.txt";
-
- if (builtin.os.tag == .windows) {
- var ctxs = [_]FileLockTestContext{
- .{ .filename = filename },
- .{ .filename = filename },
- };
-
- const threads = [_]*std.Thread{
- try std.Thread.spawn(&ctxs[0], lock_file_for_test),
- try std.Thread.spawn(&ctxs[1], lock_file_for_test),
- };
-
- for (threads[0..]) |thread| {
- thread.wait();
- }
-
- std.debug.assert(!ctxs[0].overlaps(&ctxs[1]));
- } else {
- 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);
- defer std.os.munmap(shared_mem);
- const ctxs = @ptrCast([*]FileLockTestContext, shared_mem.ptr);
-
- const childpid = try std.os.fork();
- const ctx_idx: usize = if (childpid != 0) 0 else 1;
-
- ctxs[ctx_idx].filename = filename;
- lock_file_for_test(&ctxs[ctx_idx]);
-
- if (childpid != 0) {
- _ = std.os.waitpid(childpid, 0);
-
- std.debug.assert(!ctxs[0].overlaps(&ctxs[1]));
- }
- }
-
- cwd().deleteFile(filename) catch |err| switch (err) {
- error.FileNotFound => {},
- else => return err,
- };
-}
+//test "open file with lock twice, make sure it wasn't open at the same time" {
+// const filename = "file_lock_test.txt";
+//
+// if (builtin.os.tag == .windows) {
+// var ctxs = [_]FileLockTestContext{
+// .{ .filename = filename },
+// .{ .filename = filename },
+// };
+//
+// const threads = [_]*std.Thread{
+// try std.Thread.spawn(&ctxs[0], lock_file_for_test),
+// try std.Thread.spawn(&ctxs[1], lock_file_for_test),
+// };
+//
+// for (threads[0..]) |thread| {
+// thread.wait();
+// }
+//
+// std.debug.assert(!ctxs[0].overlaps(&ctxs[1]));
+// } else {
+// 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);
+// defer std.os.munmap(shared_mem);
+// const ctxs = @ptrCast([*]FileLockTestContext, shared_mem.ptr);
+//
+// const childpid = try std.os.fork();
+// const ctx_idx: usize = if (childpid != 0) 0 else 1;
+//
+// ctxs[ctx_idx].filename = filename;
+// lock_file_for_test(&ctxs[ctx_idx]);
+//
+// if (childpid != 0) {
+// _ = std.os.waitpid(childpid, 0);
+//
+// std.debug.assert(!ctxs[0].overlaps(&ctxs[1]));
+// } else {
+// std.os.exit(0);
+// }
+// }
+//
+// cwd().deleteFile(filename) catch |err| switch (err) {
+// error.FileNotFound => {},
+// else => return err,
+// };
+//}
const FileLockTestContext = struct {
filename: []const u8,
+ pid: if (builtin.os.tag == .windows) ?void else ?std.os.pid_t = null,
+
+ // use file.createFile
+ create: bool,
+ // get a read/write lock, instead of just a read lock
+ exclusive: bool,
// Output variables
start_time: u64 = 0,
@@ -1777,15 +1785,30 @@ const FileLockTestContext = struct {
fn overlaps(self: *const @This(), other: *const @This()) bool {
return (self.start_time < other.end_time) and (self.end_time > other.start_time);
}
-};
-fn lock_file_for_test(ctx: *FileLockTestContext) void {
- const file = cwd().createFile(ctx.filename, .{ .lock = true }) catch unreachable;
- ctx.start_time = std.time.milliTimestamp();
- std.time.sleep(FILE_LOCK_TEST_SLEEP_TIME);
- ctx.end_time = std.time.milliTimestamp();
- file.close();
-}
+ fn run(ctx: *@This()) void {
+ var file: File = undefined;
+ if (ctx.create) {
+ file = cwd().createFile(ctx.filename, .{ .lock = true }) catch unreachable;
+ } else {
+ file = cwd().openFile(ctx.filename, .{ .lock = true, .write = ctx.exclusive }) catch unreachable;
+ }
+
+ ctx.start_time = std.time.milliTimestamp();
+
+ var buffer: [100]u8 = undefined;
+ ctx.bytes_read = 0;
+ while (true) {
+ const amt = file.read(buffer[0..]) catch unreachable;
+ if (amt == 0) break;
+ ctx.bytes_read.? += amt;
+ }
+ std.time.sleep(FILE_LOCK_TEST_SLEEP_TIME);
+
+ ctx.end_time = std.time.milliTimestamp();
+ file.close();
+ }
+};
test "create file, lock and read from multiple process at once" {
const filename = "file_read_lock_test.txt";
@@ -1793,42 +1816,76 @@ test "create file, lock and read from multiple process at once" {
try std.fs.cwd().writeFile(filename, filedata);
+ const NUM_PROCESSES = 3;
+ var shared_mem: if (builtin.os.tag == .windows) [NUM_PROCESSES]FileLockTestContext else []align(mem.page_size) u8 = undefined;
+
+ var ctxs: []FileLockTestContext = undefined;
if (builtin.os.tag == .windows) {
- var ctxs = [_]FileLockTestContext{
- .{ .filename = filename },
- .{ .filename = filename },
- };
+ ctxs = shared_mem[0..NUM_PROCESSES];
+ } else {
+ 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);
+ const ctxs_ptr = @ptrCast([*]FileLockTestContext, shared_mem.ptr);
+ ctxs = ctxs_ptr[0..NUM_PROCESSES];
+ }
- const threads = [_]*std.Thread{
- try std.Thread.spawn(&ctxs[0], lock_file_for_read_test),
- try std.Thread.spawn(&ctxs[1], lock_file_for_read_test),
- };
+ ctxs[0] = .{
+ .filename = filename,
+ .create = false,
+ .exclusive = false,
+ };
+ ctxs[1] = .{
+ .filename = filename,
+ .create = false,
+ .exclusive = false,
+ };
+ ctxs[2] = .{
+ .filename = filename,
+ .create = false,
+ .exclusive = true,
+ };
+
+ if (builtin.os.tag == .windows) {
+ const threads: [NUM_PROCESSES]*std.Thread = undefined;
+ for (ctxs) |*ctx, idx| {
+ threads[idx] = try std.Thread.spawn(ctx, Context.run);
+ }
for (threads[0..]) |thread| {
thread.wait();
}
-
- std.debug.assert(ctxs[0].overlaps(&ctxs[1]));
- std.debug.assert(ctxs[0].bytes_read.? == filedata.len);
- std.debug.assert(ctxs[1].bytes_read.? == filedata.len);
} else {
- 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);
- defer std.os.munmap(shared_mem);
- const ctxs = @ptrCast([*]FileLockTestContext, shared_mem.ptr);
-
- const childpid = try std.os.fork();
- const ctx_idx: usize = if (childpid != 0) 0 else 1;
+ var ctx_opt: ?*FileLockTestContext = null;
+ for (ctxs) |*ctx| {
+ const childpid = try std.os.fork();
+ if (childpid == 0) {
+ ctx_opt = ctx;
+ break;
+ }
+ ctx.pid = childpid;
+ }
- ctxs[ctx_idx].filename = filename;
- lock_file_for_read_test(&ctxs[ctx_idx]);
+ if (ctx_opt) |ctx| {
+ ctx.run();
+ // Exit so we don't have duplicate test processes
+ std.os.exit(0);
+ } else {
+ for (ctxs) |ctx| {
+ _ = std.os.waitpid(ctx.pid.?, 0);
+ }
+ }
+ }
- if (childpid != 0) {
- _ = std.os.waitpid(childpid, 0);
+ std.debug.assert(ctxs[0].overlaps(&ctxs[1]));
+ std.debug.assert(!ctxs[2].overlaps(&ctxs[0]));
+ std.debug.assert(!ctxs[2].overlaps(&ctxs[1]));
+ if (ctxs[0].bytes_read.? != filedata.len) {
+ std.debug.warn("\n bytes_read: {}, expected: {} \n", .{ ctxs[0].bytes_read, filedata.len });
+ }
+ std.debug.assert(ctxs[0].bytes_read.? == filedata.len);
+ std.debug.assert(ctxs[1].bytes_read.? == filedata.len);
- std.debug.assert(ctxs[0].overlaps(&ctxs[1]));
- std.debug.assert(ctxs[0].bytes_read.? == filedata.len);
- std.debug.assert(ctxs[1].bytes_read.? == filedata.len);
- }
+ if (builtin.os.tag != .windows) {
+ std.os.munmap(shared_mem);
}
cwd().deleteFile(filename) catch |err| switch (err) {
@@ -1836,20 +1893,3 @@ test "create file, lock and read from multiple process at once" {
else => return err,
};
}
-
-fn lock_file_for_read_test(ctx: *FileLockTestContext) void {
- const file = cwd().openFile(ctx.filename, .{ .lock = true }) catch unreachable;
- ctx.start_time = std.time.milliTimestamp();
-
- var buffer: [100]u8 = undefined;
- ctx.bytes_read = 0;
- while (true) {
- const amt = file.read(buffer[0..]) catch unreachable;
- if (amt == 0) break;
- ctx.bytes_read.? += amt;
- }
- std.time.sleep(FILE_LOCK_TEST_SLEEP_TIME);
-
- ctx.end_time = std.time.milliTimestamp();
- file.close();
-}