diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2020-10-05 14:37:23 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2020-10-05 14:41:51 -0700 |
| commit | 7f7e2d608adb81cd00e54fd7fe5e7035a890565f (patch) | |
| tree | b23fa4dd6a1a65a289e618c7853453f77f720c6e /lib/std/event | |
| parent | 939b4860ef2990ba453842033475a18f14a5b72e (diff) | |
| download | zig-7f7e2d608adb81cd00e54fd7fe5e7035a890565f.tar.gz zig-7f7e2d608adb81cd00e54fd7fe5e7035a890565f.zip | |
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.
Diffstat (limited to 'lib/std/event')
| -rw-r--r-- | lib/std/event/loop.zig | 55 |
1 files changed, 55 insertions, 0 deletions
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; +} |
