| ... | @@ -150,7 +150,7 @@ pub const VTable = struct { | ... | @@ -150,7 +150,7 @@ pub const VTable = struct { |
| 150 | futexWake: *const fn (?*anyopaque, ptr: *const u32, max_waiters: u32) void, | 150 | futexWake: *const fn (?*anyopaque, ptr: *const u32, max_waiters: u32) void, |
| 151 | | 151 | |
| 152 | operate: *const fn (?*anyopaque, Operation) Cancelable!Operation.Result, | 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 | batchAwaitConcurrent: *const fn (?*anyopaque, *Batch, Timeout) Batch.AwaitConcurrentError!void, | 154 | batchAwaitConcurrent: *const fn (?*anyopaque, *Batch, Timeout) Batch.AwaitConcurrentError!void, |
| 155 | batchCancel: *const fn (?*anyopaque, *Batch) void, | 155 | batchCancel: *const fn (?*anyopaque, *Batch) void, |
| 156 | | 156 | |
| ... | @@ -359,7 +359,7 @@ pub fn operate(io: Io, operation: Operation) Cancelable!Operation.Result { | ... | @@ -359,7 +359,7 @@ pub fn operate(io: Io, operation: Operation) Cancelable!Operation.Result { |
| 359 | /// complete. | 359 | /// complete. |
| 360 | /// | 360 | /// |
| 361 | /// This is a low-level abstraction based on `Operation`. For a higher | 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 | pub const Batch = struct { | 363 | pub const Batch = struct { |
| 364 | storage: []Operation.Storage, | 364 | storage: []Operation.Storage, |
| 365 | unused: Operation.List, | 365 | unused: Operation.List, |
| ... | @@ -422,6 +422,11 @@ pub const Batch = struct { | ... | @@ -422,6 +422,11 @@ pub const Batch = struct { |
| 422 | b.submissions.tail = .fromIndex(index); | 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 | pub fn next(b: *Batch) ?struct { index: u32, result: Operation.Result } { | 430 | pub fn next(b: *Batch) ?struct { index: u32, result: Operation.Result } { |
| 426 | const index = b.completions.head; | 431 | const index = b.completions.head; |
| 427 | if (index == .none) return null; | 432 | if (index == .none) return null; |
| ... | @@ -441,16 +446,37 @@ pub const Batch = struct { | ... | @@ -441,16 +446,37 @@ pub const Batch = struct { |
| 441 | return .{ .index = index.toIndex(), .result = completion.result }; | 446 | return .{ .index = index.toIndex(), .result = completion.result }; |
| 442 | } | 447 | } |
| 443 | | 448 | |
| 444 | pub const AwaitAsyncError = Cancelable; | 449 | /// Waits for at least one of the submitted operations to complete. After |
| 445 | pub fn awaitAsync(b: *Batch, io: Io) AwaitAsyncError!void { | 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 | return io.vtable.batchAwaitAsync(io.userdata, b); | 458 | return io.vtable.batchAwaitAsync(io.userdata, b); |
| 447 | } | 459 | } |
| 448 | | 460 | |
| 449 | pub const AwaitConcurrentError = ConcurrentError || Cancelable || Timeout.Error; | 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 | pub fn awaitConcurrent(b: *Batch, io: Io, timeout: Timeout) AwaitConcurrentError!void { | 470 | pub fn awaitConcurrent(b: *Batch, io: Io, timeout: Timeout) AwaitConcurrentError!void { |
| 451 | return io.vtable.batchAwaitConcurrent(io.userdata, b, timeout); | 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 | pub fn cancel(b: *Batch, io: Io) void { | 480 | pub fn cancel(b: *Batch, io: Io) void { |
| 455 | return io.vtable.batchCancel(io.userdata, b); | 481 | return io.vtable.batchCancel(io.userdata, b); |
| 456 | } | 482 | } |