25#include <flow/log/log.hpp>
26#include <flow/async/single_thread_task_loop.hpp>
27#include <boost/noncopyable.hpp>
91template<
typename Core_t>
93 public flow::log::Log_context,
94 private boost::noncopyable
120 flow::async::Single_thread_task_loop* worker,
Core* sync_io);
235 mutable flow::util::Mutex_non_recursive
m_mutex;
255template<
typename Core_t>
258 flow::async::Single_thread_task_loop* worker,
260 flow::log::Log_context(logger_ptr,
Log_component::S_TRANSPORT),
267 using flow::util::Lock_guard;
283 m_sync_io.start_send_blob_ops([
this](Asio_waitable_native_handle* hndl_of_interest,
284 bool ev_of_interest_snd_else_rcv,
290 FLOW_LOG_TRACE(
m_log_pfx <<
": Sync-IO send-ops event-wait request: "
291 "descriptor [" << hndl_of_interest->native_handle() <<
"], "
292 "writable-else-readable [" << ev_of_interest_snd_else_rcv <<
"].");
295 assert(hndl_of_interest);
296 hndl_of_interest->async_wait(ev_of_interest_snd_else_rcv
297 ? Asio_waitable_native_handle::Base::wait_write
298 : Asio_waitable_native_handle::Base::wait_read,
299 [
this, on_active_ev_func = std::move(on_active_ev_func)]
304 if (err_code == boost::asio::error::operation_aborted)
319 (*on_active_ev_func)();
328template<
typename Core_t>
331 using flow::async::Single_thread_task_loop;
332 using flow::async::reset_thread_pinning;
333 using flow::util::ostream_op_string;
343 if (!m_end_sending_on_done_func_or_empty.empty())
345 Single_thread_task_loop one_thread{get_logger(),
346 ostream_op_string(
"ASdDeinit-", m_log_pfx)};
347 one_thread.start([&]()
349 reset_thread_pinning(get_logger());
351 FLOW_LOG_INFO(m_log_pfx <<
": In transient snd-finisher thread: "
352 "Shall run pending graceful-sends-close completion handler.");
354 FLOW_LOG_INFO(
"Transient finisher exiting.");
359template<
typename Core_t>
362 using flow::util::Lock_guard;
369 Lock_guard<
decltype(m_mutex)> lock{m_mutex};
373 m_sync_io.send_blob(blob, err_code);
374 assert(ok &&
"We are by definition in PEER state, and ctor starts send-ops; so that should never "
375 "return false. Bug somewhere?");
378template<
typename Core_t>
382 using flow::util::Lock_guard;
398 Lock_guard<
decltype(m_mutex)> lock{m_mutex};
402 m_sync_io.send_native_handle(hndl, meta_blob, err_code);
403 assert(ok &&
"We are by definition in PEER state, and ctor starts send-ops; so that should never "
404 "return false. Bug somewhere?");
407template<
typename Core_t>
410 using flow::util::Lock_guard;
417 Lock_guard<
decltype(m_mutex)> lock{m_mutex};
419 if (on_done_func_or_empty.empty())
421 return m_sync_io.end_sending();
425 if (!m_end_sending_on_done_func_or_empty.empty())
427 FLOW_LOG_WARNING(m_log_pfx <<
": async_end_sending(F) invoked; but we have a saved "
428 "completion handler -- which has not yet fired -- for it already, so it must be a dupe-call. "
437 m_end_sending_on_done_func_or_empty = std::move(on_done_func_or_empty);
440 const bool ok = m_sync_io.async_end_sending(&sync_err_code, [
this](
const Error_code& err_code)
444 on_sync_io_end_sending_done(err_code);
450 m_end_sending_on_done_func_or_empty.clear();
463 FLOW_LOG_INFO(m_log_pfx <<
": Sync-IO async-end-sending completed immediately. "
464 "Posting handler onto async-worker thread.");
466 on_sync_io_end_sending_done(sync_err_code);
472template<
typename Core_t>
475 using flow::util::Lock_guard;
480 assert(err_code != boost::asio::error::operation_aborted);
482 FLOW_LOG_TRACE(m_log_pfx <<
": Earlier async-wait => event active => snd-mutex lock => "
483 "on-active-event-func => sync_io module => here (on-end-sending-done handler). Or else "
484 "snd-mutex lock => no async-wait needed => here... (ditto).");
491 m_worker.post([
this, err_code, on_done_func = std::move(m_end_sending_on_done_func_or_empty)]()
494 FLOW_LOG_TRACE(m_log_pfx <<
": Invoking on-end-sending-done handler.");
495 on_done_func(err_code);
496 FLOW_LOG_TRACE(
"Handler completed.");
499 m_end_sending_on_done_func_or_empty.clear();
502template<
typename Core_t>
505 using flow::util::Lock_guard;
509 Lock_guard<
decltype(m_mutex)> lock{m_mutex};
510 return m_sync_io.auto_ping(period);
513template<
typename Core_t>
516 using flow::util::Lock_guard;
518 Lock_guard<
decltype(m_mutex)> lock{m_mutex};
519 return m_sync_io.blob_send_stats();
522template<
typename Core_t>
525 using flow::util::Lock_guard;
527 Lock_guard<
decltype(m_mutex)> lock{m_mutex};
528 m_sync_io.blob_send_stats_reset();
531template<
typename Core_t>
534 using flow::util::Lock_guard;
536 Lock_guard<
decltype(m_mutex)> lock{m_mutex};
537 return m_sync_io.native_handle_send_stats();
540template<
typename Core_t>
543 using flow::util::Lock_guard;
545 Lock_guard<
decltype(m_mutex)> lock{m_mutex};
546 m_sync_io.native_handle_send_stats_reset();
Type that adapts a given PEER-state sync_io::Native_handle_sender or sync_io::Blob_sender core into t...
~Async_adapter_sender()
To be invoked after ->stop()ping *worker (from ctor), as well as flushing any still-queued tasks in i...
void send_native_handle(Native_handle hndl_or_null, const util::Blob_const &meta_blob, Error_code *err_code)
See transport::Native_handle_sender counterpart.
flow::async::Task_asio_err m_end_sending_on_done_func_or_empty
The on_done_func argument to async_end_sending(), possibly .empty() if originally user invoked end_se...
stat::Blob_snd_stats blob_send_stats() const
See Native_socket_stream counterpart.
void blob_send_stats_reset()
See Native_socket_stream counterpart.
Core_t Core
The sync_io::X type being adapted into async-I/O-pattern X.
void on_sync_io_end_sending_done(const Error_code &err_code)
Handles the completion of m_sync_io.async_end_sending() operation whether synchronously or asynchrono...
void native_handle_send_stats_reset()
See Native_socket_stream counterpart.
bool async_end_sending(flow::async::Task_asio_err &&on_done_func_or_empty)
See transport::Native_handle_sender counterpart; or leave on_done_func_or_empty.empty() for transport...
void send_blob(const util::Blob_const &blob, Error_code *err_code)
See transport::Blob_sender counterpart.
flow::util::Mutex_non_recursive m_mutex
Protects m_end_sending_on_done_func_or_empty and, more importantly, send-ops data of m_sync_io.
flow::async::Single_thread_task_loop & m_worker
Single-thread worker pool for all internal async work. Referred to as thread W in comments.
Core & m_sync_io
The core Core engine, implementing the sync_io pattern (see util::sync_io doc header).
const std::string m_log_pfx
See log_pfx arg of ctor.
bool auto_ping(util::Fine_duration period)
See transport::Native_handle_sender counterpart.
Async_adapter_sender(flow::log::Logger *logger_ptr, util::String_view log_pfx, flow::async::Single_thread_task_loop *worker, Core *sync_io)
Constructs the adapter around sync_io::X object *sync_io.
stat::Blob_snd_stats native_handle_send_stats() const
See Native_socket_stream counterpart.
Useful if using the sync_io pattern within a user event loop built on boost.asio (optionally with flo...
@ S_SYNC_IO_WOULD_BLOCK
A sync_io operation could not immediately complete; it will complete contingent on active async-wait ...
@ S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER
Async completion handler is being called prematurely, because underlying object is shutting down,...
sync_io-pattern counterparts to async-I/O-pattern object types in parent namespace ipc::transport.
boost::shared_ptr< Task > Task_ptr
Short-hand for ref-counted pointer to a Function<> that takes no arguments and returns nothing; in pa...
flow::Fine_duration Fine_duration
Short-hand for Flow's Fine_duration.
boost::asio::const_buffer Blob_const
Short-hand for an immutable blob somewhere in memory, stored as exactly a void const * and a size_t.
flow::util::String_view String_view
Short-hand for Flow's String_view.
Log_component
The flow::log::Component payload enumeration containing various log components used by Flow-IPC inter...
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Cumulative stats from the outgoing-direction (send) pipe of a Blob_sender or Native_handle_sender con...
A monolayer-thin wrapper around a native handle, a/k/a descriptor a/k/a FD.