| author | |
| committer | |
| log | 63c554d5a796d181f9b73ec19b8d9a22de98a1fc |
| tree | 8e454b1e44ed8d101a5ff1c6f9714c67c0c0686b |
| parent | bc4da9a90743c11c7c0b3e485f46d365d57d87b7 |
which is planned to have all I/O operations in the interface, but for
now has only async and await.2 files changed, 72 insertions(+), 20 deletions(-)
lib/std/Io.zig+69| ... | ... | @@ -553,3 +553,72 @@ test { |
| 553 | 553 | _ = tty; |
| 554 | 554 | _ = @import("Io/test.zig"); |
| 555 | 555 | } |
| 556 | ||
| 557 | const Io = @This(); | |
| 558 | ||
| 559 | userdata: ?*anyopaque, | |
| 560 | vtable: *const VTable, | |
| 561 | ||
| 562 | pub const VTable = struct { | |
| 563 | /// If it returns `null` it means `result` has been already populated and | |
| 564 | /// `await` will be a no-op. | |
| 565 | async: *const fn ( | |
| 566 | /// Corresponds to `Io.userdata`. | |
| 567 | userdata: ?*anyopaque, | |
| 568 | /// The pointer of this slice is an "eager" result value. | |
| 569 | /// The length is the size in bytes of the result type. | |
| 570 | eager_result: []u8, | |
| 571 | /// Passed to `start`. | |
| 572 | context: ?*anyopaque, | |
| 573 | start: *const fn (context: ?*anyopaque, result: *anyopaque) void, | |
| 574 | ) ?*AnyFuture, | |
| 575 | ||
| 576 | /// This function is only called when `async` returns a non-null value. | |
| 577 | await: *const fn ( | |
| 578 | /// Corresponds to `Io.userdata`. | |
| 579 | userdata: ?*anyopaque, | |
| 580 | /// The same value that was returned from `async`. | |
| 581 | any_future: *AnyFuture, | |
| 582 | /// Points to a buffer where the result is written. | |
| 583 | /// The length is equal to size in bytes of result type. | |
| 584 | result: []u8, | |
| 585 | ) void, | |
| 586 | }; | |
| 587 | ||
| 588 | pub const AnyFuture = opaque {}; | |
| 589 | ||
| 590 | pub fn Future(Result: type) type { | |
| 591 | return struct { | |
| 592 | any_future: ?*AnyFuture, | |
| 593 | result: Result, | |
| 594 | ||
| 595 | pub fn await(f: *@This(), io: Io) Result { | |
| 596 | const any_future = f.any_future orelse return f.result; | |
| 597 | io.vtable.await(io.userdata, any_future, @ptrCast((&f.result)[0..1])); | |
| 598 | f.any_future = null; | |
| 599 | return f.result; | |
| 600 | } | |
| 601 | }; | |
| 602 | } | |
| 603 | ||
| 604 | /// `s` is a struct instance that contains a function like this: | |
| 605 | /// ``` | |
| 606 | /// struct { | |
| 607 | /// pub fn start(s: S) Result { ... } | |
| 608 | /// } | |
| 609 | /// ``` | |
| 610 | /// where `Result` is any type. | |
| 611 | pub fn async(io: Io, s: anytype) Future(@typeInfo(@TypeOf(@TypeOf(s).start)).@"fn".return_type.?) { | |
| 612 | const S = @TypeOf(s); | |
| 613 | const Result = @typeInfo(@TypeOf(S.start)).@"fn".return_type.?; | |
| 614 | const TypeErased = struct { | |
| 615 | fn start(context: ?*anyopaque, result: *anyopaque) void { | |
| 616 | const context_casted: *const S = @alignCast(@ptrCast(context)); | |
| 617 | const result_casted: *Result = @ptrCast(@alignCast(result)); | |
| 618 | result_casted.* = S.start(context_casted.*); | |
| 619 | } | |
| 620 | }; | |
| 621 | var future: Future(Result) = undefined; | |
| 622 | future.any_future = io.vtable.async(io.userdata, @ptrCast((&future.result)[0..1]), @constCast(&s), TypeErased.start); | |
| 623 | return future; | |
| 624 | } |
lib/std/Thread/Pool.zig+3-20| ... | ... | @@ -7,6 +7,7 @@ mutex: std.Thread.Mutex = .{}, |
| 7 | 7 | cond: std.Thread.Condition = .{}, |
| 8 | 8 | run_queue: std.SinglyLinkedList = .{}, |
| 9 | 9 | is_running: bool = true, |
| 10 | /// Must be a thread-safe allocator. | |
| 10 | 11 | allocator: std.mem.Allocator, |
| 11 | 12 | threads: if (builtin.single_threaded) [0]std.Thread else []std.Thread, |
| 12 | 13 | ids: if (builtin.single_threaded) struct { |
| ... | ... | @@ -16,12 +17,12 @@ ids: if (builtin.single_threaded) struct { |
| 16 | 17 | } |
| 17 | 18 | } else std.AutoArrayHashMapUnmanaged(std.Thread.Id, void), |
| 18 | 19 | |
| 19 | const Runnable = struct { | |
| 20 | pub const Runnable = struct { | |
| 20 | 21 | runFn: RunProto, |
| 21 | 22 | node: std.SinglyLinkedList.Node = .{}, |
| 22 | 23 | }; |
| 23 | 24 | |
| 24 | const RunProto = *const fn (*Runnable, id: ?usize) void; | |
| 25 | pub const RunProto = *const fn (*Runnable, id: ?usize) void; | |
| 25 | 26 | |
| 26 | 27 | pub const Options = struct { |
| 27 | 28 | allocator: std.mem.Allocator, |
| ... | ... | @@ -117,12 +118,6 @@ pub fn spawnWg(pool: *Pool, wait_group: *WaitGroup, comptime func: anytype, args |
| 117 | 118 | const closure: *@This() = @alignCast(@fieldParentPtr("runnable", runnable)); |
| 118 | 119 | @call(.auto, func, closure.arguments); |
| 119 | 120 | closure.wait_group.finish(); |
| 120 | ||
| 121 | // The thread pool's allocator is protected by the mutex. | |
| 122 | const mutex = &closure.pool.mutex; | |
| 123 | mutex.lock(); | |
| 124 | defer mutex.unlock(); | |
| 125 | ||
| 126 | 121 | closure.pool.allocator.destroy(closure); |
| 127 | 122 | } |
| 128 | 123 | }; |
| ... | ... | @@ -179,12 +174,6 @@ pub fn spawnWgId(pool: *Pool, wait_group: *WaitGroup, comptime func: anytype, ar |
| 179 | 174 | const closure: *@This() = @alignCast(@fieldParentPtr("runnable", runnable)); |
| 180 | 175 | @call(.auto, func, .{id.?} ++ closure.arguments); |
| 181 | 176 | closure.wait_group.finish(); |
| 182 | ||
| 183 | // The thread pool's allocator is protected by the mutex. | |
| 184 | const mutex = &closure.pool.mutex; | |
| 185 | mutex.lock(); | |
| 186 | defer mutex.unlock(); | |
| 187 | ||
| 188 | 177 | closure.pool.allocator.destroy(closure); |
| 189 | 178 | } |
| 190 | 179 | }; |
| ... | ... | @@ -228,12 +217,6 @@ pub fn spawn(pool: *Pool, comptime func: anytype, args: anytype) !void { |
| 228 | 217 | fn runFn(runnable: *Runnable, _: ?usize) void { |
| 229 | 218 | const closure: *@This() = @alignCast(@fieldParentPtr("runnable", runnable)); |
| 230 | 219 | @call(.auto, func, closure.arguments); |
| 231 | ||
| 232 | // The thread pool's allocator is protected by the mutex. | |
| 233 | const mutex = &closure.pool.mutex; | |
| 234 | mutex.lock(); | |
| 235 | defer mutex.unlock(); | |
| 236 | ||
| 237 | 220 | closure.pool.allocator.destroy(closure); |
| 238 | 221 | } |
| 239 | 222 | }; |