| ... | ... | @@ -647,6 +647,29 @@ pub const Loop = struct { |
| 647 | 647 | } |
| 648 | 648 | } |
| 649 | 649 | |
| 650 | /// Runs the provided function asynchonously, similarly to Go's "go" operator. |
| 651 | /// `func` must return void and it can be an async function. |
| 652 | fn runDetached(self: *Loop, alloc: *mem.Allocator, comptime func: anytype, args: anytype) error{OutOfMemory}!void { |
| 653 | if (!std.io.is_async) @compileError("Can't use runDetached in non-async mode!"); |
| 654 | if (@TypeOf(@call(.{}, func, args)) != void) { |
| 655 | @compileError("`func` must not have a return value"); |
| 656 | } |
| 657 | |
| 658 | const Wrapper = struct { |
| 659 | const Args = @TypeOf(args); |
| 660 | fn run(func_args: Args, loop: *Loop, allocator: *mem.Allocator) void { |
| 661 | loop.yield(); |
| 662 | const result = @call(.{}, func, func_args); |
| 663 | suspend { |
| 664 | allocator.destroy(@frame()); |
| 665 | } |
| 666 | } |
| 667 | }; |
| 668 | |
| 669 | var run_frame = try alloc.create(@Frame(Wrapper.run)); |
| 670 | run_frame.* = async Wrapper.run(args, self, alloc); |
| 671 | } |
| 672 | |
| 650 | 673 | /// Yielding lets the event loop run, starting any unstarted async operations. |
| 651 | 674 | /// Note that async operations automatically start when a function yields for any other reason, |
| 652 | 675 | /// 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 { |
| 1493 | 1516 | testing.expect(value == 1234); |
| 1494 | 1517 | did_it.* = true; |
| 1495 | 1518 | } |
| 1519 | |
| 1520 | var testRunDetachedData: usize = 0; |
| 1521 | test "std.event.Loop - runDetached" { |
| 1522 | // https://github.com/ziglang/zig/issues/1908 |
| 1523 | if (builtin.single_threaded) return error.SkipZigTest; |
| 1524 | if (!std.io.is_async) return error.SkipZigTest; |
| 1525 | if (true) { |
| 1526 | // https://github.com/ziglang/zig/issues/4922 |
| 1527 | return error.SkipZigTest; |
| 1528 | } |
| 1529 | |
| 1530 | var loop: Loop = undefined; |
| 1531 | try loop.initMultiThreaded(); |
| 1532 | defer loop.deinit(); |
| 1533 | |
| 1534 | // Schedule the execution, won't actually start until we start the |
| 1535 | // event loop. |
| 1536 | try loop.runDetached(std.testing.allocator, testRunDetached, .{}); |
| 1537 | |
| 1538 | // Now we can start the event loop. The function will return only |
| 1539 | // after all tasks have been completed, allowing us to synchonize |
| 1540 | // with the previous runDetached. |
| 1541 | loop.run(); |
| 1542 | |
| 1543 | testing.expect(testRunDetachedData == 1); |
| 1544 | } |
| 1545 | |
| 1546 | fn testRunDetached() void { |
| 1547 | testRunDetachedData += 1; |
| 1548 | } |