authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-08 15:13:05-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-08-08 15:13:05-04:00
logcfe84423c97eb2121138c2de5876c47782cd6dda
tree026afba62a3c412cee5fb4c40e4208f1e3038a3c
parentbfa1d12fbad2031402fbafe51c3a0c481fe69351
signature Commit is signed but in an unrecognized format.

fix segfault with var args


3 files changed, 143 insertions(+), 148 deletions(-)

src/ir.cpp+5-3
...@@ -15746,7 +15746,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -15746,7 +15746,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
15746 size_t impl_param_count = impl_fn_type_id->param_count;15746 size_t impl_param_count = impl_fn_type_id->param_count;
15747 if (call_instruction->is_async) {15747 if (call_instruction->is_async) {
15748 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,15748 IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry,
15749 nullptr, casted_args, call_param_count, casted_new_stack);15749 nullptr, casted_args, impl_param_count, casted_new_stack);
15750 return ir_finish_anal(ira, result);15750 return ir_finish_anal(ira, result);
15751 }15751 }
1575215752
...@@ -15756,7 +15756,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -15756,7 +15756,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
1575615756
15757 IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base,15757 IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base,
15758 impl_fn, nullptr, impl_param_count, casted_args, fn_inline,15758 impl_fn, nullptr, impl_param_count, casted_args, fn_inline,
15759 call_instruction->is_async, casted_new_stack, result_loc,15759 false, casted_new_stack, result_loc,
15760 impl_fn_type_id->return_type);15760 impl_fn_type_id->return_type);
1576115761
15762 parent_fn_entry->call_list.append(new_call_instruction);15762 parent_fn_entry->call_list.append(new_call_instruction);
...@@ -15799,7 +15799,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c...@@ -15799,7 +15799,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c
15799 casted_args[next_arg_index] = casted_arg;15799 casted_args[next_arg_index] = casted_arg;
15800 next_arg_index += 1;15800 next_arg_index += 1;
15801 }15801 }
15802 for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) {15802 size_t iter_count = (call_param_count < call_instruction->arg_count) ?
15803 call_param_count : call_instruction->arg_count;
15804 for (size_t call_i = 0; call_i < iter_count; call_i += 1) {
15803 IrInstruction *old_arg = call_instruction->args[call_i]->child;15805 IrInstruction *old_arg = call_instruction->args[call_i]->child;
15804 if (type_is_invalid(old_arg->value.type))15806 if (type_is_invalid(old_arg->value.type))
15805 return ira->codegen->invalid_instruction;15807 return ira->codegen->invalid_instruction;
std/event/fs.zig+60-60
...@@ -83,10 +83,10 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us...@@ -83,10 +83,10 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us
83 resume @handle();83 resume @handle();
84 }84 }
85 switch (builtin.os) {85 switch (builtin.os) {
86 builtin.Os.macosx,86 .macosx,
87 builtin.Os.linux,87 .linux,
88 builtin.Os.freebsd,88 .freebsd,
89 builtin.Os.netbsd,89 .netbsd,
90 => {90 => {
91 const iovecs = try loop.allocator.alloc(os.iovec_const, data.len);91 const iovecs = try loop.allocator.alloc(os.iovec_const, data.len);
92 defer loop.allocator.free(iovecs);92 defer loop.allocator.free(iovecs);
...@@ -100,7 +100,7 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us...@@ -100,7 +100,7 @@ pub async fn pwritev(loop: *Loop, fd: fd_t, data: []const []const u8, offset: us
100100
101 return await (async pwritevPosix(loop, fd, iovecs, offset) catch unreachable);101 return await (async pwritevPosix(loop, fd, iovecs, offset) catch unreachable);
102 },102 },
103 builtin.Os.windows => {103 .windows => {
104 const data_copy = try std.mem.dupe(loop.allocator, []const u8, data);104 const data_copy = try std.mem.dupe(loop.allocator, []const u8, data);
105 defer loop.allocator.free(data_copy);105 defer loop.allocator.free(data_copy);
106 return await (async pwritevWindows(loop, fd, data, offset) catch unreachable);106 return await (async pwritevWindows(loop, fd, data, offset) catch unreachable);
...@@ -220,10 +220,10 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR...@@ -220,10 +220,10 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR
220220
221 assert(data.len != 0);221 assert(data.len != 0);
222 switch (builtin.os) {222 switch (builtin.os) {
223 builtin.Os.macosx,223 .macosx,
224 builtin.Os.linux,224 .linux,
225 builtin.Os.freebsd,225 .freebsd,
226 builtin.Os.netbsd,226 .netbsd,
227 => {227 => {
228 const iovecs = try loop.allocator.alloc(os.iovec, data.len);228 const iovecs = try loop.allocator.alloc(os.iovec, data.len);
229 defer loop.allocator.free(iovecs);229 defer loop.allocator.free(iovecs);
...@@ -237,7 +237,7 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR...@@ -237,7 +237,7 @@ pub async fn preadv(loop: *Loop, fd: fd_t, data: []const []u8, offset: usize) PR
237237
238 return await (async preadvPosix(loop, fd, iovecs, offset) catch unreachable);238 return await (async preadvPosix(loop, fd, iovecs, offset) catch unreachable);
239 },239 },
240 builtin.Os.windows => {240 .windows => {
241 const data_copy = try std.mem.dupe(loop.allocator, []u8, data);241 const data_copy = try std.mem.dupe(loop.allocator, []u8, data);
242 defer loop.allocator.free(data_copy);242 defer loop.allocator.free(data_copy);
243 return await (async preadvWindows(loop, fd, data_copy, offset) catch unreachable);243 return await (async preadvWindows(loop, fd, data_copy, offset) catch unreachable);
...@@ -403,12 +403,12 @@ pub async fn openPosix(...@@ -403,12 +403,12 @@ pub async fn openPosix(
403403
404pub async fn openRead(loop: *Loop, path: []const u8) File.OpenError!fd_t {404pub async fn openRead(loop: *Loop, path: []const u8) File.OpenError!fd_t {
405 switch (builtin.os) {405 switch (builtin.os) {
406 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {406 .macosx, .linux, .freebsd, .netbsd => {
407 const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;407 const flags = os.O_LARGEFILE | os.O_RDONLY | os.O_CLOEXEC;
408 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);408 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
409 },409 },
410410
411 builtin.Os.windows => return windows.CreateFile(411 .windows => return windows.CreateFile(
412 path,412 path,
413 windows.GENERIC_READ,413 windows.GENERIC_READ,
414 windows.FILE_SHARE_READ,414 windows.FILE_SHARE_READ,
...@@ -431,15 +431,15 @@ pub async fn openWrite(loop: *Loop, path: []const u8) File.OpenError!fd_t {...@@ -431,15 +431,15 @@ pub async fn openWrite(loop: *Loop, path: []const u8) File.OpenError!fd_t {
431/// Creates if does not exist. Truncates the file if it exists.431/// Creates if does not exist. Truncates the file if it exists.
432pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: File.Mode) File.OpenError!fd_t {432pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: File.Mode) File.OpenError!fd_t {
433 switch (builtin.os) {433 switch (builtin.os) {
434 builtin.Os.macosx,434 .macosx,
435 builtin.Os.linux,435 .linux,
436 builtin.Os.freebsd,436 .freebsd,
437 builtin.Os.netbsd,437 .netbsd,
438 => {438 => {
439 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;439 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT | os.O_CLOEXEC | os.O_TRUNC;
440 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);440 return await (async openPosix(loop, path, flags, File.default_mode) catch unreachable);
441 },441 },
442 builtin.Os.windows => return windows.CreateFile(442 .windows => return windows.CreateFile(
443 path,443 path,
444 windows.GENERIC_WRITE,444 windows.GENERIC_WRITE,
445 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,445 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
...@@ -459,12 +459,12 @@ pub async fn openReadWrite(...@@ -459,12 +459,12 @@ pub async fn openReadWrite(
459 mode: File.Mode,459 mode: File.Mode,
460) File.OpenError!fd_t {460) File.OpenError!fd_t {
461 switch (builtin.os) {461 switch (builtin.os) {
462 builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd, builtin.Os.netbsd => {462 .macosx, .linux, .freebsd, .netbsd => {
463 const flags = os.O_LARGEFILE | os.O_RDWR | os.O_CREAT | os.O_CLOEXEC;463 const flags = os.O_LARGEFILE | os.O_RDWR | os.O_CREAT | os.O_CLOEXEC;
464 return await (async openPosix(loop, path, flags, mode) catch unreachable);464 return await (async openPosix(loop, path, flags, mode) catch unreachable);
465 },465 },
466466
467 builtin.Os.windows => return windows.CreateFile(467 .windows => return windows.CreateFile(
468 path,468 path,
469 windows.GENERIC_WRITE | windows.GENERIC_READ,469 windows.GENERIC_WRITE | windows.GENERIC_READ,
470 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,470 windows.FILE_SHARE_WRITE | windows.FILE_SHARE_READ | windows.FILE_SHARE_DELETE,
...@@ -489,9 +489,9 @@ pub const CloseOperation = struct {...@@ -489,9 +489,9 @@ pub const CloseOperation = struct {
489 os_data: OsData,489 os_data: OsData,
490490
491 const OsData = switch (builtin.os) {491 const OsData = switch (builtin.os) {
492 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => OsDataPosix,492 .linux, .macosx, .freebsd, .netbsd => OsDataPosix,
493493
494 builtin.Os.windows => struct {494 .windows => struct {
495 handle: ?fd_t,495 handle: ?fd_t,
496 },496 },
497497
...@@ -508,8 +508,8 @@ pub const CloseOperation = struct {...@@ -508,8 +508,8 @@ pub const CloseOperation = struct {
508 self.* = CloseOperation{508 self.* = CloseOperation{
509 .loop = loop,509 .loop = loop,
510 .os_data = switch (builtin.os) {510 .os_data = switch (builtin.os) {
511 builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => initOsDataPosix(self),511 .linux, .macosx, .freebsd, .netbsd => initOsDataPosix(self),
512 builtin.Os.windows => OsData{ .handle = null },512 .windows => OsData{ .handle = null },
513 else => @compileError("Unsupported OS"),513 else => @compileError("Unsupported OS"),
514 },514 },
515 };515 };
...@@ -535,10 +535,10 @@ pub const CloseOperation = struct {...@@ -535,10 +535,10 @@ pub const CloseOperation = struct {
535 /// Defer this after creating.535 /// Defer this after creating.
536 pub fn finish(self: *CloseOperation) void {536 pub fn finish(self: *CloseOperation) void {
537 switch (builtin.os) {537 switch (builtin.os) {
538 builtin.Os.linux,538 .linux,
539 builtin.Os.macosx,539 .macosx,
540 builtin.Os.freebsd,540 .freebsd,
541 builtin.Os.netbsd,541 .netbsd,
542 => {542 => {
543 if (self.os_data.have_fd) {543 if (self.os_data.have_fd) {
544 self.loop.posixFsRequest(&self.os_data.close_req_node);544 self.loop.posixFsRequest(&self.os_data.close_req_node);
...@@ -546,7 +546,7 @@ pub const CloseOperation = struct {...@@ -546,7 +546,7 @@ pub const CloseOperation = struct {
546 self.loop.allocator.destroy(self);546 self.loop.allocator.destroy(self);
547 }547 }
548 },548 },
549 builtin.Os.windows => {549 .windows => {
550 if (self.os_data.handle) |handle| {550 if (self.os_data.handle) |handle| {
551 os.close(handle);551 os.close(handle);
552 }552 }
...@@ -558,15 +558,15 @@ pub const CloseOperation = struct {...@@ -558,15 +558,15 @@ pub const CloseOperation = struct {
558558
559 pub fn setHandle(self: *CloseOperation, handle: fd_t) void {559 pub fn setHandle(self: *CloseOperation, handle: fd_t) void {
560 switch (builtin.os) {560 switch (builtin.os) {
561 builtin.Os.linux,561 .linux,
562 builtin.Os.macosx,562 .macosx,
563 builtin.Os.freebsd,563 .freebsd,
564 builtin.Os.netbsd,564 .netbsd,
565 => {565 => {
566 self.os_data.close_req_node.data.msg.Close.fd = handle;566 self.os_data.close_req_node.data.msg.Close.fd = handle;
567 self.os_data.have_fd = true;567 self.os_data.have_fd = true;
568 },568 },
569 builtin.Os.windows => {569 .windows => {
570 self.os_data.handle = handle;570 self.os_data.handle = handle;
571 },571 },
572 else => @compileError("Unsupported OS"),572 else => @compileError("Unsupported OS"),
...@@ -576,14 +576,14 @@ pub const CloseOperation = struct {...@@ -576,14 +576,14 @@ pub const CloseOperation = struct {
576 /// Undo a `setHandle`.576 /// Undo a `setHandle`.
577 pub fn clearHandle(self: *CloseOperation) void {577 pub fn clearHandle(self: *CloseOperation) void {
578 switch (builtin.os) {578 switch (builtin.os) {
579 builtin.Os.linux,579 .linux,
580 builtin.Os.macosx,580 .macosx,
581 builtin.Os.freebsd,581 .freebsd,
582 builtin.Os.netbsd,582 .netbsd,
583 => {583 => {
584 self.os_data.have_fd = false;584 self.os_data.have_fd = false;
585 },585 },
586 builtin.Os.windows => {586 .windows => {
587 self.os_data.handle = null;587 self.os_data.handle = null;
588 },588 },
589 else => @compileError("Unsupported OS"),589 else => @compileError("Unsupported OS"),
...@@ -592,15 +592,15 @@ pub const CloseOperation = struct {...@@ -592,15 +592,15 @@ pub const CloseOperation = struct {
592592
593 pub fn getHandle(self: *CloseOperation) fd_t {593 pub fn getHandle(self: *CloseOperation) fd_t {
594 switch (builtin.os) {594 switch (builtin.os) {
595 builtin.Os.linux,595 .linux,
596 builtin.Os.macosx,596 .macosx,
597 builtin.Os.freebsd,597 .freebsd,
598 builtin.Os.netbsd,598 .netbsd,
599 => {599 => {
600 assert(self.os_data.have_fd);600 assert(self.os_data.have_fd);
601 return self.os_data.close_req_node.data.msg.Close.fd;601 return self.os_data.close_req_node.data.msg.Close.fd;
602 },602 },
603 builtin.Os.windows => {603 .windows => {
604 return self.os_data.handle.?;604 return self.os_data.handle.?;
605 },605 },
606 else => @compileError("Unsupported OS"),606 else => @compileError("Unsupported OS"),
...@@ -617,12 +617,12 @@ pub async fn writeFile(loop: *Loop, path: []const u8, contents: []const u8) !voi...@@ -617,12 +617,12 @@ pub async fn writeFile(loop: *Loop, path: []const u8, contents: []const u8) !voi
617/// contents must remain alive until writeFile completes.617/// contents must remain alive until writeFile completes.
618pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {618pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8, mode: File.Mode) !void {
619 switch (builtin.os) {619 switch (builtin.os) {
620 builtin.Os.linux,620 .linux,
621 builtin.Os.macosx,621 .macosx,
622 builtin.Os.freebsd,622 .freebsd,
623 builtin.Os.netbsd,623 .netbsd,
624 => return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable),624 => return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable),
625 builtin.Os.windows => return await (async writeFileWindows(loop, path, contents) catch unreachable),625 .windows => return await (async writeFileWindows(loop, path, contents) catch unreachable),
626 else => @compileError("Unsupported OS"),626 else => @compileError("Unsupported OS"),
627 }627 }
628}628}
...@@ -728,7 +728,7 @@ pub fn Watch(comptime V: type) type {...@@ -728,7 +728,7 @@ pub fn Watch(comptime V: type) type {
728 os_data: OsData,728 os_data: OsData,
729729
730 const OsData = switch (builtin.os) {730 const OsData = switch (builtin.os) {
731 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => struct {731 .macosx, .freebsd, .netbsd => struct {
732 file_table: FileTable,732 file_table: FileTable,
733 table_lock: event.Lock,733 table_lock: event.Lock,
734734
...@@ -739,8 +739,8 @@ pub fn Watch(comptime V: type) type {...@@ -739,8 +739,8 @@ pub fn Watch(comptime V: type) type {
739 };739 };
740 },740 },
741741
742 builtin.Os.linux => LinuxOsData,742 .linux => LinuxOsData,
743 builtin.Os.windows => WindowsOsData,743 .windows => WindowsOsData,
744744
745 else => @compileError("Unsupported OS"),745 else => @compileError("Unsupported OS"),
746 };746 };
...@@ -793,7 +793,7 @@ pub fn Watch(comptime V: type) type {...@@ -793,7 +793,7 @@ pub fn Watch(comptime V: type) type {
793 errdefer channel.destroy();793 errdefer channel.destroy();
794794
795 switch (builtin.os) {795 switch (builtin.os) {
796 builtin.Os.linux => {796 .linux => {
797 const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);797 const inotify_fd = try os.inotify_init1(os.linux.IN_NONBLOCK | os.linux.IN_CLOEXEC);
798 errdefer os.close(inotify_fd);798 errdefer os.close(inotify_fd);
799799
...@@ -802,7 +802,7 @@ pub fn Watch(comptime V: type) type {...@@ -802,7 +802,7 @@ pub fn Watch(comptime V: type) type {
802 return result;802 return result;
803 },803 },
804804
805 builtin.Os.windows => {805 .windows => {
806 const self = try loop.allocator.create(Self);806 const self = try loop.allocator.create(Self);
807 errdefer loop.allocator.destroy(self);807 errdefer loop.allocator.destroy(self);
808 self.* = Self{808 self.* = Self{
...@@ -817,7 +817,7 @@ pub fn Watch(comptime V: type) type {...@@ -817,7 +817,7 @@ pub fn Watch(comptime V: type) type {
817 return self;817 return self;
818 },818 },
819819
820 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {820 .macosx, .freebsd, .netbsd => {
821 const self = try loop.allocator.create(Self);821 const self = try loop.allocator.create(Self);
822 errdefer loop.allocator.destroy(self);822 errdefer loop.allocator.destroy(self);
823823
...@@ -837,7 +837,7 @@ pub fn Watch(comptime V: type) type {...@@ -837,7 +837,7 @@ pub fn Watch(comptime V: type) type {
837 /// All addFile calls and removeFile calls must have completed.837 /// All addFile calls and removeFile calls must have completed.
838 pub fn destroy(self: *Self) void {838 pub fn destroy(self: *Self) void {
839 switch (builtin.os) {839 switch (builtin.os) {
840 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {840 .macosx, .freebsd, .netbsd => {
841 // TODO we need to cancel the coroutines before destroying the lock841 // TODO we need to cancel the coroutines before destroying the lock
842 self.os_data.table_lock.deinit();842 self.os_data.table_lock.deinit();
843 var it = self.os_data.file_table.iterator();843 var it = self.os_data.file_table.iterator();
...@@ -847,8 +847,8 @@ pub fn Watch(comptime V: type) type {...@@ -847,8 +847,8 @@ pub fn Watch(comptime V: type) type {
847 }847 }
848 self.channel.destroy();848 self.channel.destroy();
849 },849 },
850 builtin.Os.linux => cancel self.os_data.putter,850 .linux => cancel self.os_data.putter,
851 builtin.Os.windows => {851 .windows => {
852 while (self.os_data.all_putters.get()) |putter_node| {852 while (self.os_data.all_putters.get()) |putter_node| {
853 cancel putter_node.data;853 cancel putter_node.data;
854 }854 }
...@@ -879,9 +879,9 @@ pub fn Watch(comptime V: type) type {...@@ -879,9 +879,9 @@ pub fn Watch(comptime V: type) type {
879879
880 pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {880 pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
881 switch (builtin.os) {881 switch (builtin.os) {
882 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),882 .macosx, .freebsd, .netbsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),
883 builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable),883 .linux => return await (async addFileLinux(self, file_path, value) catch unreachable),
884 builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable),884 .windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
885 else => @compileError("Unsupported OS"),885 else => @compileError("Unsupported OS"),
886 }886 }
887 }887 }
std/event/loop.zig+78-85
...@@ -13,7 +13,7 @@ const Thread = std.Thread;...@@ -13,7 +13,7 @@ const Thread = std.Thread;
1313
14pub const Loop = struct {14pub const Loop = struct {
15 allocator: *mem.Allocator,15 allocator: *mem.Allocator,
16 next_tick_queue: std.atomic.Queue(promise),16 next_tick_queue: std.atomic.Queue(anyframe),
17 os_data: OsData,17 os_data: OsData,
18 final_resume_node: ResumeNode,18 final_resume_node: ResumeNode,
19 pending_event_count: usize,19 pending_event_count: usize,
...@@ -24,11 +24,11 @@ pub const Loop = struct {...@@ -24,11 +24,11 @@ pub const Loop = struct {
24 available_eventfd_resume_nodes: std.atomic.Stack(ResumeNode.EventFd),24 available_eventfd_resume_nodes: std.atomic.Stack(ResumeNode.EventFd),
25 eventfd_resume_nodes: []std.atomic.Stack(ResumeNode.EventFd).Node,25 eventfd_resume_nodes: []std.atomic.Stack(ResumeNode.EventFd).Node,
2626
27 pub const NextTickNode = std.atomic.Queue(promise).Node;27 pub const NextTickNode = std.atomic.Queue(anyframe).Node;
2828
29 pub const ResumeNode = struct {29 pub const ResumeNode = struct {
30 id: Id,30 id: Id,
31 handle: promise,31 handle: anyframe,
32 overlapped: Overlapped,32 overlapped: Overlapped,
3333
34 pub const overlapped_init = switch (builtin.os) {34 pub const overlapped_init = switch (builtin.os) {
...@@ -110,7 +110,7 @@ pub const Loop = struct {...@@ -110,7 +110,7 @@ pub const Loop = struct {
110 .pending_event_count = 1,110 .pending_event_count = 1,
111 .allocator = allocator,111 .allocator = allocator,
112 .os_data = undefined,112 .os_data = undefined,
113 .next_tick_queue = std.atomic.Queue(promise).init(),113 .next_tick_queue = std.atomic.Queue(anyframe).init(),
114 .extra_threads = undefined,114 .extra_threads = undefined,
115 .available_eventfd_resume_nodes = std.atomic.Stack(ResumeNode.EventFd).init(),115 .available_eventfd_resume_nodes = std.atomic.Stack(ResumeNode.EventFd).init(),
116 .eventfd_resume_nodes = undefined,116 .eventfd_resume_nodes = undefined,
...@@ -148,18 +148,18 @@ pub const Loop = struct {...@@ -148,18 +148,18 @@ pub const Loop = struct {
148 fn initOsData(self: *Loop, extra_thread_count: usize) InitOsDataError!void {148 fn initOsData(self: *Loop, extra_thread_count: usize) InitOsDataError!void {
149 switch (builtin.os) {149 switch (builtin.os) {
150 .linux => {150 .linux => {
151 self.os_data.fs_queue = std.atomic.Queue(fs.Request).init();151 // TODO self.os_data.fs_queue = std.atomic.Queue(fs.Request).init();
152 self.os_data.fs_queue_item = 0;152 // TODO self.os_data.fs_queue_item = 0;
153 // we need another thread for the file system because Linux does not have an async153 // TODO // we need another thread for the file system because Linux does not have an async
154 // file system I/O API.154 // TODO // file system I/O API.
155 self.os_data.fs_end_request = fs.RequestNode{155 // TODO self.os_data.fs_end_request = fs.RequestNode{
156 .prev = undefined,156 // TODO .prev = undefined,
157 .next = undefined,157 // TODO .next = undefined,
158 .data = fs.Request{158 // TODO .data = fs.Request{
159 .msg = fs.Request.Msg.End,159 // TODO .msg = fs.Request.Msg.End,
160 .finish = fs.Request.Finish.NoAction,160 // TODO .finish = fs.Request.Finish.NoAction,
161 },161 // TODO },
162 };162 // TODO };
163163
164 errdefer {164 errdefer {
165 while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd);165 while (self.available_eventfd_resume_nodes.pop()) |node| os.close(node.data.eventfd);
...@@ -197,10 +197,10 @@ pub const Loop = struct {...@@ -197,10 +197,10 @@ pub const Loop = struct {
197 &self.os_data.final_eventfd_event,197 &self.os_data.final_eventfd_event,
198 );198 );
199199
200 self.os_data.fs_thread = try Thread.spawn(self, posixFsRun);200 // TODO self.os_data.fs_thread = try Thread.spawn(self, posixFsRun);
201 errdefer {201 errdefer {
202 self.posixFsRequest(&self.os_data.fs_end_request);202 // TODO self.posixFsRequest(&self.os_data.fs_end_request);
203 self.os_data.fs_thread.wait();203 // TODO self.os_data.fs_thread.wait();
204 }204 }
205205
206 if (builtin.single_threaded) {206 if (builtin.single_threaded) {
...@@ -302,10 +302,10 @@ pub const Loop = struct {...@@ -302,10 +302,10 @@ pub const Loop = struct {
302 .udata = undefined,302 .udata = undefined,
303 };303 };
304304
305 self.os_data.fs_thread = try Thread.spawn(self, posixFsRun);305 // TODO self.os_data.fs_thread = try Thread.spawn(self, posixFsRun);
306 errdefer {306 errdefer {
307 self.posixFsRequest(&self.os_data.fs_end_request);307 // TODO self.posixFsRequest(&self.os_data.fs_end_request);
308 self.os_data.fs_thread.wait();308 // TODO self.os_data.fs_thread.wait();
309 }309 }
310310
311 if (builtin.single_threaded) {311 if (builtin.single_threaded) {
...@@ -397,7 +397,7 @@ pub const Loop = struct {...@@ -397,7 +397,7 @@ pub const Loop = struct {
397 }397 }
398 }398 }
399399
400 /// resume_node must live longer than the promise that it holds a reference to.400 /// resume_node must live longer than the anyframe that it holds a reference to.
401 /// flags must contain EPOLLET401 /// flags must contain EPOLLET
402 pub fn linuxAddFd(self: *Loop, fd: i32, resume_node: *ResumeNode, flags: u32) !void {402 pub fn linuxAddFd(self: *Loop, fd: i32, resume_node: *ResumeNode, flags: u32) !void {
403 assert(flags & os.EPOLLET == os.EPOLLET);403 assert(flags & os.EPOLLET == os.EPOLLET);
...@@ -460,7 +460,7 @@ pub const Loop = struct {...@@ -460,7 +460,7 @@ pub const Loop = struct {
460 return resume_node.kev;460 return resume_node.kev;
461 }461 }
462462
463 /// resume_node must live longer than the promise that it holds a reference to.463 /// resume_node must live longer than the anyframe that it holds a reference to.
464 pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, fflags: u32) !void {464 pub fn bsdAddKev(self: *Loop, resume_node: *ResumeNode.Basic, ident: usize, filter: i16, fflags: u32) !void {
465 self.beginOneEvent();465 self.beginOneEvent();
466 errdefer self.finishOneEvent();466 errdefer self.finishOneEvent();
...@@ -561,11 +561,11 @@ pub const Loop = struct {...@@ -561,11 +561,11 @@ pub const Loop = struct {
561 self.workerRun();561 self.workerRun();
562562
563 switch (builtin.os) {563 switch (builtin.os) {
564 builtin.Os.linux,564 .linux,
565 builtin.Os.macosx,565 .macosx,
566 builtin.Os.freebsd,566 .freebsd,
567 builtin.Os.netbsd,567 .netbsd,
568 => self.os_data.fs_thread.wait(),568 => {}, // TODO self.os_data.fs_thread.wait(),
569 else => {},569 else => {},
570 }570 }
571571
...@@ -574,45 +574,39 @@ pub const Loop = struct {...@@ -574,45 +574,39 @@ pub const Loop = struct {
574 }574 }
575 }575 }
576576
577 /// This is equivalent to an async call, except instead of beginning execution of the async function,577 /// This is equivalent to function call, except it calls `startCpuBoundOperation` first.
578 /// it immediately returns to the caller, and the async function is queued in the event loop. It still578 pub fn call(comptime func: var, args: ...) @typeOf(func).ReturnType {
579 /// returns a promise to be awaited.579 startCpuBoundOperation();
580 pub fn call(self: *Loop, comptime func: var, args: ...) !(promise->@typeOf(func).ReturnType) {580 return func(args);
581 const S = struct {
582 async fn asyncFunc(loop: *Loop, handle: *promise->@typeOf(func).ReturnType, args2: ...) @typeOf(func).ReturnType {
583 suspend {
584 handle.* = @handle();
585 var my_tick_node = Loop.NextTickNode{
586 .prev = undefined,
587 .next = undefined,
588 .data = @handle(),
589 };
590 loop.onNextTick(&my_tick_node);
591 }
592 // TODO guaranteed allocation elision for await in same func as async
593 return await (async func(args2) catch unreachable);
594 }
595 };
596 var handle: promise->@typeOf(func).ReturnType = undefined;
597 return async<self.allocator> S.asyncFunc(self, &handle, args);
598 }581 }
599582
600 /// Awaiting a yield lets the event loop run, starting any unstarted async operations.583 /// Yielding lets the event loop run, starting any unstarted async operations.
601 /// Note that async operations automatically start when a function yields for any other reason,584 /// Note that async operations automatically start when a function yields for any other reason,
602 /// for example, when async I/O is performed. This function is intended to be used only when585 /// for example, when async I/O is performed. This function is intended to be used only when
603 /// CPU bound tasks would be waiting in the event loop but never get started because no async I/O586 /// CPU bound tasks would be waiting in the event loop but never get started because no async I/O
604 /// is performed.587 /// is performed.
605 pub async fn yield(self: *Loop) void {588 pub fn yield(self: *Loop) void {
606 suspend {589 suspend {
607 var my_tick_node = Loop.NextTickNode{590 var my_tick_node = NextTickNode{
608 .prev = undefined,591 .prev = undefined,
609 .next = undefined,592 .next = undefined,
610 .data = @handle(),593 .data = @frame(),
611 };594 };
612 self.onNextTick(&my_tick_node);595 self.onNextTick(&my_tick_node);
613 }596 }
614 }597 }
615598
599 /// If the build is multi-threaded and there is an event loop, then it calls `yield`. Otherwise,
600 /// does nothing.
601 pub fn startCpuBoundOperation() void {
602 if (builtin.is_single_threaded) {
603 return;
604 } else if (instance) |event_loop| {
605 event_loop.yield();
606 }
607 }
608
609
616 /// call finishOneEvent when done610 /// call finishOneEvent when done
617 pub fn beginOneEvent(self: *Loop) void {611 pub fn beginOneEvent(self: *Loop) void {
618 _ = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);612 _ = @atomicRmw(usize, &self.pending_event_count, AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
...@@ -624,7 +618,7 @@ pub const Loop = struct {...@@ -624,7 +618,7 @@ pub const Loop = struct {
624 // cause all the threads to stop618 // cause all the threads to stop
625 switch (builtin.os) {619 switch (builtin.os) {
626 .linux => {620 .linux => {
627 self.posixFsRequest(&self.os_data.fs_end_request);621 // TODO self.posixFsRequest(&self.os_data.fs_end_request);
628 // writing 8 bytes to an eventfd cannot fail622 // writing 8 bytes to an eventfd cannot fail
629 os.write(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;623 os.write(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
630 return;624 return;
...@@ -672,9 +666,9 @@ pub const Loop = struct {...@@ -672,9 +666,9 @@ pub const Loop = struct {
672 const handle = resume_node.handle;666 const handle = resume_node.handle;
673 const resume_node_id = resume_node.id;667 const resume_node_id = resume_node.id;
674 switch (resume_node_id) {668 switch (resume_node_id) {
675 ResumeNode.Id.Basic => {},669 .Basic => {},
676 ResumeNode.Id.Stop => return,670 .Stop => return,
677 ResumeNode.Id.EventFd => {671 .EventFd => {
678 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);672 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
679 event_fd_node.epoll_op = os.EPOLL_CTL_MOD;673 event_fd_node.epoll_op = os.EPOLL_CTL_MOD;
680 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);674 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
...@@ -696,12 +690,12 @@ pub const Loop = struct {...@@ -696,12 +690,12 @@ pub const Loop = struct {
696 const handle = resume_node.handle;690 const handle = resume_node.handle;
697 const resume_node_id = resume_node.id;691 const resume_node_id = resume_node.id;
698 switch (resume_node_id) {692 switch (resume_node_id) {
699 ResumeNode.Id.Basic => {693 .Basic => {
700 const basic_node = @fieldParentPtr(ResumeNode.Basic, "base", resume_node);694 const basic_node = @fieldParentPtr(ResumeNode.Basic, "base", resume_node);
701 basic_node.kev = ev;695 basic_node.kev = ev;
702 },696 },
703 ResumeNode.Id.Stop => return,697 .Stop => return,
704 ResumeNode.Id.EventFd => {698 .EventFd => {
705 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);699 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
706 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);700 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
707 self.available_eventfd_resume_nodes.push(stack_node);701 self.available_eventfd_resume_nodes.push(stack_node);
...@@ -730,9 +724,9 @@ pub const Loop = struct {...@@ -730,9 +724,9 @@ pub const Loop = struct {
730 const handle = resume_node.handle;724 const handle = resume_node.handle;
731 const resume_node_id = resume_node.id;725 const resume_node_id = resume_node.id;
732 switch (resume_node_id) {726 switch (resume_node_id) {
733 ResumeNode.Id.Basic => {},727 .Basic => {},
734 ResumeNode.Id.Stop => return,728 .Stop => return,
735 ResumeNode.Id.EventFd => {729 .EventFd => {
736 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);730 const event_fd_node = @fieldParentPtr(ResumeNode.EventFd, "base", resume_node);
737 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);731 const stack_node = @fieldParentPtr(std.atomic.Stack(ResumeNode.EventFd).Node, "data", event_fd_node);
738 self.available_eventfd_resume_nodes.push(stack_node);732 self.available_eventfd_resume_nodes.push(stack_node);
...@@ -750,12 +744,12 @@ pub const Loop = struct {...@@ -750,12 +744,12 @@ pub const Loop = struct {
750 self.beginOneEvent(); // finished in posixFsRun after processing the msg744 self.beginOneEvent(); // finished in posixFsRun after processing the msg
751 self.os_data.fs_queue.put(request_node);745 self.os_data.fs_queue.put(request_node);
752 switch (builtin.os) {746 switch (builtin.os) {
753 builtin.Os.macosx, builtin.Os.freebsd, builtin.Os.netbsd => {747 .macosx, .freebsd, .netbsd => {
754 const fs_kevs = (*const [1]os.Kevent)(&self.os_data.fs_kevent_wake);748 const fs_kevs = (*const [1]os.Kevent)(&self.os_data.fs_kevent_wake);
755 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];749 const empty_kevs = ([*]os.Kevent)(undefined)[0..0];
756 _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;750 _ = os.kevent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;
757 },751 },
758 builtin.Os.linux => {752 .linux => {
759 _ = @atomicRmw(i32, &self.os_data.fs_queue_item, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);753 _ = @atomicRmw(i32, &self.os_data.fs_queue_item, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst);
760 const rc = os.linux.futex_wake(&self.os_data.fs_queue_item, os.linux.FUTEX_WAKE, 1);754 const rc = os.linux.futex_wake(&self.os_data.fs_queue_item, os.linux.FUTEX_WAKE, 1);
761 switch (os.linux.getErrno(rc)) {755 switch (os.linux.getErrno(rc)) {
...@@ -781,18 +775,18 @@ pub const Loop = struct {...@@ -781,18 +775,18 @@ pub const Loop = struct {
781 }775 }
782 while (self.os_data.fs_queue.get()) |node| {776 while (self.os_data.fs_queue.get()) |node| {
783 switch (node.data.msg) {777 switch (node.data.msg) {
784 @TagType(fs.Request.Msg).End => return,778 .End => return,
785 @TagType(fs.Request.Msg).PWriteV => |*msg| {779 .PWriteV => |*msg| {
786 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);780 msg.result = os.pwritev(msg.fd, msg.iov, msg.offset);
787 },781 },
788 @TagType(fs.Request.Msg).PReadV => |*msg| {782 .PReadV => |*msg| {
789 msg.result = os.preadv(msg.fd, msg.iov, msg.offset);783 msg.result = os.preadv(msg.fd, msg.iov, msg.offset);
790 },784 },
791 @TagType(fs.Request.Msg).Open => |*msg| {785 .Open => |*msg| {
792 msg.result = os.openC(msg.path.ptr, msg.flags, msg.mode);786 msg.result = os.openC(msg.path.ptr, msg.flags, msg.mode);
793 },787 },
794 @TagType(fs.Request.Msg).Close => |*msg| os.close(msg.fd),788 .Close => |*msg| os.close(msg.fd),
795 @TagType(fs.Request.Msg).WriteFile => |*msg| blk: {789 .WriteFile => |*msg| blk: {
796 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT |790 const flags = os.O_LARGEFILE | os.O_WRONLY | os.O_CREAT |
797 os.O_CLOEXEC | os.O_TRUNC;791 os.O_CLOEXEC | os.O_TRUNC;
798 const fd = os.openC(msg.path.ptr, flags, msg.mode) catch |err| {792 const fd = os.openC(msg.path.ptr, flags, msg.mode) catch |err| {
...@@ -804,11 +798,11 @@ pub const Loop = struct {...@@ -804,11 +798,11 @@ pub const Loop = struct {
804 },798 },
805 }799 }
806 switch (node.data.finish) {800 switch (node.data.finish) {
807 @TagType(fs.Request.Finish).TickNode => |*tick_node| self.onNextTick(tick_node),801 .TickNode => |*tick_node| self.onNextTick(tick_node),
808 @TagType(fs.Request.Finish).DeallocCloseOperation => |close_op| {802 .DeallocCloseOperation => |close_op| {
809 self.allocator.destroy(close_op);803 self.allocator.destroy(close_op);
810 },804 },
811 @TagType(fs.Request.Finish).NoAction => {},805 .NoAction => {},
812 }806 }
813 self.finishOneEvent();807 self.finishOneEvent();
814 }808 }
...@@ -855,16 +849,16 @@ pub const Loop = struct {...@@ -855,16 +849,16 @@ pub const Loop = struct {
855 epollfd: i32,849 epollfd: i32,
856 final_eventfd: i32,850 final_eventfd: i32,
857 final_eventfd_event: os.linux.epoll_event,851 final_eventfd_event: os.linux.epoll_event,
858 fs_thread: *Thread,852 // TODO fs_thread: *Thread,
859 fs_queue_item: i32,853 // TODO fs_queue_item: i32,
860 fs_queue: std.atomic.Queue(fs.Request),854 // TODO fs_queue: std.atomic.Queue(fs.Request),
861 fs_end_request: fs.RequestNode,855 // TODO fs_end_request: fs.RequestNode,
862 };856 };
863};857};
864858
865test "std.event.Loop - basic" {859test "std.event.Loop - basic" {
866 // https://github.com/ziglang/zig/issues/1908860 // https://github.com/ziglang/zig/issues/1908
867 if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;861 if (builtin.single_threaded) return error.SkipZigTest;
868862
869 const allocator = std.heap.direct_allocator;863 const allocator = std.heap.direct_allocator;
870864
...@@ -877,7 +871,7 @@ test "std.event.Loop - basic" {...@@ -877,7 +871,7 @@ test "std.event.Loop - basic" {
877871
878test "std.event.Loop - call" {872test "std.event.Loop - call" {
879 // https://github.com/ziglang/zig/issues/1908873 // https://github.com/ziglang/zig/issues/1908
880 if (builtin.single_threaded or builtin.os != builtin.Os.linux) return error.SkipZigTest;874 if (builtin.single_threaded) return error.SkipZigTest;
881875
882 const allocator = std.heap.direct_allocator;876 const allocator = std.heap.direct_allocator;
883877
...@@ -886,9 +880,8 @@ test "std.event.Loop - call" {...@@ -886,9 +880,8 @@ test "std.event.Loop - call" {
886 defer loop.deinit();880 defer loop.deinit();
887881
888 var did_it = false;882 var did_it = false;
889 const handle = try loop.call(testEventLoop);883 const handle = async Loop.call(testEventLoop);
890 const handle2 = try loop.call(testEventLoop2, handle, &did_it);884 const handle2 = async Loop.call(testEventLoop2, handle, &did_it);
891 defer cancel handle2;
892885
893 loop.run();886 loop.run();
894887
...@@ -899,7 +892,7 @@ async fn testEventLoop() i32 {...@@ -899,7 +892,7 @@ async fn testEventLoop() i32 {
899 return 1234;892 return 1234;
900}893}
901894
902async fn testEventLoop2(h: promise->i32, did_it: *bool) void {895async fn testEventLoop2(h: anyframe->i32, did_it: *bool) void {
903 const value = await h;896 const value = await h;
904 testing.expect(value == 1234);897 testing.expect(value == 1234);
905 did_it.* = true;898 did_it.* = true;