authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-11-24 14:08:51+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-11-24 17:42:20+02:00
log20f5f5698600589b32f3c4af19e856b5faf578da
tree6b92238407377508a5bf2b63f56c39b9a1f21f54
parentab534cc9f16697da4846820b038e17fd1bc27f35
signaturelock-open Commit is signed but in an unrecognized format.

uncomment event.fs.watch


1 files changed, 590 insertions(+), 590 deletions(-)

lib/std/event/fs.zig+590-590
...@@ -720,602 +720,602 @@ fn hashString(s: []const u16) u32 {...@@ -720,602 +720,602 @@ fn hashString(s: []const u16) u32 {
720 return @truncate(u32, std.hash.Wyhash.hash(0, @sliceToBytes(s)));720 return @truncate(u32, std.hash.Wyhash.hash(0, @sliceToBytes(s)));
721}721}
722722
723//pub const WatchEventError = error{723pub const WatchEventError = error{
724// UserResourceLimitReached,724 UserResourceLimitReached,
725// SystemResources,725 SystemResources,
726// AccessDenied,726 AccessDenied,
727// Unexpected, // TODO remove this possibility727 Unexpected, // TODO remove this possibility
728//};728};
729//729
730//pub fn Watch(comptime V: type) type {730pub fn Watch(comptime V: type) type {
731// return struct {731 return struct {
732// channel: *event.Channel(Event.Error!Event),732 channel: *event.Channel(Event.Error!Event),
733// os_data: OsData,733 os_data: OsData,
734//734
735// const OsData = switch (builtin.os) {735 const OsData = switch (builtin.os) {
736// .macosx, .freebsd, .netbsd, .dragonfly => struct {736 .macosx, .freebsd, .netbsd, .dragonfly => struct {
737// file_table: FileTable,737 file_table: FileTable,
738// table_lock: event.Lock,738 table_lock: event.Lock,
739//739
740// const FileTable = std.StringHashmap(*Put);740 const FileTable = std.StringHashmap(*Put);
741// const Put = struct {741 const Put = struct {
742// putter: anyframe,742 putter: anyframe,
743// value_ptr: *V,743 value_ptr: *V,
744// };744 };
745// },745 },
746//746
747// .linux => LinuxOsData,747 .linux => LinuxOsData,
748// .windows => WindowsOsData,748 .windows => WindowsOsData,
749//749
750// else => @compileError("Unsupported OS"),750 else => @compileError("Unsupported OS"),
751// };751 };
752//752
753// const WindowsOsData = struct {753 const WindowsOsData = struct {
754// table_lock: event.Lock,754 table_lock: event.Lock,
755// dir_table: DirTable,755 dir_table: DirTable,
756// all_putters: std.atomic.Queue(anyframe),756 all_putters: std.atomic.Queue(anyframe),
757// ref_count: std.atomic.Int(usize),757 ref_count: std.atomic.Int(usize),
758//758
759// const DirTable = std.StringHashMap(*Dir);759 const DirTable = std.StringHashMap(*Dir);
760// const FileTable = std.HashMap([]const u16, V, hashString, eqlString);760 const FileTable = std.HashMap([]const u16, V, hashString, eqlString);
761//761
762// const Dir = struct {762 const Dir = struct {
763// putter: anyframe,763 putter: anyframe,
764// file_table: FileTable,764 file_table: FileTable,
765// table_lock: event.Lock,765 table_lock: event.Lock,
766// };766 };
767// };767 };
768//768
769// const LinuxOsData = struct {769 const LinuxOsData = struct {
770// putter: anyframe,770 putter: anyframe,
771// inotify_fd: i32,771 inotify_fd: i32,
772// wd_table: WdTable,772 wd_table: WdTable,
773// table_lock: event.Lock,773 table_lock: event.Lock,
774//774
775// const WdTable = std.AutoHashMap(i32, Dir);775 const WdTable = std.AutoHashMap(i32, Dir);
776// const FileTable = std.StringHashMap(V);776 const FileTable = std.StringHashMap(V);
777//777
778// const Dir = struct {778 const Dir = struct {
779// dirname: []const u8,779 dirname: []const u8,
780// file_table: FileTable,780 file_table: FileTable,
781// };781 };
782// };782 };
783//783
784// const FileToHandle = std.StringHashMap(anyframe);784 const FileToHandle = std.StringHashMap(anyframe);
785//785
786// const Self = @This();786 const Self = @This();
787//787
788// pub const Event = struct {788 pub const Event = struct {
789// id: Id,789 id: Id,
790// data: V,790 data: V,
791//791
792// pub const Id = WatchEventId;792 pub const Id = WatchEventId;
793// pub const Error = WatchEventError;793 pub const Error = WatchEventError;
794// };794 };
795//795
796// pub fn create(loop: *Loop, event_buf_count: usize) !*Self {796 pub fn create(loop: *Loop, event_buf_count: usize) !*Self {
797// const channel = try event.Channel(Self.Event.Error!Self.Event).create(loop, event_buf_count);797 const channel = try event.Channel(Self.Event.Error!Self.Event).create(loop, event_buf_count);
798// errdefer channel.destroy();798 errdefer channel.destroy();
799//799
800// switch (builtin.os) {800 switch (builtin.os) {
801// .linux => {801 .linux => {
802// const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);802 const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
803// errdefer os.close(inotify_fd);803 errdefer os.close(inotify_fd);
804//804
805// var result: *Self = undefined;805 var result: *Self = undefined;
806// _ = try async<loop.allocator> linuxEventPutter(inotify_fd, channel, &result);806// _ = try async<loop.allocator> linuxEventPutter(inotify_fd, channel, &result);
807// return result;807 return result;
808// },808 },
809//809
810// .windows => {810 .windows => {
811// const self = try loop.allocator.create(Self);811 const self = try loop.allocator.create(Self);
812// errdefer loop.allocator.destroy(self);812 errdefer loop.allocator.destroy(self);
813// self.* = Self{813 self.* = Self{
814// .channel = channel,814 .channel = channel,
815// .os_data = OsData{815 .os_data = OsData{
816// .table_lock = event.Lock.init(loop),816 .table_lock = event.Lock.init(loop),
817// .dir_table = OsData.DirTable.init(loop.allocator),817 .dir_table = OsData.DirTable.init(loop.allocator),
818// .ref_count = std.atomic.Int(usize).init(1),818 .ref_count = std.atomic.Int(usize).init(1),
819// .all_putters = std.atomic.Queue(anyframe).init(),819 .all_putters = std.atomic.Queue(anyframe).init(),
820// },820 },
821// };821 };
822// return self;822 return self;
823// },823 },
824//824
825// .macosx, .freebsd, .netbsd, .dragonfly => {825 .macosx, .freebsd, .netbsd, .dragonfly => {
826// const self = try loop.allocator.create(Self);826 const self = try loop.allocator.create(Self);
827// errdefer loop.allocator.destroy(self);827 errdefer loop.allocator.destroy(self);
828//828
829// self.* = Self{829 self.* = Self{
830// .channel = channel,830 .channel = channel,
831// .os_data = OsData{831 .os_data = OsData{
832// .table_lock = event.Lock.init(loop),832 .table_lock = event.Lock.init(loop),
833// .file_table = OsData.FileTable.init(loop.allocator),833 .file_table = OsData.FileTable.init(loop.allocator),
834// },834 },
835// };835 };
836// return self;836 return self;
837// },837 },
838// else => @compileError("Unsupported OS"),838 else => @compileError("Unsupported OS"),
839// }839 }
840// }840 }
841//841
842// /// All addFile calls and removeFile calls must have completed.842 /// All addFile calls and removeFile calls must have completed.
843// pub fn destroy(self: *Self) void {843 pub fn destroy(self: *Self) void {
844// switch (builtin.os) {844 switch (builtin.os) {
845// .macosx, .freebsd, .netbsd, .dragonfly => {845 .macosx, .freebsd, .netbsd, .dragonfly => {
846// // TODO we need to cancel the frames before destroying the lock846 // TODO we need to cancel the frames before destroying the lock
847// self.os_data.table_lock.deinit();847 self.os_data.table_lock.deinit();
848// var it = self.os_data.file_table.iterator();848 var it = self.os_data.file_table.iterator();
849// while (it.next()) |entry| {849 while (it.next()) |entry| {
850// cancel entry.value.putter;850// cancel entry.value.putter;
851// self.channel.loop.allocator.free(entry.key);851 self.channel.loop.allocator.free(entry.key);
852// }852 }
853// self.channel.destroy();853 self.channel.destroy();
854// },854 },
855// .linux => cancel self.os_data.putter,855// .linux => cancel self.os_data.putter,
856// .windows => {856 .windows => {
857// while (self.os_data.all_putters.get()) |putter_node| {857 while (self.os_data.all_putters.get()) |putter_node| {
858// cancel putter_node.data;858// cancel putter_node.data;
859// }859 }
860// self.deref();860 self.deref();
861// },861 },
862// else => @compileError("Unsupported OS"),862 else => @compileError("Unsupported OS"),
863// }863 }
864// }864 }
865//865
866// fn ref(self: *Self) void {866 fn ref(self: *Self) void {
867// _ = self.os_data.ref_count.incr();867 _ = self.os_data.ref_count.incr();
868// }868 }
869//869
870// fn deref(self: *Self) void {870 fn deref(self: *Self) void {
871// if (self.os_data.ref_count.decr() == 1) {871 if (self.os_data.ref_count.decr() == 1) {
872// const allocator = self.channel.loop.allocator;872 const allocator = self.channel.loop.allocator;
873// self.os_data.table_lock.deinit();873 self.os_data.table_lock.deinit();
874// var it = self.os_data.dir_table.iterator();874 var it = self.os_data.dir_table.iterator();
875// while (it.next()) |entry| {875 while (it.next()) |entry| {
876// allocator.free(entry.key);876 allocator.free(entry.key);
877// allocator.destroy(entry.value);877 allocator.destroy(entry.value);
878// }878 }
879// self.os_data.dir_table.deinit();879 self.os_data.dir_table.deinit();
880// self.channel.destroy();880 self.channel.destroy();
881// allocator.destroy(self);881 allocator.destroy(self);
882// }882 }
883// }883 }
884//884
885// pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {885 pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
886// switch (builtin.os) {886 switch (builtin.os) {
887// .macosx, .freebsd, .netbsd, .dragonfly => return await (async addFileKEvent(self, file_path, value) catch unreachable),887 .macosx, .freebsd, .netbsd, .dragonfly => return await (async addFileKEvent(self, file_path, value) catch unreachable),
888// .linux => return await (async addFileLinux(self, file_path, value) catch unreachable),888 .linux => return await (async addFileLinux(self, file_path, value) catch unreachable),
889// .windows => return await (async addFileWindows(self, file_path, value) catch unreachable),889 .windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
890// else => @compileError("Unsupported OS"),890 else => @compileError("Unsupported OS"),
891// }891 }
892// }892 }
893//893
894// async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {894 async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
895// const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [_][]const u8{file_path});895 const resolved_path = try std.fs.path.resolve(self.channel.loop.allocator, [_][]const u8{file_path});
896// var resolved_path_consumed = false;896 var resolved_path_consumed = false;
897// defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);897 defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
898//898
899// var close_op = try CloseOperation.start(self.channel.loop);899 var close_op = try CloseOperation.start(self.channel.loop);
900// var close_op_consumed = false;900 var close_op_consumed = false;
901// defer if (!close_op_consumed) close_op.finish();901 defer if (!close_op_consumed) close_op.finish();
902//902
903// const flags = if (comptime std.Target.current.isDarwin()) os.O_SYMLINK | os.O_EVTONLY else 0;903 const flags = if (comptime std.Target.current.isDarwin()) os.O_SYMLINK | os.O_EVTONLY else 0;
904// const mode = 0;904 const mode = 0;
905// const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);905 const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);
906// close_op.setHandle(fd);906 close_op.setHandle(fd);
907//907
908// var put_data: *OsData.Put = undefined;908 var put_data: *OsData.Put = undefined;
909// const putter = try async self.kqPutEvents(close_op, value, &put_data);909 const putter = try async self.kqPutEvents(close_op, value, &put_data);
910// close_op_consumed = true;910 close_op_consumed = true;
911// errdefer cancel putter;911// errdefer cancel putter;
912//912
913// const result = blk: {913 const result = blk: {
914// const held = await (async self.os_data.table_lock.acquire() catch unreachable);914 const held = await (async self.os_data.table_lock.acquire() catch unreachable);
915// defer held.release();915 defer held.release();
916//916
917// const gop = try self.os_data.file_table.getOrPut(resolved_path);917 const gop = try self.os_data.file_table.getOrPut(resolved_path);
918// if (gop.found_existing) {918 if (gop.found_existing) {
919// const prev_value = gop.kv.value.value_ptr.*;919 const prev_value = gop.kv.value.value_ptr.*;
920// cancel gop.kv.value.putter;920// cancel gop.kv.value.putter;
921// gop.kv.value = put_data;921 gop.kv.value = put_data;
922// break :blk prev_value;922 break :blk prev_value;
923// } else {923 } else {
924// resolved_path_consumed = true;924 resolved_path_consumed = true;
925// gop.kv.value = put_data;925 gop.kv.value = put_data;
926// break :blk null;926 break :blk null;
927// }927 }
928// };928 };
929//929
930// return result;930 return result;
931// }931 }
932//932
933// async fn kqPutEvents(self: *Self, close_op: *CloseOperation, value: V, out_put: **OsData.Put) void {933 async fn kqPutEvents(self: *Self, close_op: *CloseOperation, value: V, out_put: **OsData.Put) void {
934// var value_copy = value;934 var value_copy = value;
935// var put = OsData.Put{935 var put = OsData.Put{
936// .putter = @frame(),936 .putter = @frame(),
937// .value_ptr = &value_copy,937 .value_ptr = &value_copy,
938// };938 };
939// out_put.* = &put;939 out_put.* = &put;
940// self.channel.loop.beginOneEvent();940 self.channel.loop.beginOneEvent();
941//941
942// defer {942 defer {
943// close_op.finish();943 close_op.finish();
944// self.channel.loop.finishOneEvent();944 self.channel.loop.finishOneEvent();
945// }945 }
946//946
947// while (true) {947 while (true) {
948// if (await (async self.channel.loop.bsdWaitKev(948 if (await (async self.channel.loop.bsdWaitKev(
949// @intCast(usize, close_op.getHandle()),949 @intCast(usize, close_op.getHandle()),
950// os.EVFILT_VNODE,950 os.EVFILT_VNODE,
951// os.NOTE_WRITE | os.NOTE_DELETE,951 os.NOTE_WRITE | os.NOTE_DELETE,
952// ) catch unreachable)) |kev| {952 ) catch unreachable)) |kev| {
953// // TODO handle EV_ERROR953 // TODO handle EV_ERROR
954// if (kev.fflags & os.NOTE_DELETE != 0) {954 if (kev.fflags & os.NOTE_DELETE != 0) {
955// await (async self.channel.put(Self.Event{955 await (async self.channel.put(Self.Event{
956// .id = Event.Id.Delete,956 .id = Event.Id.Delete,
957// .data = value_copy,957 .data = value_copy,
958// }) catch unreachable);958 }) catch unreachable);
959// } else if (kev.fflags & os.NOTE_WRITE != 0) {959 } else if (kev.fflags & os.NOTE_WRITE != 0) {
960// await (async self.channel.put(Self.Event{960 await (async self.channel.put(Self.Event{
961// .id = Event.Id.CloseWrite,961 .id = Event.Id.CloseWrite,
962// .data = value_copy,962 .data = value_copy,
963// }) catch unreachable);963 }) catch unreachable);
964// }964 }
965// } else |err| switch (err) {965 } else |err| switch (err) {
966// error.EventNotFound => unreachable,966 error.EventNotFound => unreachable,
967// error.ProcessNotFound => unreachable,967 error.ProcessNotFound => unreachable,
968// error.Overflow => unreachable,968 error.Overflow => unreachable,
969// error.AccessDenied, error.SystemResources => |casted_err| {969 error.AccessDenied, error.SystemResources => |casted_err| {
970// await (async self.channel.put(casted_err) catch unreachable);970 await (async self.channel.put(casted_err) catch unreachable);
971// },971 },
972// }972 }
973// }973 }
974// }974 }
975//975
976// async fn addFileLinux(self: *Self, file_path: []const u8, value: V) !?V {976 async fn addFileLinux(self: *Self, file_path: []const u8, value: V) !?V {
977// const value_copy = value;977 const value_copy = value;
978//978
979// const dirname = std.fs.path.dirname(file_path) orelse ".";979 const dirname = std.fs.path.dirname(file_path) orelse ".";
980// const dirname_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, dirname);980 const dirname_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, dirname);
981// var dirname_with_null_consumed = false;981 var dirname_with_null_consumed = false;
982// defer if (!dirname_with_null_consumed) self.channel.loop.allocator.free(dirname_with_null);982 defer if (!dirname_with_null_consumed) self.channel.loop.allocator.free(dirname_with_null);
983//983
984// const basename = std.fs.path.basename(file_path);984 const basename = std.fs.path.basename(file_path);
985// const basename_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, basename);985 const basename_with_null = try std.cstr.addNullByte(self.channel.loop.allocator, basename);
986// var basename_with_null_consumed = false;986 var basename_with_null_consumed = false;
987// defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null);987 defer if (!basename_with_null_consumed) self.channel.loop.allocator.free(basename_with_null);
988//988
989// const wd = try os.inotify_add_watchC(989 const wd = try os.inotify_add_watchC(
990// self.os_data.inotify_fd,990 self.os_data.inotify_fd,
991// dirname_with_null.ptr,991 dirname_with_null.ptr,
992// os.linux.IN_CLOSE_WRITE | os.linux.IN_ONLYDIR | os.linux.IN_EXCL_UNLINK,992 os.linux.IN_CLOSE_WRITE | os.linux.IN_ONLYDIR | os.linux.IN_EXCL_UNLINK,
993// );993 );
994// // wd is either a newly created watch or an existing one.994 // wd is either a newly created watch or an existing one.
995//995
996// const held = await (async self.os_data.table_lock.acquire() catch unreachable);996 const held = await (async self.os_data.table_lock.acquire() catch unreachable);
997// defer held.release();997 defer held.release();
998//998
999// const gop = try self.os_data.wd_table.getOrPut(wd);999 const gop = try self.os_data.wd_table.getOrPut(wd);
1000// if (!gop.found_existing) {1000 if (!gop.found_existing) {
1001// gop.kv.value = OsData.Dir{1001 gop.kv.value = OsData.Dir{
1002// .dirname = dirname_with_null,1002 .dirname = dirname_with_null,
1003// .file_table = OsData.FileTable.init(self.channel.loop.allocator),1003 .file_table = OsData.FileTable.init(self.channel.loop.allocator),
1004// };1004 };
1005// dirname_with_null_consumed = true;1005 dirname_with_null_consumed = true;
1006// }1006 }
1007// const dir = &gop.kv.value;1007 const dir = &gop.kv.value;
1008//1008
1009// const file_table_gop = try dir.file_table.getOrPut(basename_with_null);1009 const file_table_gop = try dir.file_table.getOrPut(basename_with_null);
1010// if (file_table_gop.found_existing) {1010 if (file_table_gop.found_existing) {
1011// const prev_value = file_table_gop.kv.value;1011 const prev_value = file_table_gop.kv.value;
1012// file_table_gop.kv.value = value_copy;1012 file_table_gop.kv.value = value_copy;
1013// return prev_value;1013 return prev_value;
1014// } else {1014 } else {
1015// file_table_gop.kv.value = value_copy;1015 file_table_gop.kv.value = value_copy;
1016// basename_with_null_consumed = true;1016 basename_with_null_consumed = true;
1017// return null;1017 return null;
1018// }1018 }
1019// }1019 }
1020//1020
1021// async fn addFileWindows(self: *Self, file_path: []const u8, value: V) !?V {1021 async fn addFileWindows(self: *Self, file_path: []const u8, value: V) !?V {
1022// const value_copy = value;1022 const value_copy = value;
1023// // TODO we might need to convert dirname and basename to canonical file paths ("short"?)1023 // TODO we might need to convert dirname and basename to canonical file paths ("short"?)
1024//1024
1025// const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, std.fs.path.dirname(file_path) orelse ".");1025 const dirname = try std.mem.dupe(self.channel.loop.allocator, u8, std.fs.path.dirname(file_path) orelse ".");
1026// var dirname_consumed = false;1026 var dirname_consumed = false;
1027// defer if (!dirname_consumed) self.channel.loop.allocator.free(dirname);1027 defer if (!dirname_consumed) self.channel.loop.allocator.free(dirname);
1028//1028
1029// const dirname_utf16le = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, dirname);1029 const dirname_utf16le = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, dirname);
1030// defer self.channel.loop.allocator.free(dirname_utf16le);1030 defer self.channel.loop.allocator.free(dirname_utf16le);
1031//1031
1032// // TODO https://github.com/ziglang/zig/issues/2651032 // TODO https://github.com/ziglang/zig/issues/265
1033// const basename = std.fs.path.basename(file_path);1033 const basename = std.fs.path.basename(file_path);
1034// const basename_utf16le_null = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, basename);1034 const basename_utf16le_null = try std.unicode.utf8ToUtf16LeWithNull(self.channel.loop.allocator, basename);
1035// var basename_utf16le_null_consumed = false;1035 var basename_utf16le_null_consumed = false;
1036// defer if (!basename_utf16le_null_consumed) self.channel.loop.allocator.free(basename_utf16le_null);1036 defer if (!basename_utf16le_null_consumed) self.channel.loop.allocator.free(basename_utf16le_null);
1037// const basename_utf16le_no_null = basename_utf16le_null[0 .. basename_utf16le_null.len - 1];1037 const basename_utf16le_no_null = basename_utf16le_null[0 .. basename_utf16le_null.len - 1];
1038//1038
1039// const dir_handle = try windows.CreateFileW(1039 const dir_handle = try windows.CreateFileW(
1040// dirname_utf16le.ptr,1040 dirname_utf16le.ptr,
1041// windows.FILE_LIST_DIRECTORY,1041 windows.FILE_LIST_DIRECTORY,
1042// windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE | windows.FILE_SHARE_WRITE,1042 windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE | windows.FILE_SHARE_WRITE,
1043// null,1043 null,
1044// windows.OPEN_EXISTING,1044 windows.OPEN_EXISTING,
1045// windows.FILE_FLAG_BACKUP_SEMANTICS | windows.FILE_FLAG_OVERLAPPED,1045 windows.FILE_FLAG_BACKUP_SEMANTICS | windows.FILE_FLAG_OVERLAPPED,
1046// null,1046 null,
1047// );1047 );
1048// var dir_handle_consumed = false;1048 var dir_handle_consumed = false;
1049// defer if (!dir_handle_consumed) windows.CloseHandle(dir_handle);1049 defer if (!dir_handle_consumed) windows.CloseHandle(dir_handle);
1050//1050
1051// const held = await (async self.os_data.table_lock.acquire() catch unreachable);1051 const held = await (async self.os_data.table_lock.acquire() catch unreachable);
1052// defer held.release();1052 defer held.release();
1053//1053
1054// const gop = try self.os_data.dir_table.getOrPut(dirname);1054 const gop = try self.os_data.dir_table.getOrPut(dirname);
1055// if (gop.found_existing) {1055 if (gop.found_existing) {
1056// const dir = gop.kv.value;1056 const dir = gop.kv.value;
1057// const held_dir_lock = await (async dir.table_lock.acquire() catch unreachable);1057 const held_dir_lock = await (async dir.table_lock.acquire() catch unreachable);
1058// defer held_dir_lock.release();1058 defer held_dir_lock.release();
1059//1059
1060// const file_gop = try dir.file_table.getOrPut(basename_utf16le_no_null);1060 const file_gop = try dir.file_table.getOrPut(basename_utf16le_no_null);
1061// if (file_gop.found_existing) {1061 if (file_gop.found_existing) {
1062// const prev_value = file_gop.kv.value;1062 const prev_value = file_gop.kv.value;
1063// file_gop.kv.value = value_copy;1063 file_gop.kv.value = value_copy;
1064// return prev_value;1064 return prev_value;
1065// } else {1065 } else {
1066// file_gop.kv.value = value_copy;1066 file_gop.kv.value = value_copy;
1067// basename_utf16le_null_consumed = true;1067 basename_utf16le_null_consumed = true;
1068// return null;1068 return null;
1069// }1069 }
1070// } else {1070 } else {
1071// errdefer _ = self.os_data.dir_table.remove(dirname);1071 errdefer _ = self.os_data.dir_table.remove(dirname);
1072// const dir = try self.channel.loop.allocator.create(OsData.Dir);1072 const dir = try self.channel.loop.allocator.create(OsData.Dir);
1073// errdefer self.channel.loop.allocator.destroy(dir);1073 errdefer self.channel.loop.allocator.destroy(dir);
1074//1074
1075// dir.* = OsData.Dir{1075 dir.* = OsData.Dir{
1076// .file_table = OsData.FileTable.init(self.channel.loop.allocator),1076 .file_table = OsData.FileTable.init(self.channel.loop.allocator),
1077// .table_lock = event.Lock.init(self.channel.loop),1077 .table_lock = event.Lock.init(self.channel.loop),
1078// .putter = undefined,1078 .putter = undefined,
1079// };1079 };
1080// gop.kv.value = dir;1080 gop.kv.value = dir;
1081// assert((try dir.file_table.put(basename_utf16le_no_null, value_copy)) == null);1081 assert((try dir.file_table.put(basename_utf16le_no_null, value_copy)) == null);
1082// basename_utf16le_null_consumed = true;1082 basename_utf16le_null_consumed = true;
1083//1083
1084// dir.putter = try async self.windowsDirReader(dir_handle, dir);1084 dir.putter = try async self.windowsDirReader(dir_handle, dir);
1085// dir_handle_consumed = true;1085 dir_handle_consumed = true;
1086//1086
1087// dirname_consumed = true;1087 dirname_consumed = true;
1088//1088
1089// return null;1089 return null;
1090// }1090 }
1091// }1091 }
1092//1092
1093// async fn windowsDirReader(self: *Self, dir_handle: windows.HANDLE, dir: *OsData.Dir) void {1093 async fn windowsDirReader(self: *Self, dir_handle: windows.HANDLE, dir: *OsData.Dir) void {
1094// self.ref();1094 self.ref();
1095// defer self.deref();1095 defer self.deref();
1096//1096
1097// defer os.close(dir_handle);1097 defer os.close(dir_handle);
1098//1098
1099// var putter_node = std.atomic.Queue(anyframe).Node{1099 var putter_node = std.atomic.Queue(anyframe).Node{
1100// .data = @frame(),1100 .data = @frame(),
1101// .prev = null,1101 .prev = null,
1102// .next = null,1102 .next = null,
1103// };1103 };
1104// self.os_data.all_putters.put(&putter_node);1104 self.os_data.all_putters.put(&putter_node);
1105// defer _ = self.os_data.all_putters.remove(&putter_node);1105 defer _ = self.os_data.all_putters.remove(&putter_node);
1106//1106
1107// var resume_node = Loop.ResumeNode.Basic{1107 var resume_node = Loop.ResumeNode.Basic{
1108// .base = Loop.ResumeNode{1108 .base = Loop.ResumeNode{
1109// .id = Loop.ResumeNode.Id.Basic,1109 .id = Loop.ResumeNode.Id.Basic,
1110// .handle = @frame(),1110 .handle = @frame(),
1111// .overlapped = windows.OVERLAPPED{1111 .overlapped = windows.OVERLAPPED{
1112// .Internal = 0,1112 .Internal = 0,
1113// .InternalHigh = 0,1113 .InternalHigh = 0,
1114// .Offset = 0,1114 .Offset = 0,
1115// .OffsetHigh = 0,1115 .OffsetHigh = 0,
1116// .hEvent = null,1116 .hEvent = null,
1117// },1117 },
1118// },1118 },
1119// };1119 };
1120// var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;1120 var event_buf: [4096]u8 align(@alignOf(windows.FILE_NOTIFY_INFORMATION)) = undefined;
1121//1121
1122// // TODO handle this error not in the channel but in the setup1122 // TODO handle this error not in the channel but in the setup
1123// _ = windows.CreateIoCompletionPort(1123 _ = windows.CreateIoCompletionPort(
1124// dir_handle,1124 dir_handle,
1125// self.channel.loop.os_data.io_port,1125 self.channel.loop.os_data.io_port,
1126// undefined,1126 undefined,
1127// undefined,1127 undefined,
1128// ) catch |err| {1128 ) catch |err| {
1129// await (async self.channel.put(err) catch unreachable);1129 await (async self.channel.put(err) catch unreachable);
1130// return;1130 return;
1131// };1131 };
1132//1132
1133// while (true) {1133 while (true) {
1134// {1134 {
1135// // TODO only 1 beginOneEvent for the whole function1135 // TODO only 1 beginOneEvent for the whole function
1136// self.channel.loop.beginOneEvent();1136 self.channel.loop.beginOneEvent();
1137// errdefer self.channel.loop.finishOneEvent();1137 errdefer self.channel.loop.finishOneEvent();
1138// errdefer {1138 errdefer {
1139// _ = windows.kernel32.CancelIoEx(dir_handle, &resume_node.base.overlapped);1139 _ = windows.kernel32.CancelIoEx(dir_handle, &resume_node.base.overlapped);
1140// }1140 }
1141// suspend {1141 suspend {
1142// _ = windows.kernel32.ReadDirectoryChangesW(1142 _ = windows.kernel32.ReadDirectoryChangesW(
1143// dir_handle,1143 dir_handle,
1144// &event_buf,1144 &event_buf,
1145// @intCast(windows.DWORD, event_buf.len),1145 @intCast(windows.DWORD, event_buf.len),
1146// windows.FALSE, // watch subtree1146 windows.FALSE, // watch subtree
1147// windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME |1147 windows.FILE_NOTIFY_CHANGE_FILE_NAME | windows.FILE_NOTIFY_CHANGE_DIR_NAME |
1148// windows.FILE_NOTIFY_CHANGE_ATTRIBUTES | windows.FILE_NOTIFY_CHANGE_SIZE |1148 windows.FILE_NOTIFY_CHANGE_ATTRIBUTES | windows.FILE_NOTIFY_CHANGE_SIZE |
1149// windows.FILE_NOTIFY_CHANGE_LAST_WRITE | windows.FILE_NOTIFY_CHANGE_LAST_ACCESS |1149 windows.FILE_NOTIFY_CHANGE_LAST_WRITE | windows.FILE_NOTIFY_CHANGE_LAST_ACCESS |
1150// windows.FILE_NOTIFY_CHANGE_CREATION | windows.FILE_NOTIFY_CHANGE_SECURITY,1150 windows.FILE_NOTIFY_CHANGE_CREATION | windows.FILE_NOTIFY_CHANGE_SECURITY,
1151// null, // number of bytes transferred (unused for async)1151 null, // number of bytes transferred (unused for async)
1152// &resume_node.base.overlapped,1152 &resume_node.base.overlapped,
1153// null, // completion routine - unused because we use IOCP1153 null, // completion routine - unused because we use IOCP
1154// );1154 );
1155// }1155 }
1156// }1156 }
1157// var bytes_transferred: windows.DWORD = undefined;1157 var bytes_transferred: windows.DWORD = undefined;
1158// if (windows.kernel32.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {1158 if (windows.kernel32.GetOverlappedResult(dir_handle, &resume_node.base.overlapped, &bytes_transferred, windows.FALSE) == 0) {
1159// const err = switch (windows.kernel32.GetLastError()) {1159 const err = switch (windows.kernel32.GetLastError()) {
1160// else => |err| windows.unexpectedError(err),1160 else => |err| windows.unexpectedError(err),
1161// };1161 };
1162// await (async self.channel.put(err) catch unreachable);1162 await (async self.channel.put(err) catch unreachable);
1163// } else {1163 } else {
1164// // can't use @bytesToSlice because of the special variable length name field1164 // can't use @bytesToSlice because of the special variable length name field
1165// var ptr = event_buf[0..].ptr;1165 var ptr = event_buf[0..].ptr;
1166// const end_ptr = ptr + bytes_transferred;1166 const end_ptr = ptr + bytes_transferred;
1167// var ev: *windows.FILE_NOTIFY_INFORMATION = undefined;1167 var ev: *windows.FILE_NOTIFY_INFORMATION = undefined;
1168// while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += ev.NextEntryOffset) {1168 while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += ev.NextEntryOffset) {
1169// ev = @ptrCast(*windows.FILE_NOTIFY_INFORMATION, ptr);1169 ev = @ptrCast(*windows.FILE_NOTIFY_INFORMATION, ptr);
1170// const emit = switch (ev.Action) {1170 const emit = switch (ev.Action) {
1171// windows.FILE_ACTION_REMOVED => WatchEventId.Delete,1171 windows.FILE_ACTION_REMOVED => WatchEventId.Delete,
1172// windows.FILE_ACTION_MODIFIED => WatchEventId.CloseWrite,1172 windows.FILE_ACTION_MODIFIED => WatchEventId.CloseWrite,
1173// else => null,1173 else => null,
1174// };1174 };
1175// if (emit) |id| {1175 if (emit) |id| {
1176// const basename_utf16le = ([*]u16)(&ev.FileName)[0 .. ev.FileNameLength / 2];1176 const basename_utf16le = ([*]u16)(&ev.FileName)[0 .. ev.FileNameLength / 2];
1177// const user_value = blk: {1177 const user_value = blk: {
1178// const held = await (async dir.table_lock.acquire() catch unreachable);1178 const held = await (async dir.table_lock.acquire() catch unreachable);
1179// defer held.release();1179 defer held.release();
1180//1180
1181// if (dir.file_table.get(basename_utf16le)) |entry| {1181 if (dir.file_table.get(basename_utf16le)) |entry| {
1182// break :blk entry.value;1182 break :blk entry.value;
1183// } else {1183 } else {
1184// break :blk null;1184 break :blk null;
1185// }1185 }
1186// };1186 };
1187// if (user_value) |v| {1187 if (user_value) |v| {
1188// await (async self.channel.put(Event{1188 await (async self.channel.put(Event{
1189// .id = id,1189 .id = id,
1190// .data = v,1190 .data = v,
1191// }) catch unreachable);1191 }) catch unreachable);
1192// }1192 }
1193// }1193 }
1194// if (ev.NextEntryOffset == 0) break;1194 if (ev.NextEntryOffset == 0) break;
1195// }1195 }
1196// }1196 }
1197// }1197 }
1198// }1198 }
1199//1199
1200// pub async fn removeFile(self: *Self, file_path: []const u8) ?V {1200 pub async fn removeFile(self: *Self, file_path: []const u8) ?V {
1201// @panic("TODO");1201 @panic("TODO");
1202// }1202 }
1203//1203
1204// async fn linuxEventPutter(inotify_fd: i32, channel: *event.Channel(Event.Error!Event), out_watch: **Self) void {1204 async fn linuxEventPutter(inotify_fd: i32, channel: *event.Channel(Event.Error!Event), out_watch: **Self) void {
1205// const loop = channel.loop;1205 const loop = channel.loop;
1206//1206
1207// var watch = Self{1207 var watch = Self{
1208// .channel = channel,1208 .channel = channel,
1209// .os_data = OsData{1209 .os_data = OsData{
1210// .putter = @frame(),1210 .putter = @frame(),
1211// .inotify_fd = inotify_fd,1211 .inotify_fd = inotify_fd,
1212// .wd_table = OsData.WdTable.init(loop.allocator),1212 .wd_table = OsData.WdTable.init(loop.allocator),
1213// .table_lock = event.Lock.init(loop),1213 .table_lock = event.Lock.init(loop),
1214// },1214 },
1215// };1215 };
1216// out_watch.* = &watch;1216 out_watch.* = &watch;
1217//1217
1218// loop.beginOneEvent();1218 loop.beginOneEvent();
1219//1219
1220// defer {1220 defer {
1221// watch.os_data.table_lock.deinit();1221 watch.os_data.table_lock.deinit();
1222// var wd_it = watch.os_data.wd_table.iterator();1222 var wd_it = watch.os_data.wd_table.iterator();
1223// while (wd_it.next()) |wd_entry| {1223 while (wd_it.next()) |wd_entry| {
1224// var file_it = wd_entry.value.file_table.iterator();1224 var file_it = wd_entry.value.file_table.iterator();
1225// while (file_it.next()) |file_entry| {1225 while (file_it.next()) |file_entry| {
1226// loop.allocator.free(file_entry.key);1226 loop.allocator.free(file_entry.key);
1227// }1227 }
1228// loop.allocator.free(wd_entry.value.dirname);1228 loop.allocator.free(wd_entry.value.dirname);
1229// }1229 }
1230// loop.finishOneEvent();1230 loop.finishOneEvent();
1231// os.close(inotify_fd);1231 os.close(inotify_fd);
1232// channel.destroy();1232 channel.destroy();
1233// }1233 }
1234//1234
1235// var event_buf: [4096]u8 align(@alignOf(os.linux.inotify_event)) = undefined;1235 var event_buf: [4096]u8 align(@alignOf(os.linux.inotify_event)) = undefined;
1236//1236
1237// while (true) {1237 while (true) {
1238// const rc = os.linux.read(inotify_fd, &event_buf, event_buf.len);1238 const rc = os.linux.read(inotify_fd, &event_buf, event_buf.len);
1239// const errno = os.linux.getErrno(rc);1239 const errno = os.linux.getErrno(rc);
1240// switch (errno) {1240 switch (errno) {
1241// 0 => {1241 0 => {
1242// // can't use @bytesToSlice because of the special variable length name field1242 // can't use @bytesToSlice because of the special variable length name field
1243// var ptr = event_buf[0..].ptr;1243 var ptr = event_buf[0..].ptr;
1244// const end_ptr = ptr + event_buf.len;1244 const end_ptr = ptr + event_buf.len;
1245// var ev: *os.linux.inotify_event = undefined;1245 var ev: *os.linux.inotify_event = undefined;
1246// while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += @sizeOf(os.linux.inotify_event) + ev.len) {1246 while (@ptrToInt(ptr) < @ptrToInt(end_ptr)) : (ptr += @sizeOf(os.linux.inotify_event) + ev.len) {
1247// ev = @ptrCast(*os.linux.inotify_event, ptr);1247 ev = @ptrCast(*os.linux.inotify_event, ptr);
1248// if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) {1248 if (ev.mask & os.linux.IN_CLOSE_WRITE == os.linux.IN_CLOSE_WRITE) {
1249// const basename_ptr = ptr + @sizeOf(os.linux.inotify_event);1249 const basename_ptr = ptr + @sizeOf(os.linux.inotify_event);
1250// const basename_with_null = basename_ptr[0 .. std.mem.len(u8, basename_ptr) + 1];1250 const basename_with_null = basename_ptr[0 .. std.mem.len(u8, basename_ptr) + 1];
1251// const user_value = blk: {1251 const user_value = blk: {
1252// const held = await (async watch.os_data.table_lock.acquire() catch unreachable);1252 const held = await (async watch.os_data.table_lock.acquire() catch unreachable);
1253// defer held.release();1253 defer held.release();
1254//1254
1255// const dir = &watch.os_data.wd_table.get(ev.wd).?.value;1255 const dir = &watch.os_data.wd_table.get(ev.wd).?.value;
1256// if (dir.file_table.get(basename_with_null)) |entry| {1256 if (dir.file_table.get(basename_with_null)) |entry| {
1257// break :blk entry.value;1257 break :blk entry.value;
1258// } else {1258 } else {
1259// break :blk null;1259 break :blk null;
1260// }1260 }
1261// };1261 };
1262// if (user_value) |v| {1262 if (user_value) |v| {
1263// await (async channel.put(Event{1263 await (async channel.put(Event{
1264// .id = WatchEventId.CloseWrite,1264 .id = WatchEventId.CloseWrite,
1265// .data = v,1265 .data = v,
1266// }) catch unreachable);1266 }) catch unreachable);
1267// }1267 }
1268// }1268 }
1269// }1269 }
1270// },1270 },
1271// os.linux.EINTR => continue,1271 os.linux.EINTR => continue,
1272// os.linux.EINVAL => unreachable,1272 os.linux.EINVAL => unreachable,
1273// os.linux.EFAULT => unreachable,1273 os.linux.EFAULT => unreachable,
1274// os.linux.EAGAIN => {1274 os.linux.EAGAIN => {
1275// (await (async loop.linuxWaitFd(1275 (await (async loop.linuxWaitFd(
1276// inotify_fd,1276 inotify_fd,
1277// os.linux.EPOLLET | os.linux.EPOLLIN,1277 os.linux.EPOLLET | os.linux.EPOLLIN,
1278// ) catch unreachable)) catch |err| {1278 ) catch unreachable)) catch |err| {
1279// const transformed_err = switch (err) {1279 const transformed_err = switch (err) {
1280// error.FileDescriptorAlreadyPresentInSet => unreachable,1280 error.FileDescriptorAlreadyPresentInSet => unreachable,
1281// error.OperationCausesCircularLoop => unreachable,1281 error.OperationCausesCircularLoop => unreachable,
1282// error.FileDescriptorNotRegistered => unreachable,1282 error.FileDescriptorNotRegistered => unreachable,
1283// error.FileDescriptorIncompatibleWithEpoll => unreachable,1283 error.FileDescriptorIncompatibleWithEpoll => unreachable,
1284// error.Unexpected => unreachable,1284 error.Unexpected => unreachable,
1285// else => |e| e,1285 else => |e| e,
1286// };1286 };
1287// await (async channel.put(transformed_err) catch unreachable);1287 await (async channel.put(transformed_err) catch unreachable);
1288// };1288 };
1289// },1289 },
1290// else => unreachable,1290 else => unreachable,
1291// }1291 }
1292// }1292 }
1293// }1293 }
1294// };1294 };
1295//}1295}
12961296
1297const test_tmp_dir = "std_event_fs_test";1297const test_tmp_dir = "std_event_fs_test";
12981298
1299// TODO this test is disabled until the async function rewrite is finished.1299// TODO this test is disabled until the async function rewrite is finished.
1300//test "write a file, watch it, write it again" {1300test "write a file, watch it, write it again" {
1301// return error.SkipZigTest;1301 return error.SkipZigTest;
1302// const allocator = std.heap.direct_allocator;1302 const allocator = std.heap.direct_allocator;
1303//1303
1304// // TODO move this into event loop too1304 // TODO move this into event loop too
1305// try os.makePath(allocator, test_tmp_dir);1305 try os.makePath(allocator, test_tmp_dir);
1306// defer os.deleteTree(test_tmp_dir) catch {};1306 defer os.deleteTree(test_tmp_dir) catch {};
1307//1307
1308// var loop: Loop = undefined;1308 var loop: Loop = undefined;
1309// try loop.initMultiThreaded(allocator);1309 try loop.initMultiThreaded(allocator);
1310// defer loop.deinit();1310 defer loop.deinit();
1311//1311
1312// var result: anyerror!void = error.ResultNeverWritten;1312 var result: anyerror!void = error.ResultNeverWritten;
1313// const handle = try async<allocator> testFsWatchCantFail(&loop, &result);1313// const handle = try async<allocator> testFsWatchCantFail(&loop, &result);
1314// defer cancel handle;1314// defer cancel handle;
1315//1315
1316// loop.run();1316 loop.run();
1317// return result;1317 return result;
1318//}1318}
13191319
1320fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void {1320fn testFsWatchCantFail(loop: *Loop, result: *(anyerror!void)) void {
1321 result.* = testFsWatch(loop);1321 result.* = testFsWatch(loop);