| author | |
| committer | |
| log | 5b2f54fc804cf097e673c8ba99cf4fb0a3b969ce |
| tree | df053b75143f61da239f5a671532473ca237216e |
| parent | f657767b600064c520fac0e72da6016508a8b601 |
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| ... | ... | @@ -911,3 +911,72 @@ test { |
| 911 | 911 | _ = @import("Io/stream_source.zig"); |
| 912 | 912 | _ = @import("Io/test.zig"); |
| 913 | 913 | } |
| 914 | ||
| 915 | const Io = @This(); | |
| 916 | ||
| 917 | userdata: ?*anyopaque, | |
| 918 | vtable: *const VTable, | |
| 919 | ||
| 920 | pub const VTable = struct { | |
| 921 | /// If it returns `null` it means `result` has been already populated and | |
| 922 | /// `await` will be a no-op. | |
| 923 | async: *const fn ( | |
| 924 | /// Corresponds to `Io.userdata`. | |
| 925 | userdata: ?*anyopaque, | |
| 926 | /// The pointer of this slice is an "eager" result value. | |
| 927 | /// The length is the size in bytes of the result type. | |
| 928 | eager_result: []u8, | |
| 929 | /// Passed to `start`. | |
| 930 | context: ?*anyopaque, | |
| 931 | start: *const fn (context: ?*anyopaque, result: *anyopaque) void, | |
| 932 | ) ?*AnyFuture, | |
| 933 | ||
| 934 | /// This function is only called when `async` returns a non-null value. | |
| 935 | await: *const fn ( | |
| 936 | /// Corresponds to `Io.userdata`. | |
| 937 | userdata: ?*anyopaque, | |
| 938 | /// The same value that was returned from `async`. | |
| 939 | any_future: *AnyFuture, | |
| 940 | /// Points to a buffer where the result is written. | |
| 941 | /// The length is equal to size in bytes of result type. | |
| 942 | result: []u8, | |
| 943 | ) void, | |
| 944 | }; | |
| 945 | ||
| 946 | pub const AnyFuture = opaque {}; | |
| 947 | ||
| 948 | pub fn Future(Result: type) type { | |
| 949 | return struct { | |
| 950 | any_future: ?*AnyFuture, | |
| 951 | result: Result, | |
| 952 | ||
| 953 | pub fn await(f: *@This(), io: Io) Result { | |
| 954 | const any_future = f.any_future orelse return f.result; | |
| 955 | io.vtable.await(io.userdata, any_future, @ptrCast((&f.result)[0..1])); | |
| 956 | f.any_future = null; | |
| 957 | return f.result; | |
| 958 | } | |
| 959 | }; | |
| 960 | } | |
| 961 | ||
| 962 | /// `s` is a struct instance that contains a function like this: | |
| 963 | /// ``` | |
| 964 | /// struct { | |
| 965 | /// pub fn start(s: S) Result { ... } | |
| 966 | /// } | |
| 967 | /// ``` | |
| 968 | /// where `Result` is any type. | |
| 969 | pub fn async(io: Io, s: anytype) Future(@typeInfo(@TypeOf(@TypeOf(s).start)).@"fn".return_type.?) { | |
| 970 | const S = @TypeOf(s); | |
| 971 | const Result = @typeInfo(@TypeOf(S.start)).@"fn".return_type.?; | |
| 972 | const TypeErased = struct { | |
| 973 | fn start(context: ?*anyopaque, result: *anyopaque) void { | |
| 974 | const context_casted: *const S = @alignCast(@ptrCast(context)); | |
| 975 | const result_casted: *Result = @ptrCast(@alignCast(result)); | |
| 976 | result_casted.* = S.start(context_casted.*); | |
| 977 | } | |
| 978 | }; | |
| 979 | var future: Future(Result) = undefined; | |
| 980 | future.any_future = io.vtable.async(io.userdata, @ptrCast((&future.result)[0..1]), @constCast(&s), TypeErased.start); | |
| 981 | return future; | |
| 982 | } |
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 | }; |