authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-02 00:41:19-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-02 00:41:19-04:00
log2272a07ca0661547a6889aa7f1b6262fef5dad85
treec8e093b7c72ac3e1fc2e62931167294941becc7a
parent45bce27b8fecda4fba1c22dd191030af29ccbc6f

std.event.Loop: promote the fs thread to be available for all OS's


6 files changed, 137 insertions(+), 193 deletions(-)

lib/std/debug.zig+48-42
......@@ -112,39 +112,43 @@ pub fn detectTTYConfig() TTY.Config {
112112/// Tries to print the current stack trace to stderr, unbuffered, and ignores any error returned.
113113/// TODO multithreaded awareness
114114pub fn dumpCurrentStackTrace(start_addr: ?usize) void {
115 const stderr = getStderrStream();
116 if (builtin.strip_debug_info) {
117 noasync stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
118 return;
115 noasync {
116 const stderr = getStderrStream();
117 if (builtin.strip_debug_info) {
118 stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
119 return;
120 }
121 const debug_info = getSelfDebugInfo() catch |err| {
122 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
123 return;
124 };
125 writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(), start_addr) catch |err| {
126 stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;
127 return;
128 };
119129 }
120 const debug_info = getSelfDebugInfo() catch |err| {
121 noasync stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
122 return;
123 };
124 writeCurrentStackTrace(stderr, debug_info, detectTTYConfig(), start_addr) catch |err| {
125 noasync stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;
126 return;
127 };
128130}
129131
130132/// Tries to print the stack trace starting from the supplied base pointer to stderr,
131133/// unbuffered, and ignores any error returned.
132134/// TODO multithreaded awareness
133135pub fn dumpStackTraceFromBase(bp: usize, ip: usize) void {
134 const stderr = getStderrStream();
135 if (builtin.strip_debug_info) {
136 noasync stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
137 return;
138 }
139 const debug_info = getSelfDebugInfo() catch |err| {
140 noasync stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
141 return;
142 };
143 const tty_config = detectTTYConfig();
144 printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return;
145 var it = StackIterator.init(null, bp);
146 while (it.next()) |return_address| {
147 printSourceAtAddress(debug_info, stderr, return_address - 1, tty_config) catch return;
136 noasync {
137 const stderr = getStderrStream();
138 if (builtin.strip_debug_info) {
139 stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
140 return;
141 }
142 const debug_info = getSelfDebugInfo() catch |err| {
143 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
144 return;
145 };
146 const tty_config = detectTTYConfig();
147 printSourceAtAddress(debug_info, stderr, ip, tty_config) catch return;
148 var it = StackIterator.init(null, bp);
149 while (it.next()) |return_address| {
150 printSourceAtAddress(debug_info, stderr, return_address - 1, tty_config) catch return;
151 }
148152 }
149153}
150154
......@@ -199,19 +203,21 @@ pub fn captureStackTrace(first_address: ?usize, stack_trace: *builtin.StackTrace
199203/// Tries to print a stack trace to stderr, unbuffered, and ignores any error returned.
200204/// TODO multithreaded awareness
201205pub fn dumpStackTrace(stack_trace: builtin.StackTrace) void {
202 const stderr = getStderrStream();
203 if (builtin.strip_debug_info) {
204 noasync stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
205 return;
206 noasync {
207 const stderr = getStderrStream();
208 if (builtin.strip_debug_info) {
209 stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
210 return;
211 }
212 const debug_info = getSelfDebugInfo() catch |err| {
213 stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
214 return;
215 };
216 writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, detectTTYConfig()) catch |err| {
217 stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;
218 return;
219 };
206220 }
207 const debug_info = getSelfDebugInfo() catch |err| {
208 noasync stderr.print("Unable to dump stack trace: Unable to open debug info: {}\n", .{@errorName(err)}) catch return;
209 return;
210 };
211 writeStackTrace(stack_trace, stderr, getDebugInfoAllocator(), debug_info, detectTTYConfig()) catch |err| {
212 noasync stderr.print("Unable to dump stack trace: {}\n", .{@errorName(err)}) catch return;
213 return;
214 };
215221}
216222
217223/// This function invokes undefined behavior when `ok` is `false`.
......@@ -255,7 +261,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
255261 resetSegfaultHandler();
256262 }
257263
258 switch (panic_stage) {
264 noasync switch (panic_stage) {
259265 0 => {
260266 panic_stage = 1;
261267
......@@ -267,7 +273,7 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
267273 defer held.release();
268274
269275 const stderr = getStderrStream();
270 noasync stderr.print(format ++ "\n", args) catch os.abort();
276 stderr.print(format ++ "\n", args) catch os.abort();
271277 if (trace) |t| {
272278 dumpStackTrace(t.*);
273279 }
......@@ -292,12 +298,12 @@ pub fn panicExtra(trace: ?*const builtin.StackTrace, first_trace_addr: ?usize, c
292298 // we're still holding the mutex but that's fine as we're going to
293299 // call abort()
294300 const stderr = getStderrStream();
295 noasync stderr.print("Panicked during a panic. Aborting.\n", .{}) catch os.abort();
301 stderr.print("Panicked during a panic. Aborting.\n", .{}) catch os.abort();
296302 },
297303 else => {
298304 // Panicked while printing "Panicked during a panic."
299305 },
300 }
306 };
301307
302308 os.abort();
303309}
lib/std/event/loop.zig+69-144
......@@ -4,19 +4,27 @@ const root = @import("root");
44const assert = std.debug.assert;
55const testing = std.testing;
66const mem = std.mem;
7const AtomicRmwOp = builtin.AtomicRmwOp;
8const AtomicOrder = builtin.AtomicOrder;
97const os = std.os;
108const windows = os.windows;
119const maxInt = std.math.maxInt;
1210const Thread = std.Thread;
1311
12const is_windows = std.Target.current.os.tag == .windows;
13
1414pub const Loop = struct {
1515 next_tick_queue: std.atomic.Queue(anyframe),
1616 os_data: OsData,
1717 final_resume_node: ResumeNode,
1818 pending_event_count: usize,
1919 extra_threads: []*Thread,
20 /// TODO change this to a pool of configurable number of threads
21 /// and rename it to be not file-system-specific. it will become
22 /// a thread pool for turning non-CPU-bound blocking things into
23 /// async things. A fallback for any missing OS-specific API.
24 fs_thread: *Thread,
25 fs_queue: std.atomic.Queue(Request),
26 fs_end_request: Request.Node,
27 fs_thread_wakeup: std.ResetEvent,
2028
2129 /// For resources that have the same lifetime as the `Loop`.
2230 /// This is only used by `Loop` for the thread pool and associated resources.
......@@ -143,7 +151,12 @@ pub const Loop = struct {
143151 .handle = undefined,
144152 .overlapped = ResumeNode.overlapped_init,
145153 },
154 .fs_end_request = .{ .data = .{ .msg = .end, .finish = .NoAction } },
155 .fs_queue = std.atomic.Queue(Request).init(),
156 .fs_thread = undefined,
157 .fs_thread_wakeup = std.ResetEvent.init(),
146158 };
159 errdefer self.fs_thread_wakeup.deinit();
147160 errdefer self.arena.deinit();
148161
149162 // We need at least one of these in case the fs thread wants to use onNextTick
......@@ -158,10 +171,19 @@ pub const Loop = struct {
158171
159172 try self.initOsData(extra_thread_count);
160173 errdefer self.deinitOsData();
174
175 if (!builtin.single_threaded) {
176 self.fs_thread = try Thread.spawn(self, posixFsRun);
177 }
178 errdefer if (!builtin.single_threaded) {
179 self.posixFsRequest(&self.fs_end_request);
180 self.fs_thread.wait();
181 };
161182 }
162183
163184 pub fn deinit(self: *Loop) void {
164185 self.deinitOsData();
186 self.fs_thread_wakeup.deinit();
165187 self.arena.deinit();
166188 self.* = undefined;
167189 }
......@@ -173,21 +195,10 @@ pub const Loop = struct {
173195 const wakeup_bytes = [_]u8{0x1} ** 8;
174196
175197 fn initOsData(self: *Loop, extra_thread_count: usize) InitOsDataError!void {
176 switch (builtin.os.tag) {
198 noasync switch (builtin.os.tag) {
177199 .linux => {
178 self.os_data.fs_queue = std.atomic.Queue(Request).init();
179 self.os_data.fs_queue_item = 0;
180 // we need another thread for the file system because Linux does not have an async
181 // file system I/O API.
182 self.os_data.fs_end_request = Request.Node{
183 .data = Request{
184 .msg = .end,
185 .finish = .NoAction,
186 },
187 };
188
189200 errdefer {
190 while (self.available_eventfd_resume_nodes.pop()) |node| noasync os.close(node.data.eventfd);
201 while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd);
191202 }
192203 for (self.eventfd_resume_nodes) |*eventfd_node| {
193204 eventfd_node.* = std.atomic.Stack(ResumeNode.EventFd).Node{
......@@ -206,10 +217,10 @@ pub const Loop = struct {
206217 }
207218
208219 self.os_data.epollfd = try os.epoll_create1(os.EPOLL_CLOEXEC);
209 errdefer noasync os.close(self.os_data.epollfd);
220 errdefer os.close(self.os_data.epollfd);
210221
211222 self.os_data.final_eventfd = try os.eventfd(0, os.EFD_CLOEXEC | os.EFD_NONBLOCK);
212 errdefer noasync os.close(self.os_data.final_eventfd);
223 errdefer os.close(self.os_data.final_eventfd);
213224
214225 self.os_data.final_eventfd_event = os.epoll_event{
215226 .events = os.EPOLLIN,
......@@ -222,12 +233,6 @@ pub const Loop = struct {
222233 &self.os_data.final_eventfd_event,
223234 );
224235
225 self.os_data.fs_thread = try Thread.spawn(self, posixFsRun);
226 errdefer {
227 self.posixFsRequest(&self.os_data.fs_end_request);
228 self.os_data.fs_thread.wait();
229 }
230
231236 if (builtin.single_threaded) {
232237 assert(extra_thread_count == 0);
233238 return;
......@@ -236,7 +241,7 @@ pub const Loop = struct {
236241 var extra_thread_index: usize = 0;
237242 errdefer {
238243 // writing 8 bytes to an eventfd cannot fail
239 const amt = noasync os.write(self.os_data.final_eventfd, &wakeup_bytes) catch unreachable;
244 const amt = os.write(self.os_data.final_eventfd, &wakeup_bytes) catch unreachable;
240245 assert(amt == wakeup_bytes.len);
241246 while (extra_thread_index != 0) {
242247 extra_thread_index -= 1;
......@@ -249,22 +254,7 @@ pub const Loop = struct {
249254 },
250255 .macosx, .freebsd, .netbsd, .dragonfly => {
251256 self.os_data.kqfd = try os.kqueue();
252 errdefer noasync os.close(self.os_data.kqfd);
253
254 self.os_data.fs_kqfd = try os.kqueue();
255 errdefer noasync os.close(self.os_data.fs_kqfd);
256
257 self.os_data.fs_queue = std.atomic.Queue(Request).init();
258 // we need another thread for the file system because Darwin does not have an async
259 // file system I/O API.
260 self.os_data.fs_end_request = Request.Node{
261 .prev = undefined,
262 .next = undefined,
263 .data = Request{
264 .msg = .end,
265 .finish = .NoAction,
266 },
267 };
257 errdefer os.close(self.os_data.kqfd);
268258
269259 const empty_kevs = &[0]os.Kevent{};
270260
......@@ -310,30 +300,6 @@ pub const Loop = struct {
310300 self.os_data.final_kevent.flags = os.EV_ENABLE;
311301 self.os_data.final_kevent.fflags = os.NOTE_TRIGGER;
312302
313 self.os_data.fs_kevent_wake = os.Kevent{
314 .ident = 0,
315 .filter = os.EVFILT_USER,
316 .flags = os.EV_ADD | os.EV_ENABLE,
317 .fflags = os.NOTE_TRIGGER,
318 .data = 0,
319 .udata = undefined,
320 };
321
322 self.os_data.fs_kevent_wait = os.Kevent{
323 .ident = 0,
324 .filter = os.EVFILT_USER,
325 .flags = os.EV_ADD | os.EV_CLEAR,
326 .fflags = 0,
327 .data = 0,
328 .udata = undefined,
329 };
330
331 self.os_data.fs_thread = try Thread.spawn(self, posixFsRun);
332 errdefer {
333 self.posixFsRequest(&self.os_data.fs_end_request);
334 self.os_data.fs_thread.wait();
335 }
336
337303 if (builtin.single_threaded) {
338304 assert(extra_thread_count == 0);
339305 return;
......@@ -401,25 +367,24 @@ pub const Loop = struct {
401367 }
402368 },
403369 else => {},
404 }
370 };
405371 }
406372
407373 fn deinitOsData(self: *Loop) void {
408 switch (builtin.os.tag) {
374 noasync switch (builtin.os.tag) {
409375 .linux => {
410 noasync os.close(self.os_data.final_eventfd);
411 while (self.available_eventfd_resume_nodes.pop()) |node| noasync os.close(node.data.eventfd);
412 noasync os.close(self.os_data.epollfd);
376 os.close(self.os_data.final_eventfd);
377 while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd);
378 os.close(self.os_data.epollfd);
413379 },
414380 .macosx, .freebsd, .netbsd, .dragonfly => {
415 noasync os.close(self.os_data.kqfd);
416 noasync os.close(self.os_data.fs_kqfd);
381 os.close(self.os_data.kqfd);
417382 },
418383 .windows => {
419384 windows.CloseHandle(self.os_data.io_port);
420385 },
421386 else => {},
422 }
387 };
423388 }
424389
425390 /// resume_node must live longer than the anyframe that it holds a reference to.
......@@ -635,7 +600,7 @@ pub const Loop = struct {
635600 .freebsd,
636601 .netbsd,
637602 .dragonfly,
638 => self.os_data.fs_thread.wait(),
603 => self.fs_thread.wait(),
639604 else => {},
640605 }
641606
......@@ -672,23 +637,25 @@ pub const Loop = struct {
672637
673638 /// call finishOneEvent when done
674639 pub fn beginOneEvent(self: *Loop) void {
675 _ = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
640 _ = @atomicRmw(usize, &self.pending_event_count, .Add, 1, .SeqCst);
676641 }
677642
678643 pub fn finishOneEvent(self: *Loop) void {
679 const prev = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
680 if (prev == 1) {
644 noasync {
645 const prev = @atomicRmw(usize, &self.pending_event_count, .Sub, 1, .SeqCst);
646 if (prev != 1) return;
647
681648 // cause all the threads to stop
649 self.posixFsRequest(&self.fs_end_request);
650
682651 switch (builtin.os.tag) {
683652 .linux => {
684 self.posixFsRequest(&self.os_data.fs_end_request);
685653 // writing 8 bytes to an eventfd cannot fail
686 const amt = noasync os.write(self.os_data.final_eventfd, &wakeup_bytes) catch unreachable;
654 const amt = os.write(self.os_data.final_eventfd, &wakeup_bytes) catch unreachable;
687655 assert(amt == wakeup_bytes.len);
688656 return;
689657 },
690658 .macosx, .freebsd, .netbsd, .dragonfly => {
691 self.posixFsRequest(&self.os_data.fs_end_request);
692659 const final_kevent = @as(*const [1]os.Kevent, &self.os_data.final_kevent);
693660 const empty_kevs = &[0]os.Kevent{};
694661 // cannot fail because we already added it and this just enables it
......@@ -1041,73 +1008,55 @@ pub const Loop = struct {
10411008
10421009 fn posixFsRequest(self: *Loop, request_node: *Request.Node) void {
10431010 self.beginOneEvent(); // finished in posixFsRun after processing the msg
1044 self.os_data.fs_queue.put(request_node);
1045 switch (builtin.os.tag) {
1046 .macosx, .freebsd, .netbsd, .dragonfly => {
1047 const fs_kevs = @as(*const [1]os.Kevent, &self.os_data.fs_kevent_wake);
1048 const empty_kevs = &[0]os.Kevent{};
1049 _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;
1050 },
1051 .linux => {
1052 @atomicStore(i32, &self.os_data.fs_queue_item, 1, AtomicOrder.SeqCst);
1053 const rc = os.linux.futex_wake(&self.os_data.fs_queue_item, os.linux.FUTEX_WAKE, 1);
1054 switch (os.linux.getErrno(rc)) {
1055 0 => {},
1056 os.EINVAL => unreachable,
1057 else => unreachable,
1058 }
1059 },
1060 else => @compileError("Unsupported OS"),
1061 }
1011 self.fs_queue.put(request_node);
1012 self.fs_thread_wakeup.set();
10621013 }
10631014
10641015 fn posixFsCancel(self: *Loop, request_node: *Request.Node) void {
1065 if (self.os_data.fs_queue.remove(request_node)) {
1016 if (self.fs_queue.remove(request_node)) {
10661017 self.finishOneEvent();
10671018 }
10681019 }
10691020
1070 // TODO make this whole function noasync
1071 // https://github.com/ziglang/zig/issues/3157
10721021 fn posixFsRun(self: *Loop) void {
1073 while (true) {
1074 if (builtin.os.tag == .linux) {
1075 @atomicStore(i32, &self.os_data.fs_queue_item, 0, .SeqCst);
1076 }
1077 while (self.os_data.fs_queue.get()) |node| {
1022 noasync while (true) {
1023 self.fs_thread_wakeup.reset();
1024 while (self.fs_queue.get()) |node| {
10781025 switch (node.data.msg) {
10791026 .end => return,
10801027 .read => |*msg| {
1081 msg.result = noasync os.read(msg.fd, msg.buf);
1028 msg.result = os.read(msg.fd, msg.buf);
10821029 },
10831030 .readv => |*msg| {
1084 msg.result = noasync os.readv(msg.fd, msg.iov);
1031 msg.result = os.readv(msg.fd, msg.iov);
10851032 },
10861033 .write => |*msg| {
1087 msg.result = noasync os.write(msg.fd, msg.bytes);
1034 msg.result = os.write(msg.fd, msg.bytes);
10881035 },
10891036 .writev => |*msg| {
1090 msg.result = noasync os.writev(msg.fd, msg.iov);
1037 msg.result = os.writev(msg.fd, msg.iov);
10911038 },
10921039 .pwritev => |*msg| {
1093 msg.result = noasync os.pwritev(msg.fd, msg.iov, msg.offset);
1040 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);
10941041 },
10951042 .pread => |*msg| {
1096 msg.result = noasync os.pread(msg.fd, msg.buf, msg.offset);
1043 msg.result = os.pread(msg.fd, msg.buf, msg.offset);
10971044 },
10981045 .preadv => |*msg| {
1099 msg.result = noasync os.preadv(msg.fd, msg.iov, msg.offset);
1046 msg.result = os.preadv(msg.fd, msg.iov, msg.offset);
11001047 },
11011048 .open => |*msg| {
1102 msg.result = noasync os.openZ(msg.path, msg.flags, msg.mode);
1049 if (is_windows) unreachable; // TODO
1050 msg.result = os.openZ(msg.path, msg.flags, msg.mode);
11031051 },
11041052 .openat => |*msg| {
1105 msg.result = noasync os.openatZ(msg.fd, msg.path, msg.flags, msg.mode);
1053 if (is_windows) unreachable; // TODO
1054 msg.result = os.openatZ(msg.fd, msg.path, msg.flags, msg.mode);
11061055 },
11071056 .faccessat => |*msg| {
1108 msg.result = noasync os.faccessatZ(msg.dirfd, msg.path, msg.mode, msg.flags);
1057 msg.result = os.faccessatZ(msg.dirfd, msg.path, msg.mode, msg.flags);
11091058 },
1110 .close => |*msg| noasync os.close(msg.fd),
1059 .close => |*msg| os.close(msg.fd),
11111060 }
11121061 switch (node.data.finish) {
11131062 .TickNode => |*tick_node| self.onNextTick(tick_node),
......@@ -1115,22 +1064,8 @@ pub const Loop = struct {
11151064 }
11161065 self.finishOneEvent();
11171066 }
1118 switch (builtin.os.tag) {
1119 .linux => {
1120 const rc = os.linux.futex_wait(&self.os_data.fs_queue_item, os.linux.FUTEX_WAIT, 0, null);
1121 switch (os.linux.getErrno(rc)) {
1122 0, os.EINTR, os.EAGAIN => continue,
1123 else => unreachable,
1124 }
1125 },
1126 .macosx, .freebsd, .netbsd, .dragonfly => {
1127 const fs_kevs = @as(*const [1]os.Kevent, &self.os_data.fs_kevent_wait);
1128 var out_kevs: [1]os.Kevent = undefined;
1129 _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, out_kevs[0..], null) catch unreachable;
1130 },
1131 else => @compileError("Unsupported OS"),
1132 }
1133 }
1067 self.fs_thread_wakeup.wait();
1068 };
11341069 }
11351070
11361071 const OsData = switch (builtin.os.tag) {
......@@ -1146,22 +1081,12 @@ pub const Loop = struct {
11461081 const KEventData = struct {
11471082 kqfd: i32,
11481083 final_kevent: os.Kevent,
1149 fs_kevent_wake: os.Kevent,
1150 fs_kevent_wait: os.Kevent,
1151 fs_thread: *Thread,
1152 fs_kqfd: i32,
1153 fs_queue: std.atomic.Queue(Request),
1154 fs_end_request: Request.Node,
11551084 };
11561085
11571086 const LinuxOsData = struct {
11581087 epollfd: i32,
11591088 final_eventfd: i32,
11601089 final_eventfd_event: os.linux.epoll_event,
1161 fs_thread: *Thread,
1162 fs_queue_item: i32,
1163 fs_queue: std.atomic.Queue(Request),
1164 fs_end_request: Request.Node,
11651090 };
11661091
11671092 pub const Request = struct {
......@@ -1302,11 +1227,11 @@ test "std.event.Loop - basic" {
13021227 loop.run();
13031228}
13041229
1305async fn testEventLoop() i32 {
1230fn testEventLoop() i32 {
13061231 return 1234;
13071232}
13081233
1309async fn testEventLoop2(h: anyframe->i32, did_it: *bool) void {
1234fn testEventLoop2(h: anyframe->i32, did_it: *bool) void {
13101235 const value = await h;
13111236 testing.expect(value == 1234);
13121237 did_it.* = true;
lib/std/fs.zig+1-1
......@@ -734,7 +734,7 @@ pub const Dir = struct {
734734 .dir = self.fd,
735735 .access_mask = w.SYNCHRONIZE | w.GENERIC_WRITE | read_flag,
736736 .share_access = switch (flags.lock) {
737 .None => @as(?w.ULONG, null),
737 .None => w.FILE_SHARE_WRITE | w.FILE_SHARE_READ | w.FILE_SHARE_DELETE,
738738 .Shared => w.FILE_SHARE_READ | w.FILE_SHARE_DELETE,
739739 .Exclusive => w.FILE_SHARE_DELETE,
740740 },
lib/std/os.zig+16-3
......@@ -854,8 +854,11 @@ pub const OpenError = error{
854854
855855/// Open and possibly create a file. Keeps trying if it gets interrupted.
856856/// See also `openC`.
857/// TODO support windows
858857pub fn open(file_path: []const u8, flags: u32, perm: usize) OpenError!fd_t {
858 if (std.Target.current.os.tag == .windows) {
859 const file_path_w = try windows.sliceToPrefixedFileW(file_path);
860 return openW(&file_path_w, flags, perm);
861 }
859862 const file_path_c = try toPosixPath(file_path);
860863 return openZ(&file_path_c, flags, perm);
861864}
......@@ -864,8 +867,11 @@ pub const openC = @compileError("deprecated: renamed to openZ");
864867
865868/// Open and possibly create a file. Keeps trying if it gets interrupted.
866869/// See also `open`.
867/// TODO support windows
868870pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t {
871 if (std.Target.current.os.tag == .windows) {
872 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
873 return openW(&file_path_w, flags, perm);
874 }
869875 while (true) {
870876 const rc = system.open(file_path, flags, perm);
871877 switch (errno(rc)) {
......@@ -895,6 +901,13 @@ pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: usize) OpenError!fd_t {
895901 }
896902}
897903
904/// Windows-only. The path parameter is
905/// [WTF-16](https://simonsapin.github.io/wtf-8/#potentially-ill-formed-utf-16) encoded.
906/// Translates the POSIX open API call to a Windows API call.
907pub fn openW(file_path_w: []const u16, flags: u32, perm: usize) OpenError!fd_t {
908 @compileError("TODO implement openW for windows");
909}
910
898911/// Open and possibly create a file. Keeps trying if it gets interrupted.
899912/// `file_path` is relative to the open directory handle `dir_fd`.
900913/// See also `openatC`.
......@@ -1683,7 +1696,7 @@ pub fn renameatW(
16831696 .dir = old_dir_fd,
16841697 .access_mask = windows.SYNCHRONIZE | windows.GENERIC_WRITE | windows.DELETE,
16851698 .creation = windows.FILE_OPEN,
1686 .enable_async_io = false,
1699 .io_mode = .blocking,
16871700 }) catch |err| switch (err) {
16881701 error.WouldBlock => unreachable, // Not possible without `.share_access_nonblocking = true`.
16891702 else => |e| return e,
lib/std/os/windows.zig+2-2
......@@ -116,10 +116,10 @@ pub const OpenFileOptions = struct {
116116/// TODO when share_access_nonblocking is false, this implementation uses
117117/// untinterruptible sleep() to block. This is not the final iteration of the API.
118118pub fn OpenFile(sub_path_w: []const u16, options: OpenFileOptions) OpenError!HANDLE {
119 if (sub_path_w[0] == '.' and sub_path_w[1] == 0) {
119 if (mem.eql(u16, sub_path_w, ".")) {
120120 return error.IsDir;
121121 }
122 if (sub_path_w[0] == '.' and sub_path_w[1] == '.' and sub_path_w[2] == 0) {
122 if (mem.eql(u16, sub_path_w, "..")) {
123123 return error.IsDir;
124124 }
125125
lib/std/reset_event.zig+1-1
......@@ -52,7 +52,7 @@ pub const ResetEvent = struct {
5252
5353 /// Wait for the event to be set by blocking the current thread.
5454 /// A timeout in nanoseconds can be provided as a hint for how
55 /// long the thread should block on the unset event before throwind error.TimedOut.
55 /// long the thread should block on the unset event before throwing error.TimedOut.
5656 pub fn timedWait(self: *ResetEvent, timeout_ns: u64) !void {
5757 return self.os_event.wait(timeout_ns);
5858 }