Repository navigation
Cancellation: one kind, and a write says how much it has taken - #42
Merged
Merged
Conversation
There is one kind of cancellation: it completes the operation right away, whatever that leaves behind, the same as a stop request on COROSIO. That is Asio's terminal type. A request for partial or total alone promises a state that a cancelled write cannot always keep, so on_cancel() now ignores it, which is what Asio asks of an operation that does not support a type, and what its own coroutines do by default. cancel_after sends terminal and || sends all three, so neither notices. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A cancelled write completes right away, and so far said nothing but that. Where the message is still usable afterwards, the caller cannot go on without knowing where the write stopped, so Write is void(error_code, size_t) now, and write() and write_eof() yield IoTask<size_t>: all of the buffer on success, none when the entry ladder answers, and otherwise what the writer has taken -- copied by nghttp2 version 1, copied in Staged and framed or handed to the stack in ZeroCopy on HTTP/2 version 2 and HTTP/3, and over HTTP/1.1 the body bytes that reached the connection, which h1::write_some() counts among the header and chunk framing Beast hands out. On COROSIO, Writer::write_some() passes that on, where it reported 0 for any error. Cancelling write_eof() before nghttp2 has been told about the end now takes the end back on HTTP/2, as HTTP/3 already did, so that write_eof(buffer + n) finishes the body after any cancelled write, on every protocol. Until now a data write after it failed with broken_pipe there, and only a bare re-end was possible. The callers in the library, the programs, the tests and the snippets take the count; send() counts what was actually taken. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On ASIO, a request for partial or total cancellation alone leaves a read running, and terminal completes it. A cancelled read_some() can be followed by reading the rest of the body. A write cancelled while the server is not reading says how much of an 8 MiB body it has taken, and write_eof(buffer + n) then gets the whole body across intact, after write() as after write_eof(). HTTP/1.1 skips the last two, as its cancelled write ends the connection. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A page of its own for what used to be a list of cases in the guide. There are three ways to stop something in progress: cancelling one operation, which completes right away, abandoning a message or session by destroying its handle, and draining, the ordinary operations that finish what was started and may wait for the peer. The page has what a cancelled operation promises, what each one leaves behind, how writes differ by protocol, and how to finish a body after a cancelled write. The guide points there now, and end-of-body.rst says what cancelling write_eof() does to the end of the body since it is taken back where the stack has not been given it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A new file for what runtime.hpp offers generic code, with the same expectations on both runtimes. A delay cancelled from outside completes right away with operation_canceled: on ASIO through a terminal signal on its completion's slot, on COROSIO through its stop token. when_either() does not wait for the delay it cancels. On ASIO, partial or total alone does not reach the timer, since co_spawn() lets only terminal cancellation through by default. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A cancelled operation now promises one thing on both runtimes: it completes right away, with
operation_canceled, and a write reports how much of its buffer it has taken, so that the body can still be finished where the message is still usable.Changes
Only terminal cancellation cancels a parked operation on ASIO (65febe7).
on_cancel()ignores a request forpartialortotalalone, which is what Asio asks of an operation that can't guarantee what those types promise, and what its own coroutines do by default.cancel_aftersends terminal and||sends all three, so neither is affected.A write says how much of its buffer it has taken (f82a6d7). API change:
Writeisvoid(error_code, size_t), andwrite()/write_eof()yieldIoTask<size_t>. On success that is all of the buffer; after a cancellation it is what the protocol has taken:On HTTP/2, cancelling
write_eof()before nghttp2 has seen the end now takes the end back, as HTTP/3 already did. Sowrite_eof(buffer + n)finishes the body after any cancelled write, on every protocol.Tests for what a cancelled operation promises (c9c53c4):
partial/totalalone leave a read running, and terminal completes itread_some()can be followed by reading the rest of the bodyn, andwrite_eof(buffer + n)then gets the whole body across intact (HTTP/1.1 skips this one, because a cancelled write there ends the connection)docs/cancellation.rst(14556f7): a page on cancelling, abandoning and draining. It covers what a cancelled operation promises, what each operation leaves behind, how writes differ by protocol, and how to finish a body after a cancelled write. The programmer's guide andend-of-body.rstnow link to it.test/test_runtime.cpp(df5c9dd):delay()can be cancelled on both runtimes,when_either()doesn't wait for the delay it cancels, and on ASIOpartial/totalalone don't reach the timer.Testing
build/(ASIO) andbuild-corosio/pass the new runtime tests. CI runs the full matrix.🤖 Generated with Claude Code