| ... | ... | @@ -150,7 +150,7 @@ pub const VTable = struct { |
| 150 | 150 | futexWake: *const fn (?*anyopaque, ptr: *const u32, max_waiters: u32) void, |
| 151 | 151 | |
| 152 | 152 | operate: *const fn (?*anyopaque, Operation) Cancelable!Operation.Result, |
| 153 | | batchAwaitAsync: *const fn (?*anyopaque, *Batch) Batch.AwaitAsyncError!void, |
| 153 | batchAwaitAsync: *const fn (?*anyopaque, *Batch) Cancelable!void, |
| 154 | 154 | batchAwaitConcurrent: *const fn (?*anyopaque, *Batch, Timeout) Batch.AwaitConcurrentError!void, |
| 155 | 155 | batchCancel: *const fn (?*anyopaque, *Batch) void, |
| 156 | 156 | |
| ... | ... | @@ -359,7 +359,7 @@ pub fn operate(io: Io, operation: Operation) Cancelable!Operation.Result { |
| 359 | 359 | /// complete. |
| 360 | 360 | /// |
| 361 | 361 | /// This is a low-level abstraction based on `Operation`. For a higher |
| 362 | | /// level API that operates on `Future`, see `Select`. |
| 362 | /// level API that operates on `Future`, see `Select` and `Group`. |
| 363 | 363 | pub const Batch = struct { |
| 364 | 364 | storage: []Operation.Storage, |
| 365 | 365 | unused: Operation.List, |
| ... | ... | @@ -422,6 +422,11 @@ pub const Batch = struct { |
| 422 | 422 | b.submissions.tail = .fromIndex(index); |
| 423 | 423 | } |
| 424 | 424 | |
| 425 | /// After calling `awaitAsync`, `awaitConcurrent`, or `cancel`, this |
| 426 | /// function iterates over the completed operations. |
| 427 | /// |
| 428 | /// Each completion returned from this function dequeues from the `Batch`. |
| 429 | /// It is not required to dequeue all completions before awaiting again. |
| 425 | 430 | pub fn next(b: *Batch) ?struct { index: u32, result: Operation.Result } { |
| 426 | 431 | const index = b.completions.head; |
| 427 | 432 | if (index == .none) return null; |
| ... | ... | @@ -441,16 +446,37 @@ pub const Batch = struct { |
| 441 | 446 | return .{ .index = index.toIndex(), .result = completion.result }; |
| 442 | 447 | } |
| 443 | 448 | |
| 444 | | pub const AwaitAsyncError = Cancelable; |
| 445 | | pub fn awaitAsync(b: *Batch, io: Io) AwaitAsyncError!void { |
| 449 | /// Waits for at least one of the submitted operations to complete. After |
| 450 | /// this function returns the completed operations can be iterated with |
| 451 | /// `next`. |
| 452 | /// |
| 453 | /// This function provides opportunity for the implementation to introduce |
| 454 | /// concurrency into the batched operations, but unlike `awaitConcurrent`, |
| 455 | /// does not require it, and therefore cannot fail with |
| 456 | /// `error.ConcurrencyUnavailable`. |
| 457 | pub fn awaitAsync(b: *Batch, io: Io) Cancelable!void { |
| 446 | 458 | return io.vtable.batchAwaitAsync(io.userdata, b); |
| 447 | 459 | } |
| 448 | 460 | |
| 449 | 461 | pub const AwaitConcurrentError = ConcurrentError || Cancelable || Timeout.Error; |
| 462 | |
| 463 | /// Waits for at least one of the submitted operations to complete. After |
| 464 | /// this function returns the completed operations can be iterated with |
| 465 | /// `next`. |
| 466 | /// |
| 467 | /// Unlike `awaitAsync`, this function requires the implementation to |
| 468 | /// perform the operations concurrently and therefore can fail with |
| 469 | /// `error.ConcurrencyUnavailable`. |
| 450 | 470 | pub fn awaitConcurrent(b: *Batch, io: Io, timeout: Timeout) AwaitConcurrentError!void { |
| 451 | 471 | return io.vtable.batchAwaitConcurrent(io.userdata, b, timeout); |
| 452 | 472 | } |
| 453 | 473 | |
| 474 | /// Requests all pending operations to be interrupted, then waits for all |
| 475 | /// pending operations to complete. After this returns, the `Batch` is in a |
| 476 | /// well-defined state, ready to be iterated with `next`. Successfully |
| 477 | /// canceled operations will be absent from the iteration. Some operations |
| 478 | /// may have successfully completed regardless of the cancel request and |
| 479 | /// will appear in the iteration. |
| 454 | 480 | pub fn cancel(b: *Batch, io: Io) void { |
| 455 | 481 | return io.vtable.batchCancel(io.userdata, b); |
| 456 | 482 | } |