Flow-IPC 1.0.1
Flow-IPC project: Full implementation reference.
blob_stream_mq_snd.hpp
Go to the documentation of this file.
1/* Flow-IPC: Core
2 * Copyright 2023 Akamai Technologies, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the
5 * "License"); you may not use this file except in
6 * compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in
12 * writing, software distributed under the License is
13 * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
14 * CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing
16 * permissions and limitations under the License. */
17
18/// @file
19#pragma once
20
22#include <boost/move/make_unique.hpp>
23#include <experimental/propagate_const>
24
25namespace ipc::transport
26{
27
28// Types.
29
30/**
31 * Implements Blob_sender concept by using an adopted Persistent_mq_handle MQ handle to an MQ (message queue)
32 * of that type, such as a POSIX or bipc MQ. This allows for high-performance, potentially zero-copy (except
33 * for copying into the transport MQ) of discrete messages, each containing a binary blob.
34 * This is a low-level (core) transport mechanism; higher-level (structured)
35 * transport mechanisms may use Blob_stream_mq_sender (and Blob_stream_mq_receiver) to enable their work.
36 *
37 * ### Informal comparison to other core transport mechanisms ###
38 * It is intended for transmission of relatively short messages -- rough guidance
39 * being for max length being in the 10s-of-KiB range. With a modern Linux kernel on server hardware from about 2014
40 * to 2020, our performance tests show that its raw speed for messages of aforementioned size is comparable to
41 * non-zero-copy mechanism based on Unix domain sockets. Technically we found `Blob_stream_mq_*<Posix_mq_handle>`
42 * to be somewhat faster; and `Blob_stream_*<Bipc_mq_handle>` (internally, SHM-based) somewhat slower.
43 * However, for best perf, it is recommended to send handles to SHM areas containing arbitrarily long structured
44 * messages (such as ones [de]serialized using zero-copy builders: capnp and the like).
45 * This further reduces the importance of relative perf compared to
46 * other low-level transports (which, as noted, is pretty close regardless -- though this is bound to stop being true
47 * for much longer messages, if the send-SHM-handles technique were to *not* be used).
48 *
49 * @see Native_socket_stream which also implements Blob_sender (and Blob_receiver) in its degraded mode (where
50 * one does not transmit native handles, only blobs).
51 *
52 * ### Relationship between `Blob_stream_mq_*`, the underlying MQ resource, and its Shared_name ###
53 * If one is familiar with MQs (doesn't matter whether POSIX or bipc -- their persistence semantics are identical),
54 * it is easy to become confused as to what `Blob_stream_mq_*` is modeling. To explain it then:
55 *
56 * - Think of the MQ itself as a file -- albeit in RAM -- a bulky thing that can store a certain number of bytes.
57 * - Think of its Shared_name as a directory entry, essentially a file name in a certain directory in the file system.
58 * - Think of a Persistent_mq_handle (the actual type being a template param; namely as of this writing
59 * Posix_mq_handle or Bipc_mq_handle) as a file handle. They can be opened for reading, writing, or both.
60 * More than 1 can be opened simultaneously.
61 * - Writing through this handle *pushes* a message but really writes those bytes somewhere in the "file" (MQ)
62 * in RAM. Any handle can be used for this; one can write through handle X and then right after that read through
63 * same handle X if desired.
64 * - Reading, similarly, *pops* a message by reading bytes from the "file."
65 * - One can open handle X, close handle X, wait 5 minutes, and from even another process open handle Y
66 * to the same name: the "stuff" (un-popped messages) will still be there.
67 *
68 * So that's MQs. However, `Blob_stream_mq_*` -- implementing Blob_sender and Blob_receiver as they do -- emphatically
69 * does *not* model that kind of free-for-all access (read/write, through 3+ handles if desired). Instead it models
70 * a *one-direction pipe*. So: there is up to 1 (exactly 1, if you want it to be useful) Blob_stream_mq_sender
71 * per Shared_name. It *only* writes (pushes). There is up to 1 (exactly 1, if...) Blob_stream_mq_receiver
72 * per Shared_name. It *only* reads (pops). Therefore trying to create a 2nd `_sender`, when 1 already exists --
73 * in *any* process -- is an error and does not work (an error is emitted from ctor; see its doc header).
74 * Same thing for `_receiver`.
75 *
76 * Moreover it is not a persistent pipe, either, even though the underlying MQ is quite capable of persistence
77 * (until reboot at any rate). Per Blob_sender/Blob_receiver concept, when a destructor for *either*
78 * the 1 Blob_stream_mq_sender *or* the 1 Blob_stream_mq_receiver is called (whichever happens first):
79 * - The Shared_name "directory entry" is deleted. The MQ becomes anonymous: creating an MQ with the same name
80 * will begin working -- and will create a totally new MQ.
81 * - (Caveat/corner case: In practice this is only useful after *both* destructors have run.
82 * Indeed MQ creation is possible after 1, but not the other, has executed; but then that "the other" will
83 * sadly delete the new, same-named MQ. So don't.)
84 * - The MQ handle is closed.
85 *
86 * Then once the other peer object (whether receiver or sender) dtor also executes:
87 * - (There is no "directory entry" to delete any longer.)
88 * - The MQ handle is closed.
89 *
90 * That last step brings the ref-count of things referring to the underlying MQ "file" (in RAM) to 0. Hence
91 * the MQ "file" (in RAM) is deleted (RAM is freed, becoming usable by other stuff, like maybe the general heap).
92 *
93 * That is how the Blob_sender/Blob_receiver one-direction pipe concept is satisfied, even though a general MQ
94 * has greater capabilities. That's not to say one should not use those; just not what this class is for;
95 * but one can use Posix_mq_handle/Bipc_mq_handle directly if necessary.
96 *
97 * ### Cleanup ###
98 * As just described, the two `Blob_stream_mq_*` classes are fairly aggressive about deleting the underlying MQ
99 * RAM resource. It is, generally, important not to leave those lying around post-use, as they can take non-trivial
100 * RAM.
101 *
102 * However, MQs (being kernel-persistent at least) require an even greater amount of care in cleanup than that.
103 * Assuming buglessness of the classes themselves and a graceful shutdown of the program -- including on clean
104 * exception handling, wherein the stack fully unwinds, and the destructors all run -- there is no problem.
105 *
106 * However, if something (a hard crash perhaps) prevents a Blob_stream_mq_sender or Blob_stream_mq_receiver dtor
107 * from running, the MQ "file" (in RAM) shall leak. It is your responsibility to implement a contingency for such
108 * leaks. (Note that, beyond RAM, there are limits on the number of MQs -- and certain other internally used
109 * kernel-persistent objects -- that exist system-wide. If reached -- which is not hard -- then things will
110 * screech to a halt, until something cleans up the leaks.) We provide 2 techniques to aid this.
111 *
112 * - You can maintain a *persistent* registry of created MQ streams. In that case you'll have a list of
113 * `mq.absolute_name()`s (where `mq` is passed to our and the receiver peer's ctors). After any potential
114 * abort, in another instance (process) of the application, invoke Blob_stream_mq_base::remove_persistent()
115 * on each such name.
116 * - To avoid the persistent registry, a much easier, though less surgical/definitive, technique is to maintain
117 * a prefix-based naming convention for `mq.absolute_name()`. Then: After any potential abort, in another
118 * instance (process) of the application, invoke remove_each_persistent_with_name_prefix<Blob_stream_mq_base>(),
119 * passing in the applicable Shared_name prefix. Having done so, the leaks (if any) should be cleaned.
120 *
121 * ipc::session uses the 2nd technique.
122 *
123 * ### Reusing the same absolute_name() for a new MQ and one-direction pipe ###
124 * Formally, as pointed out in various docs, this is possible no later than the return of the later of the
125 * Blob_stream_mq_sender and Blob_stream_mq_receiver dtors. Informally, we recommend against this if it can be avoided.
126 * Sure, it's fine if you can guarantee no process -- even *another* process -- would try to do so until
127 * in fact both of those dtors has run. This may not be trivial; it might even require more IPC to coordinate!
128 * It is better to segregate these things via unique names, using a namespace from something like a PID which
129 * will not, within reason, repeat before reboot. ipc::session uses this technique for various kernel-persistent
130 * resources including (not limited to) these MQs.
131 *
132 * ### Thread safety ###
133 * We add no more thread safety guarantees than those mandated by Blob_sender concept.
134 *
135 * @internal
136 * ### Implementation design/rationale ###
137 * Internally this class template uses uses the pImpl idiom (see https://en.cppreference.com/w/cpp/language/pimpl
138 * for an excellent overview), except it is what I (ygoldfel) term "pImpl-lite". That is: it is pImpl that achieves
139 * performant and easily-coded move-semantics -- in the face of fairly complex async impl details --
140 * but does *not* achieve a stable ABI (the thing where one can change impl method bodies without recompiling
141 * the code/changing the binary signature of the class). Long story short:
142 * - See Native_socket_stream's "Implementation design/rationale" for why they chose pImpl. The same applies here.
143 * - However, we are a template, and this template-ness is not reasonably possible to elide (via type erasure or
144 * something) into a non-template impl class. Therefore, simply, there is the non-movable
145 * Blob_stream_mq_sender_impl class *template* which is in detail/ and not to be `#include`d by the user;
146 * but *we* simply `#include` it above this doc header; and then write Blob_stream_mq_sender in terms of it.
147 * - So we get the quick/easy move-semantics that pImpl gives; but we don't get the binary separation between
148 * interface and implementation.
149 * - Also, stylistically, I (ygoldfel) did not bother to make Blob_stream_mq_sender_impl an inner class.
150 * It's in detail/ which means user must not instantiate it; this is a common pattern.
151 * I did not bother vaguely because it's not full pImpl anyway, and the circular reference nonsense would
152 * be annoying.
153 *
154 * @see Blob_stream_mq_sender_impl doc header.
155 *
156 * @endinternal
157 *
158 * @tparam Persistent_mq_handle
159 * See Persistent_mq_handle concept doc header.
160 *
161 * @see Blob_sender: implemented concept.
162 */
163template<typename Persistent_mq_handle>
164class Blob_stream_mq_sender : public Blob_stream_mq_base<Persistent_mq_handle>
165{
166public:
167 // Types.
168
169 /// Short-hand for our base with `static` goodies at least.
171
172 /// Short-hand for template arg for underlying MQ handle type.
174
175 /// Useful for generic programming, the `sync_io`-pattern counterpart to `*this` type.
177 /// You may disregard.
179
180 // Constants.
181
182 /// Implements concept API. Equals `Mq::S_RESOURCE_TYPE_ID`.
184
185 // Constructors/destructor.
186
187 /**
188 * Constructs the sender by taking over an already-opened MQ handle.
189 * Note that this op does not implement any concept; Blob_sender concept does not define how a Blob_sender
190 * is created in this explicit fashion.
191 *
192 * No traffic must have occurred on `mq_moved` up to this call. Otherwise behavior is undefined.
193 *
194 * If this fails (sets `*err_code` to truthy if not null; throws if null), all transmission calls on `*this`
195 * will fail with the post-value in `*err_code` emitted. In particular, error::Code::S_BLOB_STREAM_MQ_SENDER_EXISTS
196 * is that code, if the reason for failure was that another Blob_stream_mq_sender to
197 * `mq_moved.absolute_name()` has already been created in this or other process. See class doc header for
198 * discussion of the relationship between Blob_stream_mq_sender, Blob_stream_mq_receiver, the underlying MQ
199 * at a given Shared_name, and that Shared_name as registered in the OS.
200 * In short: there is to be up to 1 Blob_stream_mq_sender and up to 1 Blob_stream_mq_receiver for a given
201 * named persistent MQ. In this way, it is one single-direction pipe with 2 peers, like half of
202 * Native_socket_stream pipe: it is not a MQ with
203 * back-and-forth traffic nor multiple senders or multiple receivers. The underlying MQ supports such things;
204 * but that is not what the Blob_sender/Blob_receiver concepts model.
205 *
206 * Along those same lines note that the dtor (at the latest -- which happens if no fatal error occurs throughout)
207 * will not only close the MQ handle acquired from `mq_moved` but will execute `Mq::remove_persistent(name)`,
208 * where `name == mq_moved.absolute_name()` pre-this-ctor.
209 *
210 * ### Leaks of persistent resources ###
211 * If something prevents the destructor from running -- a hard crash, say -- the underlying MQ and/or the name
212 * may be leaked. External measures taken by ipc::session machinery are likely necessary to subsequently clean up
213 * the resource which, depending on the parameters passed to the #Mq ctor when originally creating the MQ,
214 * may use non-trivial RAM.
215 *
216 * ### Performance ###
217 * The taking over of `mq_moved` should be thought of as light-weight.
218 *
219 * @param logger_ptr
220 * Logger to use for subsequently logging.
221 * @param mq_moved
222 * An MQ handle to an MQ with no traffic on it so far. Unless an error is emitted, `mq_moved` becomes
223 * nullified upon return from this ctor. `*this` owns the MQ handle from this point on and is reponsible
224 * for closing it.
225 * @param nickname_str
226 * Human-readable nickname of the new object, as of this writing for use in `operator<<(ostream)` and
227 * logging only.
228 * @param err_code
229 * See `flow::Error_code` docs for error reporting semantics. #Error_code generated:
230 * error::Code::S_BLOB_STREAM_MQ_SENDER_EXISTS (another Blob_stream_mq_sender exists),
231 * system codes (other errors, all to do with the creation of a separate internally used tiny SHM pool
232 * used to prevent duplicate Blob_stream_mq_sender in the system).
233 */
234 explicit Blob_stream_mq_sender(flow::log::Logger* logger_ptr, util::String_view nickname_str,
235 Mq&& mq_moved, Error_code* err_code = 0);
236
237 /**
238 * Implements Blob_sender API, per its concept contract.
239 * All the notes for that concept's core-adopting ctor apply.
240 *
241 * @param sync_io_core_in_peer_state_moved
242 * See above.
243 *
244 * @see Blob_sender::Blob_sender(): implemented concept.
245 */
246 explicit Blob_stream_mq_sender(Sync_io_obj&& sync_io_core_in_peer_state_moved);
247
248 /**
249 * Implements Blob_sender API, per its concept contract.
250 * All the notes for that concept's default ctor apply.
251 *
252 * @see Blob_sender::Blob_sender(): implemented concept.
253 */
255
256 /**
257 * Move-constructs from `src`; `src` becomes as-if default-cted (therefore in NULL state).
258 * Implements Blob_sender API, per its concept contract.
259 *
260 * @param src
261 * See above.
262 *
263 * @see Blob_sender::Blob_sender(): implemented concept.
264 */
266
267 /// Copy construction is disallowed.
269
270 /**
271 * Implements Blob_sender API. All the notes for the concept's destructor apply but as a reminder:
272 *
273 * Destroys this peer endpoint which will end the one-direction pipe and cancel any pending
274 * completion handlers by invoking it ASAP with error::Code::S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER.
275 * As of this writing these are the completion handlers that would therefore be called:
276 * - The handler passed to async_end_sending() if not yet invoked.
277 * Since it is not valid to call async_end_sending() more than once, there is at most 1 of these.
278 *
279 * ### Fate of underlying MQ and its `.absolute_name()` ###
280 * No later than the return of this destructor:
281 * - The MQ name, namely `mq_moved.absolute_name()` from ctor, shall have been deleted.
282 * Therefore one will be able to util::Create a new #Mq; whereas before the dtor is called and returns
283 * it may (most likely will) not be possible to do so. This shall decrease the ref-count for the underlying
284 * MQ resource to at most 2. (Its ref-count is ever at most 3: 1 from the OS-registered Shared_name in the
285 * file system; 1 from `*this` Blob_stream_mq_sender; and 1 from the peer Blob_stream_mq_receiver).
286 * - The ref-count for the underlying MQ resource shall further decrease from 2 to 1 (if the counterpart
287 * Blob_stream_mq_sender still lives) or from 1 to 0 (if not). In the latter case the MQ itself shall be
288 * deleted, its bulk resources (in RAM) freed.
289 *
290 * While indeed util::Create of a new #Mq is possible after this dtor returns:
291 * - In practice it should only be done after *both* (sender and receiver) dtors have returned.
292 * Otherwise the later of the 2 will delete the new underlying MQ too: probably not what you want.
293 * - Even having accomplished that, it is still best not to reuse names if possible, at least not anytime soon.
294 * See class doc header for brief discussion.
295 *
296 * @see Blob_sender::~Blob_sender(): implemented concept.
297 */
299
300 // Methods.
301
302 /**
303 * Move-assigns from `src`; `*this` acts as if destructed; `src` becomes as-if default-cted (therefore in NULL state).
304 * No-op if `&src == this`.
305 * Implements Blob_sender API, per its concept contract.
306 *
307 * @see ~Blob_stream_mq_sender().
308 *
309 * @param src
310 * See above.
311 * @return See above.
312 *
313 * @see Blob_sender move assignment: implemented concept.
314 */
316
317 /// Copy assignment is disallowed.
319
320 /**
321 * Implements Blob_sender API per contract. Note this value equals "remote" peer's value for the same call
322 * at any given time which is *not* a concept requirement and may be untrue of other concept co-implementing classes.
323 *
324 * @return See above.
325 *
326 * @see Blob_sender::send_blob_max_size(): implemented concept.
327 */
328 size_t send_blob_max_size() const;
329
330 /**
331 * Implements Blob_sender API per contract. Reminder: It's not thread-safe
332 * to call this concurrently with other transmission methods or destructor on the same `*this`.
333 *
334 * Reminder: `blob.size() == 0` results in undefined behavior (assertion may trip).
335 *
336 * @param blob
337 * See above. Reminder: The memory area described by this arg need only be valid until this
338 * method returns. Perf reminder: That area will not be copied except for rare circumstances.
339 * @param err_code
340 * See above. Reminder: In rare circumstances, an error emitted here may represent something
341 * detected during handling of a *preceding* send_blob() call but after it returned.
342 * #Error_code generated:
343 * error::Code::S_INVALID_ARGUMENT (`blob.size()` exceeds max_msg_size()),
344 * error::Code::S_SENDS_FINISHED_CANNOT_SEND (`*end_sending()` was called earlier),
345 * system codes (but never would-block), indicating the underlying transport is hosed for that
346 * specific reason, as detected during outgoing-direction processing.
347 * @return See above.
348 *
349 * @see Native_handle_sender::send_native_handle(): implemented concept.
350 */
351 bool send_blob(const util::Blob_const& blob, Error_code* err_code = 0);
352
353 /**
354 * Implements Blob_sender API per contract.
355 * Reminder: It's not thread-safe to call this concurrently with other transmission methods or destructor on
356 * the same `*this`.
357 *
358 * #Error_code generated and passed to `on_done_func()`:
359 * system codes (but never would-block) (same as for send_blob()),
360 * error::Code::S_OBJECT_SHUTDOWN_ABORTED_COMPLETION_HANDLER (destructor called, canceling all pending ops;
361 * spiritually identical to `boost::asio::error::operation_aborted`),
362 *
363 * Reminder: In rare circumstances, an error emitted there may represent something
364 * detected during handling of a preceding send_blob() call but after it returned.
365 *
366 * @tparam Task_err
367 * See above.
368 * @param on_done_func
369 * See above. Reminder: any moved/copied version of this callback's associated captured state will
370 * be freed soon after it returns.
371 * @return See above. Reminder: If and only if it returns `false`, we're in NULL state, or `*end_sending()` has
372 * already been called; and `on_done_func()` will never be called.
373 *
374 * @see Blob_sender::async_end_sending(): implemented concept.
375 */
376 template<typename Task_err>
377 bool async_end_sending(Task_err&& on_done_func);
378
379 /**
380 * Implements Blob_sender API per contract. Reminder: It is equivalent to async_end_sending()
381 * but with a no-op `on_done_func`.
382 *
383 * @return See above. Reminder: If and only if it returns `false`, we're in NULL state, or `*end_sending()` has
384 * already been called.
385 *
386 * @see Blob_sender::end_sending(): implemented concept.
387 */
388 bool end_sending();
389
390 /**
391 * Implements Blob_sender API per contract.
392 *
393 * @param period
394 * See above.
395 * @return See above.
396 *
397 * @see Blob_sender::auto_ping(): implemented concept.
398 */
399 bool auto_ping(util::Fine_duration period = boost::chrono::seconds(2));
400
401 /**
402 * Returns nickname, a brief string suitable for logging. This is included in the output by the `ostream<<`
403 * operator as well. This method is thread-safe in that it always returns the same value.
404 *
405 * If this object is default-cted (or moved-from), this will return a value equal to "".
406 *
407 * @return See above.
408 */
409 const std::string& nickname() const;
410
411 /**
412 * Returns name equal to `mq.absolute_name()`, where `mq` was passed to ctor, at the time it was passed to ctor.
413 *
414 * If this object is default-cted (or moved-from), this will return Shared_name::S_EMPTY.
415 *
416 * @return See above. Always the same value except across move-assignment.
417 */
418 const Shared_name& absolute_name() const;
419
420private:
421 // Types.
422
423 /// Short-hand for `const`-respecting wrapper around Blob_stream_mq_sender_impl for the pImpl idiom.
424 using Impl_ptr = std::experimental::propagate_const<boost::movelib::unique_ptr<Blob_stream_mq_sender_impl<Mq>>>;
425
426 // Friends.
427
428 /// Friend of Blob_stream_mq_sender.
429 template<typename Persistent_mq_handle2>
430 friend std::ostream& operator<<(std::ostream& os, const Blob_stream_mq_sender<Persistent_mq_handle2>& val);
431
432 // Data.
433
434 /// The true implementation of this class. See also our class doc header.
436}; // class Blob_stream_mq_sender
437
438// Free functions: in *_fwd.hpp.
439
440// Template initializers.
441
442template<typename Persistent_mq_handle>
444
445// Template implementations (strict pImpl-idiom style (albeit pImpl-lite due to template-ness)).
446
447// The performant move semantics we get delightfully free with pImpl; they'll just move-to/from the unique_ptr m_impl.
448
449template<typename Persistent_mq_handle>
451template<typename Persistent_mq_handle>
453 (Blob_stream_mq_sender&&) = default;
454
455// The NULL state ctor comports with how null m_impl is treated all over below.
456template<typename Persistent_mq_handle>
458
459// The rest is strict forwarding to m_impl, once PEER state is established (non-null m_impl).
460
461template<typename Persistent_mq_handle>
463 (flow::log::Logger* logger_ptr, util::String_view nickname_str, Mq&& mq, Error_code* err_code) :
464 m_impl(boost::movelib::make_unique<Blob_stream_mq_sender_impl<Mq>>
465 (logger_ptr, nickname_str, std::move(mq), err_code))
466{
467 // Yay.
468}
469
470template<typename Persistent_mq_handle>
472 (Sync_io_obj&& sync_io_core_in_peer_state_moved) :
473
474 m_impl(boost::movelib::make_unique<Blob_stream_mq_sender_impl<Mq>>
475 (std::move(sync_io_core_in_peer_state_moved)))
476{
477 // Yay.
478}
479
480// It's only explicitly defined to formally document it.
481template<typename Persistent_mq_handle>
483
484template<typename Persistent_mq_handle>
486{
487 return m_impl ? m_impl->send_blob_max_size() : 0;
488}
489
490template<typename Persistent_mq_handle>
492{
493 return m_impl ? (m_impl->send_blob(blob, err_code), true)
494 : false;
495}
496
497template<typename Persistent_mq_handle>
498template<typename Task_err>
500{
501 return m_impl ? m_impl->async_end_sending(std::move(on_done_func)) : false;
502}
503
504template<typename Persistent_mq_handle>
506{
507 return m_impl ? m_impl->end_sending() : false;
508}
509
510template<typename Persistent_mq_handle>
512{
513 return m_impl ? m_impl->auto_ping(period) : false;
514}
515
516template<typename Persistent_mq_handle>
518{
519 return m_impl ? m_impl->absolute_name() : Shared_name::S_EMPTY;
520}
521
522template<typename Persistent_mq_handle>
524{
525 return m_impl ? m_impl->nickname() : util::EMPTY_STRING;
526}
527
528// `friend`ship needed for this "non-method method":
529
530template<typename Persistent_mq_handle>
531std::ostream& operator<<(std::ostream& os, const Blob_stream_mq_sender<Persistent_mq_handle>& val)
532{
533 if (val.m_impl)
534 {
535 return os << *val.m_impl;
536 }
537 // else
538 return os << "null";
539}
540
541} // namespace ipc::transport
Base of Blob_stream_mq_sender and Blob_stream_mq_receiver containing certain static facilities,...
Internal, non-movable pImpl-lite implementation of Blob_stream_mq_sender class template.
typename Base::Mq Mq
Short-hand for template arg for underlying MQ handle type.
Implements Blob_sender concept by using an adopted Persistent_mq_handle MQ handle to an MQ (message q...
~Blob_stream_mq_sender()
Implements Blob_sender API.
bool send_blob(const util::Blob_const &blob, Error_code *err_code=0)
Implements Blob_sender API per contract.
bool end_sending()
Implements Blob_sender API per contract.
size_t send_blob_max_size() const
Implements Blob_sender API per contract.
bool auto_ping(util::Fine_duration period=boost::chrono::seconds(2))
Implements Blob_sender API per contract.
static const Shared_name S_RESOURCE_TYPE_ID
Implements concept API. Equals Mq::S_RESOURCE_TYPE_ID.
Blob_stream_mq_sender & operator=(Blob_stream_mq_sender &&src)
Move-assigns from src; *this acts as if destructed; src becomes as-if default-cted (therefore in NULL...
Blob_stream_mq_sender & operator=(const Blob_stream_mq_sender &)=delete
Copy assignment is disallowed.
const Shared_name & absolute_name() const
Returns name equal to mq.absolute_name(), where mq was passed to ctor, at the time it was passed to c...
typename Blob_stream_mq_sender_impl< Persistent_mq_handle >::Mq Mq
Short-hand for template arg for underlying MQ handle type.
Blob_stream_mq_sender()
Implements Blob_sender API, per its concept contract.
const std::string & nickname() const
Returns nickname, a brief string suitable for logging.
friend std::ostream & operator<<(std::ostream &os, const Blob_stream_mq_sender< Persistent_mq_handle2 > &val)
Friend of Blob_stream_mq_sender.
std::experimental::propagate_const< boost::movelib::unique_ptr< Blob_stream_mq_sender_impl< Mq > > > Impl_ptr
Short-hand for const-respecting wrapper around Blob_stream_mq_sender_impl for the pImpl idiom.
Blob_stream_mq_sender(const Blob_stream_mq_sender &)=delete
Copy construction is disallowed.
Blob_stream_mq_sender(Blob_stream_mq_sender &&src)
Move-constructs from src; src becomes as-if default-cted (therefore in NULL state).
bool async_end_sending(Task_err &&on_done_func)
Implements Blob_sender API per contract.
Impl_ptr m_impl
The true implementation of this class. See also our class doc header.
Dummy type for use as a template param to Channel when either the blobs pipe or handles pipe is disab...
Definition: channel.hpp:1000
String-wrapping abstraction representing a name uniquely distinguishing a kernel-persistent entity fr...
static const Shared_name S_EMPTY
A (default-cted) Shared_name. May be useful for functions returning const Shared_name&.
Flow-IPC module providing transmission of structured messages and/or low-level blobs (and more) betwe...
std::ostream & operator<<(std::ostream &os, const Bipc_mq_handle &val)
Prints string representation of the given Bipc_mq_handle to the given ostream.
flow::Fine_duration Fine_duration
Short-hand for Flow's Fine_duration.
Definition: util_fwd.hpp:111
const std::string EMPTY_STRING
A (default-cted) string. May be useful for functions returning const std::string&.
Definition: util.cpp:33
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.
Definition: util_fwd.hpp:128
flow::util::String_view String_view
Short-hand for Flow's String_view.
Definition: util_fwd.hpp:109
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Definition: common.hpp:297