From 16f041970007d997d67ee2e15f0eba1053204808 Mon Sep 17 00:00:00 2001 From: Loris Cro Date: Tue, 29 Sep 2020 14:50:46 +0200 Subject: add runDetached to event loop Signed-off-by: Loris Cro --- lib/std/event/loop.zig | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'lib/std/event/loop.zig') diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig index 2ed9f938d8..cb0aa63dbe 100644 --- a/lib/std/event/loop.zig +++ b/lib/std/event/loop.zig @@ -647,6 +647,29 @@ pub const Loop = struct { } } + /// Runs the provided function asynchonously, similarly to Go's "go" operator. + /// `func` must return void and it can be an async function. + fn runDetached(self: *Loop, alloc: *mem.Allocator, comptime func: anytype, args: anytype) error{OutOfMemory}!void { + if (!std.io.is_async) @compileError("Can't use runDetached in non-async mode!"); + if (@TypeOf(@call(.{}, func, args)) != void) { + @compileError("`func` must not have a return value"); + } + + const Wrapper = struct { + const Args = @TypeOf(args); + fn run(func_args: Args, loop: *Loop, allocator: *mem.Allocator) void { + loop.yield(); + const result = @call(.{}, func, func_args); + suspend { + allocator.destroy(@frame()); + } + } + }; + + var run_frame = try alloc.create(@Frame(Wrapper.run)); + run_frame.* = async Wrapper.run(args, self, alloc); + } + /// Yielding lets the event loop run, starting any unstarted async operations. /// Note that async operations automatically start when a function yields for any other reason, /// for example, when async I/O is performed. This function is intended to be used only when @@ -1493,3 +1516,33 @@ fn testEventLoop2(h: anyframe->i32, did_it: *bool) void { testing.expect(value == 1234); did_it.* = true; } + +var testRunDetachedData: usize = 0; +test "std.event.Loop - runDetached" { + // https://github.com/ziglang/zig/issues/1908 + if (builtin.single_threaded) return error.SkipZigTest; + if (!std.io.is_async) return error.SkipZigTest; + if (true) { + // https://github.com/ziglang/zig/issues/4922 + return error.SkipZigTest; + } + + var loop: Loop = undefined; + try loop.initMultiThreaded(); + defer loop.deinit(); + + // Schedule the execution, won't actually start until we start the + // event loop. + try loop.runDetached(std.testing.allocator, testRunDetached, .{}); + + // Now we can start the event loop. The function will return only + // after all tasks have been completed, allowing us to synchonize + // with the previous runDetached. + loop.run(); + + testing.expect(testRunDetachedData == 1); +} + +fn testRunDetached() void { + testRunDetachedData += 1; +} -- cgit v1.2.3 From bf0afaa876391571f6072650bf450356b26c928d Mon Sep 17 00:00:00 2001 From: Alexandros Naskos Date: Thu, 1 Oct 2020 16:50:05 +0300 Subject: std.event.Loop.runDetached should be pub --- lib/std/event/loop.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/std/event/loop.zig') diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig index cb0aa63dbe..cf220bf775 100644 --- a/lib/std/event/loop.zig +++ b/lib/std/event/loop.zig @@ -649,7 +649,7 @@ pub const Loop = struct { /// Runs the provided function asynchonously, similarly to Go's "go" operator. /// `func` must return void and it can be an async function. - fn runDetached(self: *Loop, alloc: *mem.Allocator, comptime func: anytype, args: anytype) error{OutOfMemory}!void { + pub fn runDetached(self: *Loop, alloc: *mem.Allocator, comptime func: anytype, args: anytype) error{OutOfMemory}!void { if (!std.io.is_async) @compileError("Can't use runDetached in non-async mode!"); if (@TypeOf(@call(.{}, func, args)) != void) { @compileError("`func` must not have a return value"); -- cgit v1.2.3 From 70f37679035e64bacfc4807709da37bc02fbb346 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 3 Oct 2020 17:13:22 -0700 Subject: revert adding std.event.Loop.runDetached I'd like to discuss this before adding it. I think this is the wrong direction to go with this API. --- lib/std/event/loop.zig | 53 -------------------------------------------------- 1 file changed, 53 deletions(-) (limited to 'lib/std/event/loop.zig') diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig index cf220bf775..2ed9f938d8 100644 --- a/lib/std/event/loop.zig +++ b/lib/std/event/loop.zig @@ -647,29 +647,6 @@ pub const Loop = struct { } } - /// Runs the provided function asynchonously, similarly to Go's "go" operator. - /// `func` must return void and it can be an async function. - pub fn runDetached(self: *Loop, alloc: *mem.Allocator, comptime func: anytype, args: anytype) error{OutOfMemory}!void { - if (!std.io.is_async) @compileError("Can't use runDetached in non-async mode!"); - if (@TypeOf(@call(.{}, func, args)) != void) { - @compileError("`func` must not have a return value"); - } - - const Wrapper = struct { - const Args = @TypeOf(args); - fn run(func_args: Args, loop: *Loop, allocator: *mem.Allocator) void { - loop.yield(); - const result = @call(.{}, func, func_args); - suspend { - allocator.destroy(@frame()); - } - } - }; - - var run_frame = try alloc.create(@Frame(Wrapper.run)); - run_frame.* = async Wrapper.run(args, self, alloc); - } - /// Yielding lets the event loop run, starting any unstarted async operations. /// Note that async operations automatically start when a function yields for any other reason, /// for example, when async I/O is performed. This function is intended to be used only when @@ -1516,33 +1493,3 @@ fn testEventLoop2(h: anyframe->i32, did_it: *bool) void { testing.expect(value == 1234); did_it.* = true; } - -var testRunDetachedData: usize = 0; -test "std.event.Loop - runDetached" { - // https://github.com/ziglang/zig/issues/1908 - if (builtin.single_threaded) return error.SkipZigTest; - if (!std.io.is_async) return error.SkipZigTest; - if (true) { - // https://github.com/ziglang/zig/issues/4922 - return error.SkipZigTest; - } - - var loop: Loop = undefined; - try loop.initMultiThreaded(); - defer loop.deinit(); - - // Schedule the execution, won't actually start until we start the - // event loop. - try loop.runDetached(std.testing.allocator, testRunDetached, .{}); - - // Now we can start the event loop. The function will return only - // after all tasks have been completed, allowing us to synchonize - // with the previous runDetached. - loop.run(); - - testing.expect(testRunDetachedData == 1); -} - -fn testRunDetached() void { - testRunDetachedData += 1; -} -- cgit v1.2.3 From 7f7e2d608adb81cd00e54fd7fe5e7035a890565f Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 5 Oct 2020 14:37:23 -0700 Subject: Revert "revert adding std.event.Loop.runDetached" This reverts commit 70f37679035e64bacfc4807709da37bc02fbb346. After discussion, I can see the value provided here, specifically with avoiding the footgun of defer { suspend { free(@frame()); } }. However the doc comments are updated to explain the semantics directly, rather than basing them on the behavior of another programming language. --- lib/std/event/loop.zig | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) (limited to 'lib/std/event/loop.zig') diff --git a/lib/std/event/loop.zig b/lib/std/event/loop.zig index 2ed9f938d8..226d5f1d52 100644 --- a/lib/std/event/loop.zig +++ b/lib/std/event/loop.zig @@ -647,6 +647,31 @@ pub const Loop = struct { } } + /// Runs the provided function asynchronously. The function's frame is allocated + /// with `allocator` and freed when the function returns. + /// `func` must return void and it can be an async function. + /// Yields to the event loop, running the function on the next tick. + pub fn runDetached(self: *Loop, alloc: *mem.Allocator, comptime func: anytype, args: anytype) error{OutOfMemory}!void { + if (!std.io.is_async) @compileError("Can't use runDetached in non-async mode!"); + if (@TypeOf(@call(.{}, func, args)) != void) { + @compileError("`func` must not have a return value"); + } + + const Wrapper = struct { + const Args = @TypeOf(args); + fn run(func_args: Args, loop: *Loop, allocator: *mem.Allocator) void { + loop.yield(); + const result = @call(.{}, func, func_args); + suspend { + allocator.destroy(@frame()); + } + } + }; + + var run_frame = try alloc.create(@Frame(Wrapper.run)); + run_frame.* = async Wrapper.run(args, self, alloc); + } + /// Yielding lets the event loop run, starting any unstarted async operations. /// Note that async operations automatically start when a function yields for any other reason, /// for example, when async I/O is performed. This function is intended to be used only when @@ -1493,3 +1518,33 @@ fn testEventLoop2(h: anyframe->i32, did_it: *bool) void { testing.expect(value == 1234); did_it.* = true; } + +var testRunDetachedData: usize = 0; +test "std.event.Loop - runDetached" { + // https://github.com/ziglang/zig/issues/1908 + if (builtin.single_threaded) return error.SkipZigTest; + if (!std.io.is_async) return error.SkipZigTest; + if (true) { + // https://github.com/ziglang/zig/issues/4922 + return error.SkipZigTest; + } + + var loop: Loop = undefined; + try loop.initMultiThreaded(); + defer loop.deinit(); + + // Schedule the execution, won't actually start until we start the + // event loop. + try loop.runDetached(std.testing.allocator, testRunDetached, .{}); + + // Now we can start the event loop. The function will return only + // after all tasks have been completed, allowing us to synchonize + // with the previous runDetached. + loop.run(); + + testing.expect(testRunDetachedData == 1); +} + +fn testRunDetached() void { + testRunDetachedData += 1; +} -- cgit v1.2.3