After discussion here, I have re-written my "demo" HTTP server with mio::TcpListener
The server can actually be shut down "cleanly" when SIGINT is retrieved.
Also, because there seems to be no other/better way with mio::TcpListener, we keep on reading the request until either a zero is read encountered, or the \r\n\r\n end marker was seen.
The server does not support HTTP/1.1 Pipelining, but browser support seems to be lacking anyway.
It's not clear to me what the match listener.canceller() expression is doing in Server::canceller. Why not replace this match expression with just listener.canceller()?
The implementation of Server::thread_main is kind of hard to parse (at least for me). It might benefit from some let Ok(_) = _ else { return ... }; statements or .map_err(...)?s.
It might be helpful for other people reading the code to annotate atomic accesses with why certain orderings were chosen.
That's mostly style-wise. I can't really comment on the correctness or design as I haven't looked at the code long enough.
It's not clear to me what the match listener.canceller() expression is doing in Server::canceller. Why not replace this match expression with just listener.canceller()?
Yeah, I think it's redundant and can be removed
The implementation of Server::thread_main is kind of hard to parse (at least for me). It might benefit from some let Ok(_) = _ else { return ... }; statements or .map_err(...)?s.
My feeling is that a match expression is usually preferred over if let...s + else, provided that we have more than one "case" to handle, because it leads to more condensed code.
It might be helpful for other people reading the code to annotate atomic accesses with why certain orderings were chosen.
I don't claim that I understand atomic memory ordering in full details
My understanding is that we should use "Release" if we write the atomic value; "Accquire" if we read the atomic value; and "AcqRel" to update (read + possibly write) the atomic value, as in compare-exchange.
Orderings affect how the atomic memory access relates to other memory accesses (atomic or otherwise). For example, you'd use Release if you were updating an atomic to signal that you had finished writing other memory (e.g. releasing a lock) and Acquire before reading that memory (acquiring the lock).
If you don't care about consistency with accesses to any other memory locations, which is usually the case for a cancellation flag (you only care that it eventually reads as true ) then you can use Relaxed for every access.
I just briefly skimmed it, but one tiny nit is that, if you're not using the const_format crate for anything else, why not replace your call to formatcp with a simple concat expression from the standard library? Unless you're planning to do something more complicated.