Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
Classes | Typedefs | Functions
ipc::transport::sync_io Namespace Reference

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_receiver_impl
 Internal, non-movable pImpl-lite implementation of sync_io::Blob_stream_mq_receiver class template. 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  Blob_stream_mq_sender_impl
 Internal, non-movable pImpl-lite implementation of sync_io::Blob_stream_mq_sender class template. 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...
 
class  Native_socket_stream_impl
 Internal, non-movable pImpl-lite implementation of sync_io::Native_socket_stream class. 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). More...
 
using Posix_mq_receiver = Blob_stream_mq_receiver< Posix_mq_handle >
 Convenience alias: sync_io::Blob_receiver via unidirectional POSIX MQ (message queue). More...
 
using Bipc_mq_sender = Blob_stream_mq_sender< Bipc_mq_handle >
 Convenience alias: sync_io::Blob_sender via unidirectional bipc MQ (message queue). More...
 
using Bipc_mq_receiver = Blob_stream_mq_receiver< Bipc_mq_handle >
 Convenience alias: sync_io::Blob_receiver via unidirectional bipc MQ (message queue). More...
 
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). More...
 
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). More...
 
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. More...
 
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. More...
 

Functions

template<bool NO_HNDLS, typename Batch , typename Async_rcv_impl_func >
void async_receive_batch_emulation_on_init_msg (flow::log::Logger *logger_ptr, Batch *batch, Error_code *sync_err_code, const Async_rcv_impl_func &async_rcv_impl_func, const Error_code init_err_code, size_t init_sz)
 Helper for async_receive_batch_emulation() that executes on that call's initial single-message async-read (whether the result was immediate or following an async-wait due to initial would-block). More...
 
std::ostream & operator<< (std::ostream &os, const Native_socket_stream_impl &val)
 Prints string representation of the given Native_socket_stream_impl to the given ostream. More...
 
template<typename Persistent_mq_handle >
std::ostream & operator<< (std::ostream &os, const Blob_stream_mq_receiver_impl< Persistent_mq_handle > &val)
 Prints string representation of the given Blob_stream_mq_receiver_impl to the given ostream. More...
 
template<typename Persistent_mq_handle >
std::ostream & operator<< (std::ostream &os, const Blob_stream_mq_sender_impl< Persistent_mq_handle > &val)
 Prints string representation of the given Blob_stream_mq_sender to the given ostream. More...
 
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...
 

Detailed Description

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.

See also
util::sync_io doc header – describes the general sync_io pattern we are following.

Typedef Documentation

◆ Bipc_mq_receiver

Convenience alias: sync_io::Blob_receiver via unidirectional bipc MQ (message queue).

Definition at line 485 of file transport_fwd.hpp.

◆ Bipc_mq_sender

Convenience alias: sync_io::Blob_sender via unidirectional bipc MQ (message queue).

Definition at line 483 of file transport_fwd.hpp.

◆ Bipc_mqs_channel_of_blobs

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).

Definition at line 497 of file transport_fwd.hpp.

◆ Bipc_mqs_socket_stream_channel

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.

Definition at line 513 of file transport_fwd.hpp.

◆ Posix_mq_receiver

Convenience alias: sync_io::Blob_receiver via unidirectional POSIX MQ (message queue).

Definition at line 481 of file transport_fwd.hpp.

◆ Posix_mq_sender

Convenience alias: sync_io::Blob_sender via unidirectional POSIX MQ (message queue).

Definition at line 479 of file transport_fwd.hpp.

◆ Posix_mqs_channel_of_blobs

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).

Definition at line 491 of file transport_fwd.hpp.

◆ Posix_mqs_socket_stream_channel

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.

Definition at line 505 of file transport_fwd.hpp.

Function Documentation

◆ async_receive_batch_emulation()

template<bool NO_HNDLS, typename Batch , typename Task_err , typename Async_rcv_impl_func >
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.

How to use

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:

  • (If and only if 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()!)
  • util::Blob_mutable: Target memory area for the async-read.
  • 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.
  • Function-object of the specific type 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:

  • Which one it is: it must act consistently with NO_HNDLS.
    • It shall take the extra leading Native_handle* arg (see above) if NO_HNDLS == false.
  • It may assume the following checks have all passed: in PEER state, start_*_ops() has been called, no pipe-hosing error recorded yet from prior ops, no async_receive_*() already outstanding, batch->initialized() && (!batch->full()).
  • May act differently (probably for perf savings) depending on the bool arg (assume-would-block; see above).
  • If it emits non-success, non-would-block (in-pipe-hosing) error 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:
    • error::Code::S_RECEIVES_FINISHED_CANNOT_RECEIVE,
    • boost::asio::error::eof.
    • Any other 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.)
  • The on-done handler may be non-empty (as required for normal user-triggered calls) or .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.
    • If would-block is encountered immediately (no partial message is read/non-steady state reached): Emit would-block as normal; but end the async-receive op. Do not issue an async-wait for readability; do not save on-done handler (which is empty anyway).
    • If would-block is encountered after receiving part of an in-message/a non-steady state is reached: Do the same; plus:
      • Memorize the partial-message payload/non-steady state, so that if another async-receive is issued by something/someone later, your state machine starts from the point as-if the partial-message payload/state had already been received/reached. (After all: it had already been received/reached – it just ended up irrelevant to the previous async-receive; namely us.)

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.

Warning
It is important that 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.

Rationale / use-cases

See also
Native_handle_receiver concept doc header "Batch-receiving" section for background.

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.

Template Parameters
NO_HNDLStrue if implementing Blob_receiver::async_receive_blob_batch(). false if Native_handle_receiver::async_receive_native_handle_batch().
BatchBlob_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_errAs for {Native_handle|Blob}_receiver::async_receive_*_batch().
Async_rcv_impl_funcSee above.
Parameters
logger_ptrLogger to use for logging in this op, including its async-continuation if applicable.
batchAs for {Native_handle|Blob}_receiver::async_receive_*_batch().
assume_would_blockAs for {Native_handle|Blob}_receiver::async_receive_*_batch().
sync_err_codeAs for {Native_handle|Blob}_receiver::async_receive_*_batch().
on_done_funcAs for {Native_handle|Blob}_receiver::async_receive_*_batch().
async_rcv_impl_funcYour *_receiver's single-message receive op. See above.

Definition at line 33 of file batch.hpp.

References ipc::transport::error::S_INVALID_ARGUMENT, and ipc::transport::error::S_SYNC_IO_WOULD_BLOCK.

◆ async_receive_batch_emulation_on_init_msg()

template<bool NO_HNDLS, typename Batch , typename Async_rcv_impl_func >
void ipc::transport::sync_io::async_receive_batch_emulation_on_init_msg ( flow::log::Logger *  logger_ptr,
Batch *  batch,
Error_code *  sync_err_code,
const Async_rcv_impl_func &  async_rcv_impl_func,
const Error_code  init_err_code,
size_t  init_sz 
)

Helper for async_receive_batch_emulation() that executes on that call's initial single-message async-read (whether the result was immediate or following an async-wait due to initial would-block).

In short, then,

  • If init_err_code, it saves it to *sync_err_code and returns. Otherwise:
  • It performs further single-message sync-reads, stopping once any of the following occurs (but in all cases setting *sync_err_code to success (falsy)):
    • batch->full() (might be the case at entry already);
    • would-block;
    • error. (The error is not emitted, as the pre-condition at this stage is 1+ in-messages have already been received, and async-receive overall must not emit both messages and error, nor just the latter while eating the fotmer! Hence async_rcv_impl_func() should cache it, if it is pipe-hosing, so the next async-receive immediately emits it.)
Parameters
logger_ptrSee async_receive_batch_emulation().
batchSee async_receive_batch_emulation().
sync_err_codeSee async_receive_batch_emulation().
async_rcv_impl_funcSee async_receive_batch_emulation().
init_err_codeThe result of the initial async_rcv_impl_func() call in this async_receive_batch_emulation().
init_szIf init_err_code is success: The # of bytes received by the initial async_rcv_impl_func() call in this async_receive_batch_emulation().

Definition at line 31 of file batch.hpp.

References ipc::transport::error::S_RECEIVES_FINISHED_CANNOT_RECEIVE, and ipc::transport::error::S_SYNC_IO_WOULD_BLOCK.

◆ operator<<() [1/7]

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.

If object is default-cted (or moved-from), this will output something graceful indicating this.

Parameters
osStream to which to write.
valObject to serialize.
Returns
os.

Definition at line 451 of file blob_stream_mq_rcv.hpp.

◆ operator<<() [2/7]

template<typename Persistent_mq_handle >
std::ostream & ipc::transport::sync_io::operator<< ( std::ostream &  os,
const Blob_stream_mq_receiver_impl< Persistent_mq_handle > &  val 
)

Prints string representation of the given Blob_stream_mq_receiver_impl to the given ostream.

Parameters
osStream to which to write.
valObject to serialize.
Returns
os.

Definition at line 1592 of file blob_stream_mq_rcv_impl.hpp.

◆ operator<<() [3/7]

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.

If object is default-cted (or moved-from), this will output something graceful indicating this.

Parameters
osStream to which to write.
valObject to serialize.
Returns
os.

Definition at line 430 of file blob_stream_mq_snd.hpp.

◆ operator<<() [4/7]

template<typename Persistent_mq_handle >
std::ostream & ipc::transport::sync_io::operator<< ( std::ostream &  os,
const Blob_stream_mq_sender_impl< Persistent_mq_handle > &  val 
)

Prints string representation of the given Blob_stream_mq_sender to the given ostream.

Parameters
osStream to which to write.
valObject to serialize.
Returns
os.

Definition at line 1839 of file blob_stream_mq_snd_impl.hpp.

◆ operator<<() [5/7]

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.

Parameters
osStream to which to write.
valObject to serialize.
Returns
os.

Definition at line 195 of file native_socket_stream.cpp.

◆ operator<<() [6/7]

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.

Parameters
osStream to which to write.
valObject to serialize.
Returns
os.

Definition at line 83 of file native_socket_stream_acceptor.cpp.

◆ operator<<() [7/7]

std::ostream & ipc::transport::sync_io::operator<< ( std::ostream &  os,
const Native_socket_stream_impl &  val 
)

Prints string representation of the given Native_socket_stream_impl to the given ostream.

Parameters
osStream to which to write.
valObject to serialize.
Returns
os.

Definition at line 646 of file native_socket_stream_impl.cpp.