25#include <boost/move/make_unique.hpp>
52template<
typename Session>
101 template<
typename On_passive_open_channel_handler,
typename Task_err>
104 Task_err&& on_err_func,
105 On_passive_open_channel_handler&& on_passive_open_channel_func);
125 template<
typename Task_err>
128 Task_err&& on_err_func);
142 template<
typename Event_wait_func_t>
143 bool start_ops(Event_wait_func_t&& ev_wait_func);
154 template<
typename Create_ev_wait_hndl_func>
172 template<
typename Task_err,
typename On_passive_open_channel_handler>
173 bool init_handlers(Task_err&& on_err_func_arg, On_passive_open_channel_handler&& on_passive_open_channel_func_arg);
186 template<
typename Task_err>
212 template<
typename... Args>
253 using Ptr = boost::movelib::unique_ptr<Channel_open_result>;
423template<
typename Session>
425 m_ready_reader_err(m_nb_task_engine),
426 m_ready_writer_err(m_nb_task_engine),
427 m_ev_wait_hndl_err(m_ev_hndl_task_engine_unused),
428 m_ready_reader_chan(m_nb_task_engine),
429 m_ready_writer_chan(m_nb_task_engine),
430 m_ev_wait_hndl_chan(m_ev_hndl_task_engine_unused)
436template<
typename Session>
437template<
typename On_passive_open_channel_handler,
typename Task_err>
440 Task_err&& on_err_func,
441 On_passive_open_channel_handler&& on_passive_open_channel_func) :
442 m_ready_reader_err(m_nb_task_engine),
443 m_ready_writer_err(m_nb_task_engine),
444 m_ev_wait_hndl_err(m_ev_hndl_task_engine_unused),
445 m_ready_reader_chan(m_nb_task_engine),
446 m_ready_writer_chan(m_nb_task_engine),
447 m_ev_wait_hndl_chan(m_ev_hndl_task_engine_unused),
448 m_on_err_func(std::move(on_err_func)),
449 m_on_channel_func_or_empty(std::move(on_passive_open_channel_func)),
450 m_async_io(logger_ptr, cli_app_ref, srv_app_ref, on_err_func_sio(), on_channel_func_sio())
456template<
typename Session>
457template<
typename Task_err>
460 Task_err&& on_err_func) :
461 m_ready_reader_err(m_nb_task_engine),
462 m_ready_writer_err(m_nb_task_engine),
463 m_ev_wait_hndl_err(m_ev_hndl_task_engine_unused),
464 m_ready_reader_chan(m_nb_task_engine),
465 m_ready_writer_chan(m_nb_task_engine),
466 m_ev_wait_hndl_chan(m_ev_hndl_task_engine_unused),
467 m_on_err_func(std::move(on_err_func)),
468 m_async_io(logger_ptr, cli_app_ref, srv_app_ref, on_err_func_sio())
474template<
typename Session>
475template<
typename Task_err,
typename On_passive_open_channel_handler>
477 On_passive_open_channel_handler&& on_passive_open_channel_func_arg)
479 if (m_ev_wait_func.empty())
481 FLOW_LOG_WARNING(
"Session_adapter [" << m_async_io <<
"]: init_handlers() called before start_ops(). Ignoring.");
490 if (!core()->init_handlers(on_err_func_sio(), on_channel_func_sio()))
492 FLOW_LOG_WARNING(
"Session_adapter [" << m_async_io <<
"]: init_handlers() rejected by the async-I/O core "
493 "(called duplicately? session not yet accepted?). Ignoring.");
498 m_on_err_func = std::move(on_err_func_arg);
499 m_on_channel_func_or_empty = std::move(on_passive_open_channel_func_arg);
503template<
typename Session>
504template<
typename Task_err>
507 if (m_ev_wait_func.empty())
509 FLOW_LOG_WARNING(
"Session_adapter [" << m_async_io <<
"]: init_handlers() called before start_ops(). Ignoring.");
515 if (!core()->init_handlers(on_err_func_sio()))
517 FLOW_LOG_WARNING(
"Session_adapter [" << m_async_io <<
"]: init_handlers() rejected by the async-I/O core "
518 "(called duplicately? session not yet accepted?). Ignoring.");
523 m_on_err_func = std::move(on_err_func_arg);
527template<
typename Session>
532 using boost::asio::connect_pipe;
536 connect_pipe(*reader, *writer, sys_err_code);
539 FLOW_LOG_FATAL(
"Session_adapter [" << m_async_io <<
"]: Constructing: connect-pipe failed. Details follow.");
540 FLOW_ERROR_SYS_ERROR_LOG_FATAL();
541 assert(
false &&
"We chose not to complicate the code given how unlikely this is, and how hosed you'd have to be.");
548template<
typename Session>
549template<
typename Event_wait_func_t>
554 if (!m_ev_wait_func.empty())
556 FLOW_LOG_WARNING(
"Session_adapter [" << m_async_io <<
"]: Start-ops requested, "
557 "but we are already started. Probably a user bug, but it is not for us to judge.");
562 m_ev_wait_func = std::move(ev_wait_func);
567 async_wait(&m_ev_wait_hndl_err,
569 boost::make_shared<Task>([
this]()
571 FLOW_LOG_INFO(
"Session_adapter [" << m_async_io <<
"]: Async-IO core on-error event: informed via IPC-pipe; "
572 "invoking handler.");
575 auto on_done_func = std::move(m_on_err_func);
576 m_on_err_func.clear();
578 on_done_func(m_target_err_code_err);
579 FLOW_LOG_TRACE(
"Handler completed.");
587 async_wait(&m_ev_wait_hndl_chan,
589 boost::make_shared<Task>([
this]() { on_ev_channel_open(); }));
591 FLOW_LOG_INFO(
"Session_adapter [" << m_async_io <<
"]: Start-ops requested. Done.");
595template<
typename Session>
599 using flow::util::Lock_guard;
605 Lock_guard<
decltype(m_target_channel_open_q_mutex)> lock{m_target_channel_open_q_mutex};
607 FLOW_LOG_INFO(
"Session_adapter [" << m_async_io <<
"]: Async-IO core passively-opened channel event: "
608 "informed via IPC-pipe; invoking handler. Including this one "
609 "[" << m_target_channel_open_q.size() <<
"] are pending.");
611 assert((!m_target_channel_open_q.empty())
612 &&
"Algorithm bug? Result-queue elements and pipe signal bytes must be 1-1, so either something "
613 "failed to correctly push, or something overzealously popped.");
615 result = std::move(m_target_channel_open_q.front());
616 m_target_channel_open_q.pop();
619 m_on_channel_func_or_empty(std::move(result->m_channel), std::move(result->m_mdt_reader_ptr));
620 FLOW_LOG_TRACE(
"Handler completed. Beginning next async-wait immediately. If more is/are pending "
621 "it/they'll be popped quickly due to immediately-completing async-wait(s).");
624 async_wait(&m_ev_wait_hndl_chan,
626 boost::make_shared<Task>([
this]() { on_ev_channel_open(); }));
629template<
typename Session>
630template<
typename Create_ev_wait_hndl_func>
635 if (!m_ev_wait_func.empty())
637 FLOW_LOG_WARNING(
"Session_adapter [" << m_async_io <<
"]: Cannot replace event-wait handles after "
638 "a start-*-ops procedure has been executed. Ignoring.");
643 FLOW_LOG_INFO(
"Session_adapter [" << m_async_io <<
"]: Replacing event-wait handles (probably to replace underlying "
644 "execution context with outside event loop's boost.asio Task_engine or similar).");
646 assert(m_ev_wait_hndl_err.is_open());
647 assert(m_ev_wait_hndl_chan.is_open());
650 m_ev_wait_hndl_err = create_ev_wait_hndl_func();
651 m_ev_wait_hndl_err.assign(saved);
653 saved = m_ev_wait_hndl_chan.release();
654 m_ev_wait_hndl_chan = create_ev_wait_hndl_func();
655 m_ev_wait_hndl_chan.assign(saved);
660template<
typename Session>
663 using flow::async::Task_asio_err;
669 FLOW_LOG_INFO(
"Session_adapter [" << m_async_io <<
"]: Async-IO core reports on-error event: tickling IPC-pipe to "
672 assert((!m_target_err_code_err)
673 &&
"Error handler must never fire more than once per Session! Bug in the particular Session_obj type?");
674 m_target_err_code_err = err_code;
682template<
typename Session>
686 using flow::util::Lock_guard;
694 Lock_guard<
decltype(m_target_channel_open_q_mutex)> lock{m_target_channel_open_q_mutex};
696 FLOW_LOG_INFO(
"Session_adapter [" << m_async_io <<
"]: Async-IO core reports passively-opened channel event: "
697 "tickling IPC-pipe to inform user. This will make the # of pending such events "
698 "[" << (m_target_channel_open_q.size() + 1) <<
"].");
699 m_target_channel_open_q.emplace(boost::movelib::make_unique<Channel_open_result>());
700 auto& result = *(m_target_channel_open_q.back());
701 result.m_channel = std::move(new_channel);
702 result.m_mdt_reader_ptr = std::move(new_channel_mdt);
715template<
typename Session>
716template<
typename... Args>
719 m_ev_wait_func(std::forward<Args>(args)...);
722template<
typename Session>
728template<
typename Session>
734template<
typename Session>
737 return core()->get_logger();
740template<
typename Session>
743 return core()->get_log_component();
A documentation-only concept defining the local side of an IPC conversation (session) with another en...
unspecified Channel_obj
Each successful open_channel() and on-passive-open handler firing shall yield a concrete transport::C...
shared_ptr< typename transport::struc::schema::Metadata< Mdt_payload_obj >::Reader > Mdt_reader_ptr
Ref-counted handle to a capnp-generated Reader (and the payload it accesses) through which the user s...
typename Base::Session_obj Session_obj
Short-hand, for generic programming et al, for template parameter Session.
Internal-use workhorse containing common elements of Client_session_adapter and Server_session_adapte...
flow::async::Task_asio_err m_on_err_func
on_err_func from init_handlers() or ctor; .empty() until then, and once it has been invoked.
const flow::log::Component & get_log_component() const
See flow::log::Log_context.
util::Pipe_writer m_ready_writer_err
Write-end of IPC-pipe together with m_ready_reader_err.
util::sync_io::Asio_waitable_native_handle m_ev_wait_hndl_err
Descriptor waitable by outside event loop async-waits – storing the same Native_handle as (and thus b...
typename Session_obj::Channel_obj Channel_obj
Short-hand for session-openable Channel type.
typename Session_obj::Mdt_reader_ptr Mdt_reader_ptr
Short-hand for session-open metadata reader.
void init_pipe(util::Pipe_reader *reader, util::Pipe_writer *writer, util::sync_io::Asio_waitable_native_handle *ev_wait_hndl)
Utility that sets up an IPC-pipe in the given peer objects as well as loading a watcher-descriptor ob...
void on_ev_channel_open()
Signaled by the function returned by on_channel_func_sio(), it pops the next result from m_target_cha...
On_channel_func on_channel_func_sio()
Returns the proper on-passive-channel-open handler to set up on the underlying Session_obj (Client_se...
flow::async::Task_asio_err on_err_func_sio()
Returns the proper on-error handler to set up on the underlying Session_obj (Client_session: via ctor...
bool replace_event_wait_handles(const Create_ev_wait_hndl_func &create_ev_wait_hndl_func)
See, e.g., Client_session_adapter.
Error_code m_target_err_code_err
Result given to (or about to be given to) m_on_err_func.
void async_wait(Args &&... args)
Forwards to the util::sync_io::Event_wait_func saved in start_ops().
util::Pipe_reader m_ready_reader_err
Read-end of IPC-pipe used by *this to detect that the error-wait has completed.
flow::util::Mutex_non_recursive m_target_channel_open_q_mutex
Protects m_target_channel_open_q, accessed from user async-wait-reporter thread; and Session_obj work...
Session_adapter()
Forwards to the Session_obj default ctor.
util::sync_io::Asio_waitable_native_handle m_ev_wait_hndl_chan
Descriptor waitable by outside event loop async-waits – storing the same Native_handle as (and thus b...
Session_obj * core()
The adapted mutable Session_obj.
util::Pipe_reader m_ready_reader_chan
Read-end of IPC-pipe used by *this to detect that a channel-open-wait has completed.
Function< void(Channel_obj &&, Mdt_reader_ptr &&)> On_channel_func
Short-hand for passive-channel-open handler.
flow::log::Logger * get_logger() const
See flow::log::Log_context.
Session Session_obj
See, e.g., Client_session_adapter.
bool start_ops(Event_wait_func_t &&ev_wait_func)
See, e.g., Client_session_adapter.
Async_io_obj m_async_io
This guy does all the work. In our dtor this will be destroyed (hence thread stopped) first-thing.
util::sync_io::Event_wait_func m_ev_wait_func
Function (set forever in start_ops()) through which we invoke the outside event loop's async-wait fac...
Channel_open_result_q m_target_channel_open_q
Queue of On_channel_func handler arg sets received from async-I/O Session_obj – meaning the Session,...
std::queue< typename Channel_open_result::Ptr > Channel_open_result_q
Queue of Channel_open_result.
bool init_handlers(Task_err &&on_err_func_arg, On_passive_open_channel_handler &&on_passive_open_channel_func_arg)
Compilable only when Session_obj is a Server_session variant, forwards to its method of identical for...
util::Pipe_writer m_ready_writer_chan
Write-end of IPC-pipe together with m_ready_reader_chan.
flow::util::Task_engine m_nb_task_engine
The Task_engine for m_ready_*.
On_channel_func m_on_channel_func_or_empty
on_passive_open_channel_func_or_empty from init_handlers() or ctor (possibly .empty() if not supplied...
flow::util::Task_engine m_ev_hndl_task_engine_unused
The Task_engine for m_ev_wait_hndl_*, unless it is replaced via replace_event_wait_handles().
Dummy type for use as a template param to Channel when either the blobs pipe or handles pipe is disab...
Useful if using the sync_io pattern within a user event loop built on boost.asio (optionally with flo...
void assign(Native_handle hndl)
Loads value to be returned by native_handle().
sync_io-pattern counterparts to async-I/O-pattern object types in parent namespace ipc::session.
util::Native_handle Native_handle
Convenience alias for the commonly used type util::Native_handle.
Function< void(Asio_waitable_native_handle *hndl_of_interest, bool ev_of_interest_snd_else_rcv, Task_ptr &&on_active_ev_func)> Event_wait_func
In sync_io pattern, concrete type storing user-supplied function invoked by pattern-implementing ipc:...
flow::async::Task Task
Short-hand for polymorphic function (a-la std::function<>) that takes no arguments and returns nothin...
void pipe_produce(flow::log::Logger *logger_ptr, Pipe_writer *pipe)
Writes a byte to the given pipe writer.
void pipe_consume(flow::log::Logger *logger_ptr, Pipe_reader *pipe)
Reads a byte via the given pipe reader.
boost::asio::writable_pipe Pipe_writer
Short-hand for anonymous pipe write end.
boost::asio::readable_pipe Pipe_reader
Short-hand for anonymous pipe read end.
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
flow::Function< Signature > Function
Short-hand for polymorphic functor holder which is very common. This is essentially std::function.
An App that is used as a client in at least one client-server IPC split.
An App that is used as a server in at least one client-server IPC split.
Set of result arg values from a successful passive-channel-open from a Session_obj invoking On_channe...
Channel_obj m_channel
Result 1/2 about to be given to m_on_channel_func_or_empty.
Mdt_reader_ptr m_mdt_reader_ptr
Result 2/2 about to be given to m_on_channel_func_or_empty.
boost::movelib::unique_ptr< Channel_open_result > Ptr
Short-hand for pointer wrapper around a *this.
A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.