22#include <flow/error/error.hpp>
23#include <flow/common.hpp>
24#include <boost/interprocess/ipc/message_queue.hpp>
25#include <boost/version.hpp>
26#include <boost/move/make_unique.hpp>
27#include <boost/io/ios_state.hpp>
44 m_interrupting_snd(false),
45 m_interrupting_rcv(false)
50template<
typename Mode_tag>
52 size_t max_n_msg,
size_t max_msg_sz,
55 flow::log::Log_context(logger_ptr,
Log_component::S_TRANSPORT),
56 m_absolute_name(absolute_name_arg),
57 m_interrupting_snd(false),
58 m_interrupting_rcv(false)
61 using boost::io::ios_all_saver;
62 using boost::movelib::make_unique;
63 using bipc::message_queue;
65 assert(max_n_msg >= 1);
66 assert(max_msg_sz >= 1);
68 static_assert(std::is_same_v<Mode_tag, util::Create_only> || std::is_same_v<Mode_tag, util::Open_or_create>,
69 "Can only delegate to this ctor with Mode_tag = Create_only or Open_or_create.");
70 constexpr char const * MODE_STR = std::is_same_v<Mode_tag, util::Create_only>
71 ?
"create-only" :
"open-or-create";
73 if (logger_ptr && logger_ptr->should_log(Sev::S_TRACE, get_log_component()))
75 ios_all_saver saver{*(logger_ptr->this_thread_ostream())};
76 FLOW_LOG_TRACE_WITHOUT_CHECKING
77 (
"Bipc_mq_handle [" << *
this <<
"]: Constructing MQ handle to MQ at name [" <<
absolute_name() <<
"] in "
78 "[" << MODE_STR <<
"] mode; max msg size [" << max_msg_sz <<
"] x [" << max_n_msg <<
"] msgs; "
79 "perms = [" << std::setfill(
'0') << std::setw(4) << std::oct << perms.get_permissions() <<
"].");
87 m_mq = make_unique<message_queue>(mode_tag,
absolute_name().native_str(), max_n_msg, max_msg_sz, perms);
111 flow::log::Log_context(logger_ptr,
Log_component::S_TRANSPORT),
112 m_absolute_name(absolute_name_arg),
113 m_interrupting_snd(false),
114 m_interrupting_rcv(false)
116 using boost::movelib::make_unique;
117 using bipc::message_queue;
119 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Constructing MQ handle to MQ at name "
136 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Closing MQ handle (already null? = [" << (!
m_mq) <<
"]).");
144 using flow::log::Log_context;
149 swap(
static_cast<Log_context&
>(val1),
static_cast<Log_context&
>(val2));
158 assert(
m_mq &&
"As advertised: max_msg_size() => undefined behavior if not successfully cted or was moved-from.");
159 return m_mq->get_max_msg_size();
164 assert(
m_mq &&
"As advertised: max_n_msgs() => undefined behavior if not successfully cted or was moved-from.");
165 return m_mq->get_max_msg();
170 using flow::util::buffers_dump_string;
172 FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(
bool,
try_send, blob, _1);
175 assert(
m_mq &&
"As advertised: try_send() => undefined behavior if not successfully cted or was moved-from.");
182 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Nb-push of blob @[" <<
blob_data <<
"], "
183 "size [" << blob.size() <<
"].");
184 if (blob.size() == 0)
194 FLOW_LOG_DATA(
"Blob contents: [\n" << buffers_dump_string(blob,
" ") <<
"].");
201 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Nb-push of blob @[" <<
blob_data <<
"], "
202 "size [" << blob.size() <<
"]: would-block.");
216 using flow::util::buffers_dump_string;
218 if (flow::error::exec_void_and_throw_on_error
219 ([&](
Error_code* actual_err_code) {
send(blob, actual_err_code); },
220 err_code,
"Bipc_mq_handle::send()"))
227 assert(
m_mq &&
"As advertised: send() => undefined behavior if not successfully cted or was moved-from.");
230 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Blocking-push of blob @[" <<
blob_data <<
"], "
231 "size [" << blob.size() <<
"]. Trying nb-push first; if it succeeds -- great. "
232 "Else will wait/retry/wait/retry/....");
233 if (blob.size() == 0)
240 FLOW_LOG_DATA(
"Blob contents: [\n" << buffers_dump_string(blob,
" ") <<
"].");
262 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Nb-push of blob @[" <<
blob_data <<
"], "
263 "size [" << blob.size() <<
"]: would-block. Executing blocking-wait.");
272 FLOW_LOG_TRACE(
"Blocking-wait reported transmissibility. Retrying.");
279 using flow::util::time_since_posix_epoch;
280 using flow::util::buffers_dump_string;
281 using flow::Fine_clock;
282 using boost::chrono::round;
283 using boost::chrono::microseconds;
285 FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(
bool,
timed_send, blob, timeout_from_now, _1);
290 assert(
m_mq &&
"As advertised: timed_send() => undefined behavior if not successfully cted or was moved-from.");
293 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Blocking-timed-push of blob @[" <<
blob_data <<
"], "
294 "size [" << blob.size() <<
"]; timeout ~[" << round<microseconds>(timeout_from_now) <<
"]. "
295 "Trying nb-push first; if it succeeds -- great. Else will wait/retry/wait/retry/....");
296 if (blob.size() == 0)
303 FLOW_LOG_DATA(
"Blob contents: [\n" << buffers_dump_string(blob,
" ") <<
"].");
307 auto before = Fine_clock::now();
328 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Nb-push of blob @[" <<
blob_data <<
"], "
329 "size [" << blob.size() <<
"]: would-block. Executing blocking-wait.");
341 FLOW_LOG_TRACE(
"Did not finish before timeout.");
345 FLOW_LOG_TRACE(
"Blocking-wait reported transmissibility. Retrying.");
347 const auto after = Fine_clock::now();
348 timeout_from_now -= (after - before);
357 using flow::util::buffers_dump_string;
360 FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(
bool,
try_receive, blob, _1);
363 assert(
m_mq &&
"As advertised: try_receive() => undefined behavior if not successfully cted or was moved-from.");
369 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Nb-pop to blob @[" << blob->data() <<
"], "
370 "max-size [" << blob->size() <<
"].");
375 unsigned int pri_ignored;
377 =
m_mq->try_receive(blob->data(), blob->size(), n_rcvd, pri_ignored);
381 FLOW_LOG_TRACE(
"Received message sized [" << n_rcvd <<
"].");
382 if (blob->size() != 0)
384 FLOW_LOG_DATA(
"Blob contents: [\n" << buffers_dump_string(*blob,
" ") <<
"].");
389 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Nb-pop to blob @[" << blob->data() <<
"], "
390 "max-size [" << blob->size() <<
"]: would-block.");
404 using flow::util::buffers_dump_string;
407 if (flow::error::exec_void_and_throw_on_error
409 err_code,
"Bipc_mq_handle::receive()"))
416 assert(
m_mq &&
"As advertised: receive() => undefined behavior if not successfully cted or was moved-from.");
418 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Blocking-pop to blob @[" << blob->data() <<
"], "
419 "max-size [" << blob->size() <<
"]. Trying nb-pop first; if it succeeds -- great. "
420 "Else will wait/retry/wait/retry/....");
427 unsigned int pri_ignored;
435 ok =
m_mq->try_receive(blob->data(), blob->size(),
436 n_rcvd, pri_ignored);
447 FLOW_LOG_TRACE(
"Received message sized [" << n_rcvd <<
"].");
448 if (blob->size() != 0)
450 FLOW_LOG_DATA(
"Blob contents: [\n" << buffers_dump_string(*blob,
" ") <<
"].");
456 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Nb-pop to blob @[" << blob->data() <<
"], "
457 "max-size [" << blob->size() <<
"]: would-block. Executing blocking-pop.");
466 FLOW_LOG_TRACE(
"Blocking-wait reported transmissibility. Retrying.");
473 using flow::util::time_since_posix_epoch;
474 using flow::util::buffers_dump_string;
475 using flow::Fine_clock;
476 using boost::chrono::round;
477 using boost::chrono::microseconds;
479 FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(
bool,
timed_receive, blob, timeout_from_now, _1);
484 assert(
m_mq &&
"As advertised: timed_receive() => undefined behavior if not successfully cted or was moved-from.");
486 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Blocking-timed-pop to blob @[" << blob->data() <<
"], "
487 "max-size [" << blob->size() <<
"]; timeout ~[" << round<microseconds>(timeout_from_now) <<
"]. "
488 "Trying nb-pop first; if it succeeds -- great. Else will wait/retry/wait/retry/....");
491 unsigned int pri_ignored;
494 auto before = Fine_clock::now();
499 "Bipc_mq_handle::timed_receive(): bipc::message_queue::try_receive()",
502 ok =
m_mq->try_receive(blob->data(), blob->size(),
503 n_rcvd, pri_ignored);
514 FLOW_LOG_TRACE(
"Received message sized [" << n_rcvd <<
"].");
515 if (blob->size() != 0)
517 FLOW_LOG_DATA(
"Blob contents: [\n" << buffers_dump_string(*blob,
" ") <<
"].");
523 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Nb-pop to blob @[" << blob->data() <<
"], "
524 "max-size [" << blob->size() <<
"]: would-block. Executing blocking-wait.");
536 FLOW_LOG_TRACE(
"Did not finish before timeout.");
540 FLOW_LOG_TRACE(
"Blocking-wait reported transmissibility. Retrying.");
542 const auto after = Fine_clock::now();
543 timeout_from_now -= (after - before);
550template<
bool SND_ELSE_RCV,
bool ON_ELSE_OFF>
553 using Classic_shm_area = bipc::ipcdetail::managed_open_or_create_impl<bipc::shared_memory_object, 0, true, false>;
554 using Bipc_mq = bipc::message_queue;
555 using Bipc_mq_hdr = bipc::ipcdetail::mq_hdr_t<Bipc_mq::void_pointer>;
556 using Bipc_mq_mtx = bipc::interprocess_mutex;
557 using Bipc_mq_lock = bipc::scoped_lock<Bipc_mq_mtx>;
560 &&
"As advertised: interrupt_allow_impl() => undefined behavior if not successfully cted or was moved-from.");
565 bool* interrupting_ptr;
566 auto& shm_area =
reinterpret_cast<Classic_shm_area&
>(*m_mq);
567 auto*
const mq_hdr =
static_cast<Bipc_mq_hdr*
>(shm_area.get_user_address());
568 decltype(mq_hdr->m_cond_recv)* cond_ptr;
569 if constexpr(SND_ELSE_RCV)
572 cond_ptr = &mq_hdr->m_cond_send;
577 cond_ptr = &mq_hdr->m_cond_recv;
579 auto& interrupting = *interrupting_ptr;
580 auto& cond = *cond_ptr;
583 Bipc_mq_lock lock{mq_hdr->m_mutex};
585 if (interrupting == ON_ELSE_OFF)
587 FLOW_LOG_WARNING(
"Bipc_mq_handle [" << *
this <<
"]: Interrupt mode already set for "
588 "snd_else_rcv [" << SND_ELSE_RCV <<
"], on_else_off [" << ON_ELSE_OFF <<
"]. Ignoring.");
593 interrupting = ON_ELSE_OFF;
594 FLOW_LOG_INFO(
"Bipc_mq_handle [" << *
this <<
"]: Interrupt mode set for "
595 "snd_else_rcv [" << SND_ELSE_RCV <<
"], on_else_off [" << ON_ELSE_OFF <<
"]. If on -- we "
596 "shall now ping the associated condition variable to wake up any ongoing waits.");
598 if constexpr(ON_ELSE_OFF)
621 return interrupt_allow_impl<true, true>();
626 return interrupt_allow_impl<true, false>();
631 return interrupt_allow_impl<false, true>();
636 return interrupt_allow_impl<false, false>();
639template<Bipc_mq_handle::Wait_type WAIT_TYPE,
bool SND_ELSE_RCV>
643 using flow::util::time_since_posix_epoch;
644 using boost::chrono::round;
645 using boost::chrono::microseconds;
646 using Classic_shm_area = bipc::ipcdetail::managed_open_or_create_impl<bipc::shared_memory_object, 0, true, false>;
647 using Bipc_mq = bipc::message_queue;
648 using Bipc_mq_hdr = bipc::ipcdetail::mq_hdr_t<Bipc_mq::void_pointer>;
649 using Bipc_mq_mtx = bipc::interprocess_mutex;
650 using Bipc_mq_lock = bipc::scoped_lock<Bipc_mq_mtx>;
652 FLOW_ERROR_EXEC_AND_THROW_ON_ERROR(
bool, (wait_impl<WAIT_TYPE, SND_ELSE_RCV>), timeout_from_now, _1);
656 &&
"As advertised: wait_impl() => undefined behavior if not successfully cted or was moved-from.");
661 timeout_since_epoch =
Fine_time_pt{time_since_posix_epoch() + timeout_from_now};
694 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Poll-unstarved for snd_else_rcv [" << SND_ELSE_RCV <<
"].");
698 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Blocking-timed-await-unstarved for "
699 "snd_else_rcv [" << SND_ELSE_RCV <<
"]; "
700 "timeout ~[" << round<microseconds>(timeout_from_now) <<
"].");
705 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Blocking-await-unstarved for snd_else_rcv "
706 "[" << SND_ELSE_RCV <<
"].");
709 auto& shm_area =
reinterpret_cast<Classic_shm_area&
>(*m_mq);
710 auto*
const mq_hdr =
static_cast<Bipc_mq_hdr*
>(shm_area.get_user_address());
711 size_t* blocked_dudes_ptr;
712 bool* interrupting_ptr;
713 decltype(mq_hdr->m_cond_recv)* cond_ptr;
714 if constexpr(SND_ELSE_RCV)
716 blocked_dudes_ptr = &mq_hdr->m_blocked_senders;
717 cond_ptr = &mq_hdr->m_cond_send;
722 blocked_dudes_ptr = &mq_hdr->m_blocked_receivers;
723 cond_ptr = &mq_hdr->m_cond_recv;
726 auto& blocked_dudes = *blocked_dudes_ptr;
727 auto& cond = *cond_ptr;
728 bool& interrupting = *interrupting_ptr;
730 const auto is_starved_func = [&]() ->
bool
732 if constexpr(SND_ELSE_RCV)
734 return mq_hdr->m_cur_num_msg == mq_hdr->m_max_num_msg;
738 return mq_hdr->m_cur_num_msg == 0;
742 bool interrupted =
false;
747 "Bipc_mq_handle::wait_impl(): "
748 "bipc::interprocess_condition::[timed_]wait()",
751#if (BOOST_VERSION < 109100) && !defined(BOOST_INTERPROCESS_MSG_QUEUE_CIRCULAR_INDEX)
758 "bipc comments show this shall be true as of many Boost versions ago, unless unset which "
759 "would decrease performance; and we do not do that. Our code for simplicity assumes "
760 "it and does not support the lower-perf bipc MQ algorithm.");
764 Bipc_mq_lock lock{mq_hdr->m_mutex};
769 FLOW_LOG_TRACE(
"Interrupted before wait/poll started (preemptively).");
775 if (is_starved_func())
781 FLOW_LOG_TRACE(
"Not immediately unstarved. Poll = done.");
787 FLOW_LOG_TRACE(
"Not immediately unstarved. Awaiting unstarvedness or timeout.");
801 FLOW_LOG_TRACE(
"Interruption detected upon waking up from wait (interrupted concurrently).");
812 const bool wait_result = cond.timed_wait(lock, timeout_since_epoch);
817 FLOW_LOG_TRACE(
"Interruption detected upon waking up from wait (interrupted concurrently).");
827 if (is_starved_func())
840 while (is_starved_func());
855 FLOW_LOG_TRACE(
"Immediately unstarved.");
861 if ((!*err_code) && interrupted)
863 FLOW_LOG_INFO(
"Bipc_mq_handle [" << *
this <<
"]: Poll/wait/timed-wait-unstarved for "
864 "snd_else_rcv [" << SND_ELSE_RCV <<
"]: interrupted (TRACE message -- if visible -- "
865 "indicates whether preemptively or concurrently).");
877 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Poll-unstarved for snd_else_rcv [" << SND_ELSE_RCV <<
"]: "
878 "succeeded? = [" << not_starved <<
"].");
882 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Blocking-timed-await-unstarved for "
883 "snd_else_rcv [" << SND_ELSE_RCV <<
"]; timeout ~[" << round<microseconds>(timeout_from_now) <<
"]: "
884 "succeeded? = [" << not_starved <<
"]. "
885 "Either was immediately unstarved, or was not but waited until success or timeout+failure. "
886 "If success: TRACE message (if visible) above indicates which occurred.");
891 FLOW_LOG_TRACE(
"Bipc_mq_handle [" << *
this <<
"]: Blocking-await-unstarved for "
892 "snd_else_rcv [" << SND_ELSE_RCV <<
"]: succeeded eventually. "
893 "Either was immediately unstarved, or was not but waited it out. "
894 "TRACE message (if visible) above indicates which occurred.");
912 return wait_impl<Wait_type::S_TIMED_WAIT, true>(timeout_from_now, err_code);
927 return wait_impl<Wait_type::S_TIMED_WAIT, false>(timeout_from_now, err_code);
933 using bipc::message_queue;
934 using boost::system::system_category;
936 if (flow::error::exec_void_and_throw_on_error
939 err_code,
"Bipc_mq_handle::remove_persistent()"))
945 FLOW_LOG_SET_CONTEXT(logger_ptr, Log_component::S_TRANSPORT);
947 FLOW_LOG_INFO(
"Bipc_mq @ Shared_name[" <<
absolute_name <<
"]: Removing persistent MQ if possible.");
962 "Code in Bipc_mq_handle::remove_persistent() relies on Boost invoking Linux unlink() with errno.");
964 const auto& sys_err_code = *err_code = {errno, system_category()};
965 FLOW_ERROR_SYS_ERROR_LOG_WARNING();
968template<
typename Func>
972 using flow::error::Runtime_error;
973 using bipc::interprocess_exception;
974 using boost::system::system_category;
976 if (flow::error::exec_void_and_throw_on_error
988 catch (
const interprocess_exception& exc)
999 const auto native_code_raw = exc.get_native_error();
1000 const auto bipc_err_code_enum = exc.get_error_code();
1001 const bool is_size_error = bipc_err_code_enum == bipc::size_error;
1002 FLOW_LOG_WARNING(
"bipc threw interprocess_exception; will emit some hopefully suitable Flow-IPC Error_code; "
1003 "but here are all the details of the original exception: native code int "
1004 "[" << native_code_raw <<
"]; bipc error_code_t enum->int "
1005 "[" <<
int(bipc_err_code_enum) <<
"]; latter==size_error? = [" << is_size_error <<
"]; "
1006 "message = [" << exc.what() <<
"]; context = [" << context <<
"].");
1017 if (native_code_raw != 0)
1025 const auto& sys_err_code = *err_code = {native_code_raw, system_category()};
1026 FLOW_ERROR_SYS_ERROR_LOG_WARNING();
1048 return os <<
'@' << &val <<
": sh_name[" << val.
absolute_name() <<
']';
Implements the Persistent_mq_handle concept by thinly wrapping bipc::message_queue,...
Bipc_mq_handle()
Implements Persistent_mq_handle API: Construct null handle.
bool allow_receives()
Implements Persistent_mq_handle API: Turn off preemptive/concurrent interruption of blocking-receives...
boost::movelib::unique_ptr< bipc::message_queue > m_mq
Underlying MQ handle.
void receive(util::Blob_mutable *blob, Error_code *err_code=nullptr)
Implements Persistent_mq_handle API: Blocking receive: pops copy of message from queue into buffer; i...
Bipc_mq_handle & operator=(Bipc_mq_handle &&src)
Implements Persistent_mq_handle API: Replaces handle with the source handle while making the latter i...
bool is_sendable(Error_code *err_code=nullptr)
Implements Persistent_mq_handle API: Like try_send() but without the actual pushing of a message.
bool timed_send(const util::Blob_const &blob, util::Fine_duration timeout_from_now, Error_code *err_code=nullptr)
Implements Persistent_mq_handle API: Blocking timed send: pushes copy of message to queue; if queue i...
static void remove_persistent(flow::log::Logger *logger_ptr, const Shared_name &absolute_name, Error_code *err_code=nullptr)
Implements Persistent_mq_handle API: Removes the named persistent MQ.
bool m_interrupting_rcv
Other-direction counterpart to m_interrupting_snd.
bool interrupt_sends()
Implements Persistent_mq_handle API: Turn on preemptive/concurrent interruption of blocking-sends and...
bool is_receivable(Error_code *err_code=nullptr)
Implements Persistent_mq_handle API: Like try_receive() but without the actual popping of a message.
bool timed_wait_receivable(util::Fine_duration timeout_from_now, Error_code *err_code=nullptr)
Implements Persistent_mq_handle API: Like timed_receive() but without the actual popping of a message...
const Shared_name & absolute_name() const
Implements Persistent_mq_handle API: Returns name equal to absolute_name passed to ctor.
static const Shared_name S_RESOURCE_TYPE_ID
Implements concept API.
bool allow_sends()
Implements Persistent_mq_handle API: Turn off preemptive/concurrent interruption of blocking-sends an...
@ S_TIMED_WAIT
Timed-wait-type (blocking until timeout).
@ S_WAIT
Wait-type (blocking indefinitely).
@ S_POLL
Poll-type (non-blocking).
bool interrupt_receives()
Implements Persistent_mq_handle API: Turn on preemptive/concurrent interruption of blocking-receives ...
bool m_interrupting_snd
Starting at false, this is made true via interrupt_sends(), and back by allow_sends(); when true wait...
bool timed_wait_sendable(util::Fine_duration timeout_from_now, Error_code *err_code=nullptr)
Implements Persistent_mq_handle API: Like timed_send() but without the actual pushing of a message.
void op_with_possible_bipc_mq_exception(Error_code *err_code, util::String_view context, const Func &func)
Error helper: Run func() which will perform a bipc::message_queue API that might throw; if it does em...
size_t max_n_msgs() const
Implements Persistent_mq_handle API: Returns the max message count of the underlying queue.
void send(const util::Blob_const &blob, Error_code *err_code=nullptr)
Implements Persistent_mq_handle API: Blocking send: pushes copy of message to queue; if queue is full...
bool try_send(const util::Blob_const &blob, Error_code *err_code=nullptr)
Implements Persistent_mq_handle API: Non-blocking send: pushes copy of message to queue and returns t...
void wait_receivable(Error_code *err_code=nullptr)
Implements Persistent_mq_handle API: Like receive() but without the actual popping of a message.
~Bipc_mq_handle()
Implements Persistent_mq_handle API: Destroys this handle (or no-op if no handle was successfully con...
bool interrupt_allow_impl()
Impl body for interrupt_*() and allow_*().
bool timed_receive(util::Blob_mutable *blob, util::Fine_duration timeout_from_now, Error_code *err_code=nullptr)
Implements Persistent_mq_handle API: Blocking timed receive: pops copy of message from queue into buf...
size_t max_msg_size() const
Implements Persistent_mq_handle API: Returns the max message size of the underlying queue.
bool wait_impl(util::Fine_duration timeout_from_now, Error_code *err_code)
Impl body for *_sendable() and *_receivable().
Shared_name m_absolute_name
See absolute_name().
void wait_sendable(Error_code *err_code=nullptr)
Implements Persistent_mq_handle API: Like send() but without the actual pushing of a message.
bool try_receive(util::Blob_mutable *blob, Error_code *err_code=nullptr)
Implements Persistent_mq_handle API: Non-blocking receive: pops copy of message from queue into buffe...
String-wrapping abstraction representing a name uniquely distinguishing a kernel-persistent entity fr...
const char * native_str() const
Returns (sans copying) pointer to NUL-terminated wrapped name string, suitable to pass into sys calls...
static Shared_name ct(const Source &src)
Copy-constructs from a char-sequence container such as string or util::String_view.
@ S_INTERRUPTED
A blocking operation was intentionally interrupted or preemptively canceled.
@ S_MQ_BIPC_MISC_LIBRARY_ERROR
Low-level message queue: boost.interprocess emitted miscellaneous library exception sans a system cod...
@ S_MQ_MESSAGE_SIZE_OVER_OR_UNDERFLOW
Low-level message queue send-op buffer overflow (> max size) or receive-op buffer underflow (< max si...
Flow-IPC module providing transmission of structured messages and/or low-level blobs (and more) betwe...
std::ostream & operator<<(std::ostream &os, const Generic_msg_batch_in< Msg_resource_t, NO_HNDLS > &val)
Prints string representation of the given Generic_msg_batch_in to the given ostream.
util::Shared_name Shared_name
Convenience alias for the commonly used type util::Shared_name.
void swap(Bipc_mq_handle &val1, Bipc_mq_handle &val2)
Implements Persistent_mq_handle related concept: Swaps two objects.
bipc::permissions Permissions
Short-hand for Unix (POSIX) permissions class.
const uint8_t * blob_data(const Blob_const &blob)
Syntactic-sugary helper that returns pointer to first byte in an immutable buffer,...
bipc::open_only_t Open_only
Tag type indicating an ideally-atomic open-if-exists-else-fail operation.
const Open_or_create OPEN_OR_CREATE
Tag value indicating an open-if-exists-else-create operation.
const Open_only OPEN_ONLY
Tag value indicating an atomic open-if-exists-else-fail operation.
boost::asio::mutable_buffer Blob_mutable
Short-hand for a mutable blob somewhere in memory, stored as exactly a void* and a size_t.
bipc::open_or_create_t Open_or_create
Tag type indicating an atomic open-if-exists-else-create operation.
bipc::create_only_t Create_only
Tag type indicating a create-unless-exists-else-fail operation.
flow::Fine_time_pt Fine_time_pt
Short-hand for Flow's Fine_time_pt.
flow::Fine_duration Fine_duration
Short-hand for Flow's Fine_duration.
const Create_only CREATE_ONLY
Tag value indicating an atomic create-unless-exists-else-fail operation.
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.