| ... | @@ -8,7 +8,6 @@ const windows = std.os.windows; | ... | @@ -8,7 +8,6 @@ const windows = std.os.windows; |
| 8 | const std = @import("../std.zig"); | 8 | const std = @import("../std.zig"); |
| 9 | const Allocator = std.mem.Allocator; | 9 | const Allocator = std.mem.Allocator; |
| 10 | const assert = std.debug.assert; | 10 | const assert = std.debug.assert; |
| 11 | const WaitGroup = std.Thread.WaitGroup; | | |
| 12 | const posix = std.posix; | 11 | const posix = std.posix; |
| 13 | const Io = std.Io; | 12 | const Io = std.Io; |
| 14 | | 13 | |
| ... | @@ -101,10 +100,12 @@ pub fn io(pool: *Pool) Io { | ... | @@ -101,10 +100,12 @@ pub fn io(pool: *Pool) Io { |
| 101 | .async = async, | 100 | .async = async, |
| 102 | .concurrent = concurrent, | 101 | .concurrent = concurrent, |
| 103 | .await = await, | 102 | .await = await, |
| 104 | .asyncDetached = asyncDetached, | | |
| 105 | .cancel = cancel, | 103 | .cancel = cancel, |
| 106 | .cancelRequested = cancelRequested, | 104 | .cancelRequested = cancelRequested, |
| 107 | .select = select, | 105 | .select = select, |
| | 106 | .groupAsync = groupAsync, |
| | 107 | .groupWait = groupWait, |
| | 108 | .groupCancel = groupCancel, |
| 108 | | 109 | |
| 109 | .mutexLock = mutexLock, | 110 | .mutexLock = mutexLock, |
| 110 | .mutexUnlock = mutexUnlock, | 111 | .mutexUnlock = mutexUnlock, |
| ... | @@ -279,7 +280,7 @@ fn async( | ... | @@ -279,7 +280,7 @@ fn async( |
| 279 | .func = start, | 280 | .func = start, |
| 280 | .context_offset = context_offset, | 281 | .context_offset = context_offset, |
| 281 | .result_offset = result_offset, | 282 | .result_offset = result_offset, |
| 282 | .reset_event = .{}, | 283 | .reset_event = .unset, |
| 283 | .cancel_tid = 0, | 284 | .cancel_tid = 0, |
| 284 | .select_condition = null, | 285 | .select_condition = null, |
| 285 | .runnable = .{ | 286 | .runnable = .{ |
| ... | @@ -347,7 +348,7 @@ fn concurrent( | ... | @@ -347,7 +348,7 @@ fn concurrent( |
| 347 | .func = start, | 348 | .func = start, |
| 348 | .context_offset = context_offset, | 349 | .context_offset = context_offset, |
| 349 | .result_offset = result_offset, | 350 | .result_offset = result_offset, |
| 350 | .reset_event = .{}, | 351 | .reset_event = .unset, |
| 351 | .cancel_tid = 0, | 352 | .cancel_tid = 0, |
| 352 | .select_condition = null, | 353 | .select_condition = null, |
| 353 | .runnable = .{ | 354 | .runnable = .{ |
| ... | @@ -385,41 +386,47 @@ fn concurrent( | ... | @@ -385,41 +386,47 @@ fn concurrent( |
| 385 | return @ptrCast(closure); | 386 | return @ptrCast(closure); |
| 386 | } | 387 | } |
| 387 | | 388 | |
| 388 | const DetachedClosure = struct { | 389 | const GroupClosure = struct { |
| 389 | pool: *Pool, | 390 | pool: *Pool, |
| | 391 | group: *Io.Group, |
| 390 | func: *const fn (context: *anyopaque) void, | 392 | func: *const fn (context: *anyopaque) void, |
| 391 | runnable: Runnable, | 393 | runnable: Runnable, |
| 392 | context_alignment: std.mem.Alignment, | 394 | context_alignment: std.mem.Alignment, |
| 393 | context_len: usize, | 395 | context_len: usize, |
| 394 | | 396 | |
| 395 | fn start(runnable: *Runnable) void { | 397 | fn start(runnable: *Runnable) void { |
| 396 | const closure: *DetachedClosure = @alignCast(@fieldParentPtr("runnable", runnable)); | 398 | const closure: *GroupClosure = @alignCast(@fieldParentPtr("runnable", runnable)); |
| 397 | closure.func(closure.contextPointer()); | 399 | closure.func(closure.contextPointer()); |
| | 400 | const group = closure.group; |
| 398 | const gpa = closure.pool.allocator; | 401 | const gpa = closure.pool.allocator; |
| 399 | free(closure, gpa); | 402 | free(closure, gpa); |
| | 403 | const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state); |
| | 404 | const reset_event: *std.Thread.ResetEvent = @ptrCast(&group.context); |
| | 405 | std.Thread.WaitGroup.finishStateless(group_state, reset_event); |
| 400 | } | 406 | } |
| 401 | | 407 | |
| 402 | fn free(closure: *DetachedClosure, gpa: Allocator) void { | 408 | fn free(closure: *GroupClosure, gpa: Allocator) void { |
| 403 | const base: [*]align(@alignOf(DetachedClosure)) u8 = @ptrCast(closure); | 409 | const base: [*]align(@alignOf(GroupClosure)) u8 = @ptrCast(closure); |
| 404 | gpa.free(base[0..contextEnd(closure.context_alignment, closure.context_len)]); | 410 | gpa.free(base[0..contextEnd(closure.context_alignment, closure.context_len)]); |
| 405 | } | 411 | } |
| 406 | | 412 | |
| 407 | fn contextOffset(context_alignment: std.mem.Alignment) usize { | 413 | fn contextOffset(context_alignment: std.mem.Alignment) usize { |
| 408 | return context_alignment.forward(@sizeOf(DetachedClosure)); | 414 | return context_alignment.forward(@sizeOf(GroupClosure)); |
| 409 | } | 415 | } |
| 410 | | 416 | |
| 411 | fn contextEnd(context_alignment: std.mem.Alignment, context_len: usize) usize { | 417 | fn contextEnd(context_alignment: std.mem.Alignment, context_len: usize) usize { |
| 412 | return contextOffset(context_alignment) + context_len; | 418 | return contextOffset(context_alignment) + context_len; |
| 413 | } | 419 | } |
| 414 | | 420 | |
| 415 | fn contextPointer(closure: *DetachedClosure) [*]u8 { | 421 | fn contextPointer(closure: *GroupClosure) [*]u8 { |
| 416 | const base: [*]u8 = @ptrCast(closure); | 422 | const base: [*]u8 = @ptrCast(closure); |
| 417 | return base + contextOffset(closure.context_alignment); | 423 | return base + contextOffset(closure.context_alignment); |
| 418 | } | 424 | } |
| 419 | }; | 425 | }; |
| 420 | | 426 | |
| 421 | fn asyncDetached( | 427 | fn groupAsync( |
| 422 | userdata: ?*anyopaque, | 428 | userdata: ?*anyopaque, |
| | 429 | group: *Io.Group, |
| 423 | context: []const u8, | 430 | context: []const u8, |
| 424 | context_alignment: std.mem.Alignment, | 431 | context_alignment: std.mem.Alignment, |
| 425 | start: *const fn (context: *const anyopaque) void, | 432 | start: *const fn (context: *const anyopaque) void, |
| ... | @@ -428,17 +435,18 @@ fn asyncDetached( | ... | @@ -428,17 +435,18 @@ fn asyncDetached( |
| 428 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 435 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 429 | const cpu_count = pool.cpu_count catch 1; | 436 | const cpu_count = pool.cpu_count catch 1; |
| 430 | const gpa = pool.allocator; | 437 | const gpa = pool.allocator; |
| 431 | const n = DetachedClosure.contextEnd(context_alignment, context.len); | 438 | const n = GroupClosure.contextEnd(context_alignment, context.len); |
| 432 | const closure: *DetachedClosure = @ptrCast(@alignCast(gpa.alignedAlloc(u8, .of(DetachedClosure), n) catch { | 439 | const closure: *GroupClosure = @ptrCast(@alignCast(gpa.alignedAlloc(u8, .of(GroupClosure), n) catch { |
| 433 | return start(context.ptr); | 440 | return start(context.ptr); |
| 434 | })); | 441 | })); |
| 435 | closure.* = .{ | 442 | closure.* = .{ |
| 436 | .pool = pool, | 443 | .pool = pool, |
| | 444 | .group = group, |
| 437 | .func = start, | 445 | .func = start, |
| 438 | .context_alignment = context_alignment, | 446 | .context_alignment = context_alignment, |
| 439 | .context_len = context.len, | 447 | .context_len = context.len, |
| 440 | .runnable = .{ | 448 | .runnable = .{ |
| 441 | .start = DetachedClosure.start, | 449 | .start = GroupClosure.start, |
| 442 | .is_parallel = false, | 450 | .is_parallel = false, |
| 443 | }, | 451 | }, |
| 444 | }; | 452 | }; |
| ... | @@ -466,10 +474,30 @@ fn asyncDetached( | ... | @@ -466,10 +474,30 @@ fn asyncDetached( |
| 466 | pool.threads.appendAssumeCapacity(thread); | 474 | pool.threads.appendAssumeCapacity(thread); |
| 467 | } | 475 | } |
| 468 | | 476 | |
| | 477 | const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state); |
| | 478 | std.Thread.WaitGroup.startStateless(group_state); |
| | 479 | |
| 469 | pool.mutex.unlock(); | 480 | pool.mutex.unlock(); |
| 470 | pool.cond.signal(); | 481 | pool.cond.signal(); |
| 471 | } | 482 | } |
| 472 | | 483 | |
| | 484 | fn groupWait(userdata: ?*anyopaque, group: *Io.Group) void { |
| | 485 | if (builtin.single_threaded) return; |
| | 486 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| | 487 | _ = pool; |
| | 488 | const group_state: *std.atomic.Value(usize) = @ptrCast(&group.state); |
| | 489 | const reset_event: *std.Thread.ResetEvent = @ptrCast(&group.context); |
| | 490 | std.Thread.WaitGroup.waitStateless(group_state, reset_event); |
| | 491 | } |
| | 492 | |
| | 493 | fn groupCancel(userdata: ?*anyopaque, group: *Io.Group) void { |
| | 494 | if (builtin.single_threaded) return; |
| | 495 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| | 496 | _ = pool; |
| | 497 | _ = group; |
| | 498 | @panic("TODO threaded group cancel"); |
| | 499 | } |
| | 500 | |
| 473 | fn await( | 501 | fn await( |
| 474 | userdata: ?*anyopaque, | 502 | userdata: ?*anyopaque, |
| 475 | any_future: *Io.AnyFuture, | 503 | any_future: *Io.AnyFuture, |
| ... | @@ -968,7 +996,7 @@ fn select(userdata: ?*anyopaque, futures: []const *Io.AnyFuture) usize { | ... | @@ -968,7 +996,7 @@ fn select(userdata: ?*anyopaque, futures: []const *Io.AnyFuture) usize { |
| 968 | const pool: *Pool = @ptrCast(@alignCast(userdata)); | 996 | const pool: *Pool = @ptrCast(@alignCast(userdata)); |
| 969 | _ = pool; | 997 | _ = pool; |
| 970 | | 998 | |
| 971 | var reset_event: std.Thread.ResetEvent = .{}; | 999 | var reset_event: std.Thread.ResetEvent = .unset; |
| 972 | | 1000 | |
| 973 | for (futures, 0..) |future, i| { | 1001 | for (futures, 0..) |future, i| { |
| 974 | const closure: *AsyncClosure = @ptrCast(@alignCast(future)); | 1002 | const closure: *AsyncClosure = @ptrCast(@alignCast(future)); |