authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-03-24 18:49:03-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-07-20 10:38:38-07:00
log6ae18714b74a5267608e931b46db20be637ccb03
treebff34504b48c75d750b013fc9e8a07b7e3e62e20
parent5b2f54fc804cf097e673c8ba99cf4fb0a3b969ce

make thread pool satisfy async/await interface


1 files changed, 60 insertions(+), 2 deletions(-)

lib/std/Thread/Pool.zig+60-2
...@@ -1,7 +1,8 @@...@@ -1,7 +1,8 @@
1const std = @import("std");
2const builtin = @import("builtin");1const builtin = @import("builtin");
3const Pool = @This();2const std = @import("std");
3const assert = std.debug.assert;
4const WaitGroup = @import("WaitGroup.zig");4const WaitGroup = @import("WaitGroup.zig");
5const Pool = @This();
56
6mutex: std.Thread.Mutex = .{},7mutex: std.Thread.Mutex = .{},
7cond: std.Thread.Condition = .{},8cond: std.Thread.Condition = .{},
...@@ -307,3 +308,60 @@ pub fn waitAndWork(pool: *Pool, wait_group: *WaitGroup) void {...@@ -307,3 +308,60 @@ pub fn waitAndWork(pool: *Pool, wait_group: *WaitGroup) void {
307pub fn getIdCount(pool: *Pool) usize {308pub fn getIdCount(pool: *Pool) usize {
308 return @intCast(1 + pool.threads.len);309 return @intCast(1 + pool.threads.len);
309}310}
311
312const AsyncClosure = struct {
313 func: *const fn (context: ?*anyopaque, result: *anyopaque) void,
314 context: ?*anyopaque,
315 run_node: std.Thread.Pool.RunQueue.Node = .{ .data = .{ .runFn = runFn } },
316 reset_event: std.Thread.ResetEvent,
317
318 fn runFn(runnable: *std.Thread.Pool.Runnable, _: ?usize) void {
319 const run_node: *std.Thread.Pool.RunQueue.Node = @fieldParentPtr("data", runnable);
320 const closure: *@This() = @alignCast(@fieldParentPtr("run_node", run_node));
321 closure.func(closure.context, closure.resultPointer());
322 closure.reset_event.set();
323 }
324
325 fn resultPointer(closure: *@This()) [*]u8 {
326 const base: [*]u8 = @ptrCast(closure);
327 return base + @sizeOf(@This());
328 }
329};
330
331pub fn @"async"(
332 userdata: ?*anyopaque,
333 eager_result: []u8,
334 context: ?*anyopaque,
335 start: *const fn (context: ?*anyopaque, result: *anyopaque) void,
336) ?*std.Io.AnyFuture {
337 const pool: *std.Thread.Pool = @alignCast(@ptrCast(userdata));
338 pool.mutex.lock();
339
340 const gpa = pool.allocator;
341 const n = @sizeOf(AsyncClosure) + eager_result.len;
342 const closure: *AsyncClosure = @alignCast(@ptrCast(gpa.alignedAlloc(u8, @alignOf(AsyncClosure), n) catch {
343 pool.mutex.unlock();
344 start(context, eager_result.ptr);
345 return null;
346 }));
347 closure.* = .{
348 .func = start,
349 .context = context,
350 .reset_event = .{},
351 };
352 pool.run_queue.prepend(&closure.run_node);
353 pool.mutex.unlock();
354
355 pool.cond.signal();
356
357 return @ptrCast(closure);
358}
359
360pub fn @"await"(userdata: ?*anyopaque, any_future: *std.Io.AnyFuture, result: []u8) void {
361 const thread_pool: *std.Thread.Pool = @alignCast(@ptrCast(userdata));
362 const closure: *AsyncClosure = @ptrCast(@alignCast(any_future));
363 closure.reset_event.wait();
364 const base: [*]align(@alignOf(AsyncClosure)) u8 = @ptrCast(closure);
365 @memcpy(result, (base + @sizeOf(AsyncClosure))[0..result.len]);
366 thread_pool.allocator.free(base[0 .. @sizeOf(AsyncClosure) + result.len]);
367}