|
Flow-IPC 3.0.0
Flow-IPC project: Public API.
|
sync_io-pattern counterparts to async-I/O-pattern object types in parent namespace ipc::transport.
More...
Classes | |
| class | Async_adapter_receiver |
| Type that adapts a given PEER-state sync_io::Native_handle_receiver or sync_io::Blob_receiver core into the async-I/O-pattern Native_handle_receiver or Blob_receiver. More... | |
| class | Async_adapter_sender |
| Type that adapts a given PEER-state sync_io::Native_handle_sender or sync_io::Blob_sender core into the async-I/O-pattern Native_handle_sender or Blob_sender. More... | |
| class | Blob_receiver |
| A documentation-only concept: what transport::Blob_receiver is to transport::Native_handle_receiver (namely a degenerate version thereof), this is to sync_io::Native_handle_receiver. More... | |
| class | Blob_sender |
| A documentation-only concept: what transport::Blob_sender is to transport::Native_handle_sender (namely a degenerate version thereof), this is to sync_io::Native_handle_sender. More... | |
| class | Blob_stream_mq_receiver |
| Implements sync_io::Blob_receiver concept by using an adopted Persistent_mq_handle MQ handle to an MQ (message queue) of that type, such as a POSIX or bipc MQ. More... | |
| class | Blob_stream_mq_sender |
| Implements sync_io::Blob_sender concept by using an adopted Persistent_mq_handle MQ handle to an MQ (message queue) of that type, such as a POSIX or bipc MQ. More... | |
| class | Native_handle_receiver |
A documentation-only concept defining the behavior of an object that is the sync_io-pattern counterpart of the async-I/O-pattern-following concept of the same name in our parent namespace: transport::Native_handle_receiver. More... | |
| class | Native_handle_sender |
A documentation-only concept defining the behavior of an object that is the sync_io-pattern counterpart of the async-I/O-pattern-following concept of the same name in our parent namespace: transport::Native_handle_sender. More... | |
| class | Native_socket_stream |
| Implements both sync_io::Native_handle_sender and sync_io::Native_handle_receiver concepts by using a Unix domain socket, allowing high-performance but non-zero-copy transmission of discrete messages, each containing a native handle, a binary blob, or both. More... | |
| class | Native_socket_stream_acceptor |
sync_io-pattern counterpart to async-I/O-pattern transport::Native_socket_stream_acceptor. More... | |
Typedefs | |
| using | Posix_mq_sender = Blob_stream_mq_sender< Posix_mq_handle > |
| Convenience alias: sync_io::Blob_sender via unidirectional POSIX MQ (message queue). | |
| using | Posix_mq_receiver = Blob_stream_mq_receiver< Posix_mq_handle > |
| Convenience alias: sync_io::Blob_receiver via unidirectional POSIX MQ (message queue). | |
| using | Bipc_mq_sender = Blob_stream_mq_sender< Bipc_mq_handle > |
| Convenience alias: sync_io::Blob_sender via unidirectional bipc MQ (message queue). | |
| using | Bipc_mq_receiver = Blob_stream_mq_receiver< Bipc_mq_handle > |
| Convenience alias: sync_io::Blob_receiver via unidirectional bipc MQ (message queue). | |
| using | Posix_mqs_channel_of_blobs = transport::Mqs_channel< true, Posix_mq_handle > |
| Convenience alias: Channel peer (sync_io::Blob_sender, sync_io::Blob_receiver) at one end of full-duplex (bidirectional) pipe composed of 2 opposite-facing unidirectional POSIX MQs (message queues). | |
| using | Bipc_mqs_channel_of_blobs = transport::Mqs_channel< true, Bipc_mq_handle > |
| Convenience alias: Channel peer (sync_io::Blob_sender, sync_io::Blob_receiver) at one end of full-duplex (bidirectional) pipe composed of 2 opposite-facing unidirectional POSIX MQs (message queues). | |
| using | Posix_mqs_socket_stream_channel = Mqs_socket_stream_channel< true, Posix_mq_handle > |
| Convenience alias: Channel peer (sync_io::Blob_sender, sync_io::Blob_receiver, sync_io::Native_handle_sender, sync_io::Native_handle_receiver) at one end of a full-duplex (bidirectional) pipe composed of 2 opposite-facing unidirectional POSIX MQs (message queues), transmitting blobs only; and a full-duplex pipe over a Unix domain stream connection, transmitting native-handle-and/or-meta-blob messages. | |
| using | Bipc_mqs_socket_stream_channel = Mqs_socket_stream_channel< true, Bipc_mq_handle > |
| Convenience alias: Channel peer (sync_io::Blob_sender, sync_io::Blob_receiver, sync_io::Native_handle_sender, sync_io::Native_handle_receiver) at one end of a full-duplex (bidirectional) pipe composed of 2 opposite-facing unidirectional bipc MQs (message queues), transmitting blobs only; and a full-duplex pipe over a Unix domain stream connection, transmitting native-handle-and/or-meta-blob messages. | |
Functions | |
| template<bool NO_HNDLS, typename Batch , typename Task_err , typename Async_rcv_impl_func > | |
| void | async_receive_batch_emulation (flow::log::Logger *logger_ptr, Batch *batch, bool assume_would_block, Error_code *sync_err_code, Task_err &&on_done_func, Async_rcv_impl_func &&async_rcv_impl_func) |
Implements {Native_handle|Blob}_receiver::async_receive_*_batch() by emulating batch-receiving as a series of single-message receive-ops. More... | |
| template<typename Persistent_mq_handle > | |
| std::ostream & | operator<< (std::ostream &os, const Blob_stream_mq_receiver< Persistent_mq_handle > &val) |
Prints string representation of the given Blob_stream_mq_receiver to the given ostream. More... | |
| template<typename Persistent_mq_handle > | |
| std::ostream & | operator<< (std::ostream &os, const Blob_stream_mq_sender< Persistent_mq_handle > &val) |
Prints string representation of the given Blob_stream_mq_sender to the given ostream. More... | |
| std::ostream & | operator<< (std::ostream &os, const Native_socket_stream &val) |
Prints string representation of the given Native_socket_stream to the given ostream. More... | |
| std::ostream & | operator<< (std::ostream &os, const Native_socket_stream_acceptor &val) |
Prints string representation of the given Native_socket_stream_acceptor to the given ostream. More... | |
sync_io-pattern counterparts to async-I/O-pattern object types in parent namespace ipc::transport.
For example transport::sync_io::Native_socket_stream <=> transport::Native_socket_stream.
sync_io pattern we are following. | void ipc::transport::sync_io::async_receive_batch_emulation | ( | flow::log::Logger * | logger_ptr, |
| Batch * | batch, | ||
| bool | assume_would_block, | ||
| Error_code * | sync_err_code, | ||
| Task_err && | on_done_func, | ||
| Async_rcv_impl_func && | async_rcv_impl_func | ||
| ) |
Implements {Native_handle|Blob}_receiver::async_receive_*_batch() by emulating batch-receiving as a series of single-message receive-ops.
Just call us; we'll do it. The main requirement is to provide a proper async_rcv_impl_func() which shall perform a regular one-message receive.
The formal requirements for async_rcv_impl_func() are as follows. It shall be called in a void context and have the following arguments, in order:
NO_HNDLS == false) Native_handle*: Target handle object.bool: If true, your function may assume the pipe is in would-block state already which may help it be more efficient in doing its task; otherwise it must make no such assumption. (This will not simply always equal the eponymous argument to async_receive_batch_emulation()!)Error_code*: The error-code object for the op. This shall not be null (you do not need to throw an exception to emit an error).size_t*: Set the pointee to the received in-blob's size, unless an error is emitted.flow::async::Task_asio_err_sz, a/k/a Function<void (const Error_code& err_code, size_t n_rcvd)>. Attention! This may, or may not, be .empty(). See below.It shall act as-if {Native_handle|Blob}_receiver::async_receive_{native_handle|blob}() was called, except:
NO_HNDLS.Native_handle* arg (see above) if NO_HNDLS == false.start_*_ops() has been called, no pipe-hosing error recorded yet from prior ops, no async_receive_*() already outstanding, batch->initialized() && (!batch->full()).bool arg (assume-would-block; see above).E, and the desired outcome if 1+ in-messages have already been received successfully into *batch is delayed error (emit no error for this batch-receive, but next async-receive on that in-pipe shall instantly yield E), then E must be one of the following:boost::asio::error::eof.E in that situation will cause the batch-receive to emit E (and therefore leave batch->n_used() unchanged); 1+ in-messages shall be eaten. (Promise: any Native_handles received with the eaten in-messages shall be closed – returned to the OS – not leaked.).empty(). If it's non-empty, act normally. If it's empty, and no would-block is encountered, act normally; which is to say synchronously emit the result, and that's that (on-done handler ignored). If it's empty, and would-block is encountered then there are 2 possibilities.Unfortunately that last bullet point can be tricky to implement (or even understand what it means), so we must discuss. Firstly the (potential) good news: If your protocol combined with the underlying transport is such that reading a partial in-message is impossible, and (non-hosed) pipe state is the same regardless of where a would-block occurs, then the bullet point cannot apply, and things (your code) remain simple.
Example: Native_socket_stream, when operating (and this is determined at compile-time, not run-time) in datagram mode (asio_local_stream_socket::Protocol_pkt_stream, not Protocol_byte_stream; a/k/a in Linux SOCK_SEQPACKET, not SOCK_STREAM) can (and in our impl as of this writing does) map each in-message to one in-datagram, and the pipe is always in the same state (barring being hosed) upon receiving any in-dgram.
However if it possible to read a payload which encodes (potentially) part of an in-message/non-steady state, then the bullet point may apply, and you must code for it.
Example: Blob_stream_mq_receiver is essentially dgram-based too, so each in-message maps to one lower-level dgram (MQ message), but as of this writing our internal protocol is (for certain boring logical/technical reasons) such that some (non-user-in-message) messages are represented by 2 dgrams (MQ messages), not 1: a CONTROL message like an auto-ping is represented by an empty in-message (enters CONTROL state) and then a particular enumeration-value-encoding message (indicates auto-ping; goes back to normal state). So, the start of async-receive cannot assume normal state; it might be in CONTROL state because of the above. Of course this is pretty easy to handle; just keep a CONTROL-or-not state flag; and resume the state machine based on its value. There's no need to store any user payload copy.
Example: Native_socket_stream, when operating in stream mode (asio_local_stream_socket::Protocol_byte_stream a/k/a SOCK_STREAM unlike the earlier example) might hit would-block after any given byte whatsoever; right down to the "worst case" of, say, reading all of a 60K-long payload except for the very last expected byte. Then you'd have to copy it from the would-be user buffer; and feed that part to the next async-receive's user buffer (another copy). Fortunately this eventuality should not be frequent enough to affect overall perf.
In that case you'll need to do somehow save any partial-read results and apply them to the next async-read of any type at the start of that async-read, before reading any further potential low-level data. Usually this isn't a matter of performance, as at worst it's part of only 1 in-message, but you'll need some extra code, and the support for emulated batch-receiving will impact code not-itself-necessarily-related to batch-receiving.
async_rcv_impl_func() cache any new pipe-hosing error it encounters (and therefore emits via Error_code* – but note it may emit non-pipe-hosing error(s) too, most notably would-block; that is different); so that if an async-receive is attempted subsequently, it knows to immediately emit it. We mention this, because async_receive_batch_emulation() will – in the case of encountering 1+ in-messages followed by error (e.g., graceful close error::Code::S_RECEIVES_FINISHED_CANNOT_RECEIVE) – only emit the 1+ messages and not any error; it will stop but ignore the error itself. {Native_handle|Blob}_receiver::async_receive_*() contract is to emit the error next time in that case – and async_receive_batch_emulation() shall take no steps of its own to make that happen. Your async_rcv_impl_func() must take care of that.As of this writing Native_socket_stream and Blob_stream_mq_receiver use it internally. The latter does so, since (as of now anyway) there is no built-in batch-receiving OS support for POSIX MQs (nor bipc MQs). The former does so if and only if Native_socket_stream_cfg::S_USE_OS_DGRAM_BATCH_SUPPORT is false. In English – in both cases there's no low-level batch-receiving, so to provide that higher-level interface it has to be emulated based on normal receiving.
The same task would be faced by any potential Blob_receiver or Native_handle_receiver concept implementer, including when a Flow-IPC user wants to do so; an advanced type of work but entirely supported. Therefore it would be relatively rare that a user would call this... but definitely possible. Hence it is public.
| NO_HNDLS | true if implementing Blob_receiver::async_receive_blob_batch(). false if Native_handle_receiver::async_receive_native_handle_batch(). |
| Batch | Blob_receiver::Blob_batch_in or Native_handle_receiver::Native_handle_batch_in (see NO_HNDLS). In addition, it must have the APIs with identical names/semantics to Generic_msg_batch_in::clear_used(size_t), Generic_msg_batch_in::emulate_result(), Generic_msg_batch_in::next_target_blob(), and – if NO_HNDLS == false – Generic_msg_batch_in::next_target_hndl(). (Rationale: We could have instead simply required that Batch be an instance of Generic_msg_batch_in<Msg_resource, NO_HNDLS>. Decided to formally allow any type, as long as it has the required behavior – for freedom in custom scenarios.) |
| Task_err | As for {Native_handle|Blob}_receiver::async_receive_*_batch(). |
| Async_rcv_impl_func | See above. |
| logger_ptr | Logger to use for logging in this op, including its async-continuation if applicable. |
| batch | As for {Native_handle|Blob}_receiver::async_receive_*_batch(). |
| assume_would_block | As for {Native_handle|Blob}_receiver::async_receive_*_batch(). |
| sync_err_code | As for {Native_handle|Blob}_receiver::async_receive_*_batch(). |
| on_done_func | As for {Native_handle|Blob}_receiver::async_receive_*_batch(). |
| async_rcv_impl_func | Your *_receiver's single-message receive op. See above. |
| std::ostream & operator<< | ( | std::ostream & | os, |
| const Blob_stream_mq_receiver< Persistent_mq_handle > & | val | ||
| ) |
Prints string representation of the given Blob_stream_mq_receiver to the given ostream.
If object is default-cted (or moved-from), this will output something graceful indicating this.
| os | Stream to which to write. |
| val | Object to serialize. |
os. | std::ostream & operator<< | ( | std::ostream & | os, |
| const Blob_stream_mq_sender< Persistent_mq_handle > & | val | ||
| ) |
Prints string representation of the given Blob_stream_mq_sender to the given ostream.
If object is default-cted (or moved-from), this will output something graceful indicating this.
| os | Stream to which to write. |
| val | Object to serialize. |
os. | std::ostream & operator<< | ( | std::ostream & | os, |
| const Native_socket_stream & | val | ||
| ) |
Prints string representation of the given Native_socket_stream to the given ostream.
Friend of Native_socket_stream.
| os | Stream to which to write. |
| val | Object to serialize. |
os. | std::ostream & operator<< | ( | std::ostream & | os, |
| const Native_socket_stream_acceptor & | val | ||
| ) |
Prints string representation of the given Native_socket_stream_acceptor to the given ostream.
| os | Stream to which to write. |
| val | Object to serialize. |
os.