Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
common.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
21/* @todo More consistent to move this below `#include "ipc/..."`; but flow/common.hpp needs to #undef a couple things
22 * before `#define`ing them (FLOW_LOG_CFG_COMPONENT_ENUM_*) for that to work. It really should anyway. */
23#include <flow/util/util.hpp>
24
25#include "ipc/detail/common.hpp"
26#include <boost/interprocess/interprocess_fwd.hpp>
27#include <boost/filesystem.hpp>
28#include <string>
29
30/* We build in C++17 mode ourselves (as of this writing), but linking user shouldn't care about that so much.
31 * The APIs and header-inlined stuff (templates, constexprs, some explicitly-inlined functions), however, also
32 * require C++17 or newer; and that applies to the linking user's `#include`ing .cpp file(s)!
33 * Therefore enforce it by failing compile unless compiler's C++17 or newer mode is in use.
34 *
35 * Note this isn't academic; as of this writing there's at least a C++14-requiring constexpr feature in use in one
36 * of the headers. So at least C++14 has been required for ages in actual practice. Later, notched it up to C++17
37 * by similar logic. */
38#if (!defined(__cplusplus)) || (__cplusplus < 201703L)
39// Would use static_assert(false), but... it's C++11 and later only. So.
40# error "To compile a translation unit that `#include`s any ipc/ API headers, use C++17 compile mode or later."
41#endif
42
43/**
44 * Catch-all namespace for the Flow-IPC project: A library/API in modern C++17 providing high-performance
45 * communication between processes. It includes schema-based structured message definition and zero-copy transport
46 * between processes. It also includes a SHared Memory (SHM) module for direct allocation and related needs; and
47 * particular support for passing references to such *bulk* objects through the aforementioned messaging transport
48 * system.
49 *
50 * @see The guided Manual, starting at @ref about, is a tutorial-style introduction to Flow-IPC.
51 *
52 * @note Nomenclature: The project is called Flow-IPC.
53 *
54 * From the user's perspective, one should view this namespace as the "root," meaning it consists of two parts:
55 * - Symbols directly in Flow-IPC: The absolute most basic, commonly used symbols (such as the alias
56 * ipc::Error_code). There should be only a handful of these, and they are likely to be small.
57 * - In particular this includes `enum class` ipc::Log_component which defines the set of possible
58 * `flow::log::Component` values logged from within all modules of Flow-IPC. See end of common.hpp.
59 * - Sub-namespaces (like ipc::transport, ipc::util), each of which represents a Flow-IPC *module* providing
60 * certain grouped functionality. The modules are discussed just below.
61 *
62 * Flow-IPC modules overview
63 * ---------------------------
64 * Unlike with, say, Boost or Flow, the user of Flow-IPC should be familiar with the totality of its modules. They're
65 * interrelated -- albeit layered -- and to be used together in a typical application. Contrast with how one might use
66 * `flow::log` but not `flow::async`, or boost.asio but not boost.random. Summary of modules follows:
67 *
68 * - *ipc::transport*:
69 * It allows for low-level (unstructured) and structured message passing between each given pair of
70 * processes A and B. This is really a key aim of Flow-IPC, meaning wanting to use ipc::transport is a key reason
71 * one links/includes Flow-IPC in their application in the first place.
72 * - *ipc::transport::struc* contains the structured-message facilities. To define a structured message,
73 * the user is expected to write a *schema* for it. As of this writing schemas
74 * are to be written in the Cap'n Proto (capnp) domain-specific language (DSL). Hence ipc::transport::struc has
75 * capnp as a dependency.
76 * - *ipc::transport::struc::shm* contains some important items, albeit not ones typically directly mentioned
77 * by user code, that power the ability to place structured messages directly in SHM, thus enabling end-to-end
78 * *zero-copy* of all messages passed through transport::struc::Channel.
79 * - *ipc::transport::struc::shm::rpc* integrates Flow-IPC with capnp's Remote Procedure Call layer
80 * (capnp-RPC): one uses capnp-RPC (interfaces, promise pipelining, etc.) as normal, but with end-to-end
81 * zero-copy via SHM. It is an alternative to transport::struc::Channel, for those who prefer the RPC
82 * paradigm to message passing.
83 * - *ipc::session*:
84 * Before a given process pair A and B talks via ipc::transport, they (typically) will want to establish a
85 * broad conceptual connection (called a *session*) within the context of which all
86 * the talking occurs. ipc::session is concerned with establishing
87 * such sessions, so that most user code can then mostly forget about that and use ipc::transport to communicate.
88 * It includes safety measures like peer-identity checks and tokens, but these should be mostly invisible in
89 * day-to-day coding of IPC logic via ipc::transport. It *is* possible to establish ipc::transport pipes without
90 * sessions, and for smaller and/or legacy applications and/or prototyping that may be a reasonable approach.
91 * - *ipc::session::shm* conventionally contains SHM-enabled session functionality. The location of a
92 * given set of classes will mirror the ipc::shm facilities to which those SHM-enabled sessions provide access.
93 * For example ipc::session::shm::classic contains SHM-classic sessions which provide access to arenas
94 * supplied by ipc::shm::classic. Similarly ipc::session::shm::arena_lend::jemalloc contains SHM-jemalloc
95 * sessions <=> core arena facilities in ipc::shm::arena_lend::jemalloc. Note the 1-1 naming of namespaces in
96 * both cases.
97 * - *ipc::shm*:
98 * It provides explicit shared memory (SHM) functionality, including allocating in SHM -- vaguely
99 * analogously to using the regular heap. ipc::shm and ipc::transport are co-designed to support transmitting
100 * references to SHM-stored objects. ipc::session treats setup of SHM arenas for (direct or background) use
101 * in a given session as an important, albeit optional, capability. Unless the user wants to explicitly
102 * place data structures (such as `struct`s and STL containers) into SHM -- which is often a
103 * desirable capability in itself -- direct use of ipc::shm is not necessary.
104 * - It is also entirely possible to use ipc::shm (such as to share `struct`s and STL containers) without
105 * making calls to ipc::transport APIs. Ultimately to share a data structure, that sits in SHM, from process
106 * A to process B one must IPC-transmit a small piece of data (that encodes a handle to the SHM object)
107 * between the two; any IPC technique -- not necessarily those offered in ipc::transport -- works for this.
108 * In that sense ipc::shm is analogous to boost.interprocess's SHM facilities.
109 * - *ipc::util*: Miscellaneous items. That said some of these are quite important and oft-used throughout other
110 * modules. Here we single out, in particular, ipc::util::Shared_name and ipc::util::Native_handle.
111 *
112 * @note Nomenclature: We refer to Cap'n Proto as capnp, lower-case, no backticks. Keep to this consistent convention
113 * in comments.
114 *
115 * The above text views Flow-IPC somewhat as a monolithic whole. Indeed the present documentation generally treats
116 * the entirety of Flow-IPC as available and usable, even though there are various sub-namespaces as shown that break
117 * the monolith into layered modules. When it comes to practical needs, this view is sufficient. Really, most
118 * users will (1) start a session (using ipc::session::shm for max performance), (2) use the session to create
119 * 1+ ipc::transport::Channel, (3) possibly upgrade each to ipc::transport::struc::Channel immediately (a one-liner),
120 * (4) possibly use the `struc::Channel` API to send/receive messages with automatic end-to-end zero-copy
121 * performance; or use the unstructured ipc::transport layer instead if desired. (Alternatively to (2)-(4), one can
122 * use capnp-RPC with zero-copy via ipc::transport::struc::shm::rpc.) (5) Optionally one can also
123 * access a SHM-arena for direct C++ object placement and access in SHM; the SHM arenas are available from
124 * the session object.
125 *
126 * That said, read on if you want to maintain or otherwise more deeply understand Flow-IPC. There's a deeper
127 * organization of this monolith, in which one builds up the whole out of smaller parts, where we generally avoid
128 * circular dependencies (A needs B, and B needs A). Let's briefly go through the process of naming the most basic
129 * parts and then showing what depends on them, and so on, until everything is listed in bottom-up order. To wit:
130 *
131 * -# ipc::util: This contains basic, simple building blocks. ipc::util::Shared_name is used to name various
132 * shared resources throughout Flow-IPC. ipc::util::Native_handle is a trivial wrapper around a native handle
133 * (FD in POSIX/Linux/Unix parlance). There are various other items.
134 * - Dependents: Essentially all other code routinely depends on ipc::util.
135 * -# ipc::transport, *excluding* ipc::transport::struc: This is the transport *core layer*. Think of
136 * this as wrappers around native IPC transport APIs with which you may already be familiar: e.g., Unix domain
137 * sockets. There are key concepts, including ipc::transport::Blob_sender and `Blob_receiver`
138 * (+ `Native_handle_{send|receiv}er`); and their implementations over the aforementioned specific low-level
139 * transports (Unix domain sockets, MQs as of this writing). ipc::transport::Native_socket_stream, wrapping
140 * Unix domain sockets, implements all four and has generally prominent use.
141 * - Dependents:
142 * - ipc::transport::struc. The key part, `transport::struc::Channel` (the central object), adapts
143 * `transport::Channel`, including for example leveraging the fact an unstructured `Channel` might contain
144 * a blobs pipe *and* a native handles pipe.
145 * - ipc::session depends on ipc::transport, in that the most important function of an ipc::session::Session
146 * is to *painlessly create* (open) ipc::transport::Channel objects. You start a session to the opposing
147 * process; and you use that session to create 1+ channels; then you speak over these channels as needed.
148 * (It's typical to have N `Channel`s ready to go on session establishment; plus one can open more on-demand.)
149 * (*If* you want to speak using structured messages, you upgrade a `transport::Channel` to a
150 * `transport::struc::Channel`: a structured channel.)
151 * -# ipc::transport::struc: The transport *structured layer* builds on top of (1) the core layer and (2) capnp.
152 * `struc::Channel` adapts an unstructured `Channel`, allowing efficient transmission of structured messages
153 * filled-out according to user-provided capnp-generated schema(s). At its simplest, without the (spoiler alert)
154 * `shm` sub-namespace, an out-message is backed by the regular heap (`new` et al); and a received in-message is
155 * a copy also backed by the regular heap of the recipient process.
156 * - Dependents: ipc::session and ipc::session::shm::arena_lend, for orthogonal reasons, use
157 * ipc::transport::struc::Channel for their internal purposes. It's a useful guy!
158 * -# ipc::session, *excluding* ipc::session::shm: This is the core support for sessions, which are how one painlessly
159 * begins a conversation between your process and the opposing process. Without it you'll need to worry about
160 * low-level resource naming and cleanup; with it, it's taken care-of -- just open channels and use them.
161 * Spoiler alert: the sub-namespace `shm` (see below) will add SHM capabilities.
162 * - Dependents: ipc::session::shm builds on top of this.
163 * -# ipc::shm::stl: A couple of key facilities here enable storage of STL-compliant C++ data structures directly
164 * in SHM; e.g., a map from strings to vectors of strings and `struct`s and... etc. You, the user, will only
165 * directly use this, if you need such functionality. If you only need to send structured messages with
166 * zero-copy (which internally is achieved using SHM), then you need not directly mention this.
167 * - Dependents:
168 * - ipc::transport::struc::shm "eats our own dog food" by internally representing certain data
169 * structures using STL-compliant APIs, including `list<>` and `flow::util::Blob`.
170 * -# ipc::transport::struc::shm: This essentially just adds `shm::Builder` and `shm::Reader` which are impls
171 * of ipc::transport::struc::Struct_builder and `Struct_reader` concepts that enable end-to-end zero-copy
172 * transmission of any capnp-schema-based message -- as long as one has certain key SHM-enabling objects, most
173 * notably a `Shm_arena`.
174 * - Dependents:
175 * - ipc::session::shm mentions `shm::Builder` and `shm::Reader` in a convenience alias.
176 * - The bottom line is, if you use SHM-enabled sessions, to obtain end-to-end zero-copy perf when
177 * transmitting structured messages along channels, then ipc::transport::struc::shm shall be used,
178 * without your needing to mention it or worry about it.
179 * -# ipc::shm::classic: This is a *SHM-provider* (of SHM-arenas); namely the *SHM-classic* provider. The core item
180 * is ipc::shm::classic::Pool_arena, a "classic" single-segment (pool) SHM arena with a simple arena-allocation
181 * algorithm.
182 * - Dependents: ipc::session::shm::classic provides SHM-enabled sessions with this SHM-provider as the
183 * required SHM engine. Naturally in so doing it depends on ipc::shm::classic, especially `classic::Pool_arena`.
184 * -# ipc::shm::arena_lend (more specifically ipc::shm::arena_lend::jemalloc): This is the other *SHM-provider*
185 * (of SHM-arenas); namely the *SHM-jemalloc* provider. The core item is `jemalloc::Ipc_arena`.
186 * - Dependents: ipc::session::shm::arena_lend::jemalloc provides SHM-enabled sessions with this SHM-provider as
187 * the required SHM engine. Naturally in so doing it depends on ipc::shm::arena_lend::jemalloc,
188 * especially `jemalloc::Ipc_arena`.
189 * -# ipc::session::shm: This namespace adds SHM-enabled sessions. Namely that adds two capabilities; one: to
190 * easily get end-to-end zero-copy performance along `struc::Channel` objects opened via these sessions. Two:
191 * to have direct access to SHM-arena(s) in which to place and access C++ objects.
192 * - More specifically: ipc::session::shm::classic = SHM-classic-provider-enabled sessions;
193 * ipc::session::shm::arena_lend::jemalloc = SHM-jemalloc-provider-enabled sessions.
194 * - Dependents: ipc::transport::struc::shm::rpc (optionally, for session establishment).
195 * -# ipc::transport::struc::shm::rpc: capnp-RPC integration. It builds on ipc::transport::struc::shm (notably
196 * shm::Capnp_message_builder and shm::Capnp_message_reader); and optionally on ipc::session::shm, for
197 * peer-process discovery and session establishment.
198 * - Dependents: none (inside Flow-IPC).
199 *
200 * Again -- there's no need to understand all this, if you're just using Flow-IPC in the expected mainstream ways.
201 * Nevertheless it could be a useful, if wordy, map to the building blocks of Flow-IPC and how they interact.
202 *
203 * Distributed sub-components (libraries)
204 * --------------------------------------
205 * The above describes Flow-IPC as a whole. Generally we recommend a distribution of Flow-IPC which includes all
206 * the pieces, to be used at will. That said, for reasons outside our scope here, this project is actually distributed
207 * in a few parts, each of which is a library with a set of header files. (The generated documentation is created
208 * from all of them together, and therefore various comments aren't shy about referring to items across
209 * the boundaries between those parts, in any direction.) These parts (libraries) are:
210 *
211 * - `ipc_core`: Contains: ipc::util, ipc::transport (excluding ipc::transport::struc).
212 * - `ipc_transport_structured`: Contains: ipc::transport::struc (excluding ipc::transport::struc::shm).
213 * - `ipc_session`: Contains: ipc::session (excluding ipc::session::shm).
214 * - `ipc_shm`: Contains: ipc::shm::stl, ipc::transport::struc::shm
215 * (including ipc::transport::struc::shm::classic and ipc::transport::struc::shm::rpc
216 * but excluding all other such sub-namespaces),
217 * ipc::shm::classic + ipc::session::shm::classic.
218 * - `ipc_shm_arena_lend`: Contains: ipc::transport::struc::shm::arena_lend,
219 * ipc::shm::arena_lend + ipc::session::shm::arena_lend.
220 *
221 * The dependencies between these are as follows:
222 * - `ipc_core` <- `ipc_transport_structured` <- `ipc_session` <- `ipc_shm` <- `ipc_shm_arena_lend`.
223 * - (There are, e.g., direct dependencies redundant to the above, such as how `ipc_shm_arena_lend`
224 * depends on `ipc_transport_structured` in certain key internal impl details.)
225 *
226 * Each one, in the source code, is in a separate top-level directory; and generates a separate static library.
227 * However, their directory structures -- and accordingly the namespace trees -- overlap in naming, which
228 * manifests itself when 2 or more of the sub-components are installed together. For example `ipc_session`
229 * places `ipc/session` into the `#include` tree; and `ipc_shm` places `ipc/session/shm/classic` within that.
230 *
231 * To reiterate: If, as recommended, one installs all of Flow-IPC, then everything is exported into one
232 * directory (and namespace) structure together; and to the user the origin of each thing w/r/t the aforementioned
233 * parts/libraries probably will not much matter.
234 *
235 * Relationship with Flow and Boost
236 * --------------------------------
237 * Flow-IPC requires Flow and Boost, not only for internal implementation purposes but also in some of its APIs.
238 * For example, `flow::log` is the assumed logging system, and `flow::Error_code` -- which is
239 * `boost::system::error_code` -- and related conventions are used for error reporting; and `boost::interprocess`
240 * and `boost::thread` APIs may be exposed at times.
241 *
242 * Moreover, Flow-IPC shares Flow "DNA" in terms of coding style, error, logging, documentation, etc., conventions.
243 * Flow-IPC and Flow itself are also more loosely inspired by Boost "DNA." (For example: `snake_case` for identifier
244 * naming is inherited from Flow, which inherits it more loosely from Boost; the error reporting API convention is taken
245 * from Flow which uses a modified version of the boost.asio convention.)
246 *
247 * Documentation / Doxygen
248 * -----------------------
249 * All code in the project proper follows a high standard of documentation, almost solely via comments therein
250 * (plus a guided Manual in `manual/....dox.txt` files, also encoded as Doxygen-read comments).
251 * The standards and mechanics w/r/t documentation are entirely inherited from Flow. Therefore, see the
252 * `namespace flow` doc header's "Documentation / Doxygen" section. It applies
253 * verbatim here (within reason). (Spoiler alert: Doc header comments on most entities (classes, functions, ...) are
254 * friendly to doc web page generation by Doxygen. Doxygen is a tool similar to Javadoc.)
255 *
256 * The only exception to this is the addition of the aforementioned guided Manual as well which Flow lacks as of
257 * this writing.
258 *
259 * Using Flow-IPC modules
260 * ------------------------
261 * This section discusses usability topics that apply to all Flow-IPC modules including hopefully any future ones but
262 * definitely all existing ones as of this writing.
263 *
264 * ### Error reporting ###
265 * The standards and mechanics w/r/t error reporting are entirely inherited from Flow. Therefore, see the
266 * `namespace flow` doc header's "Error reporting" section. It applies verbatim (within reason) here.
267 *
268 * ### Logging ###
269 * We use the Flow log module, in `flow::log` namespace, for logging. We are just a consumer, but this does mean
270 * the Flow-IPC user must supply a `flow::log::Logger` into various APIs in order to enable logging. (Worst-case,
271 * passing a null `Logger*` will make it log nowhere.) See `flow::log` docs. Spoiler alert: You can hook it up to
272 * whatever logging output/other logging API you desire, or it can log for you in certain common ways including console
273 * and rotated files. Again, though, many users will bypass logging entirely by supplying
274 * `Logger* logger_ptr = nullptr` to relevant APIs.
275 *
276 * @internal
277 *
278 * Implementation notes
279 * --------------------
280 * There is a high standard of consistency and style, as well as documentation, in Flow-IPC. The standards and
281 * mechanics for all such aspects (including source tree org, code style, doc style) are entirely
282 * inherited from Flow. Therefore, see the `namespace flow` doc header: its analogous sections
283 * apply verbatim here (within reason).
284 */
285namespace ipc
286{
287
288// Types. They're outside of `namespace ::ipc::util` for brevity due to their frequent use.
289
290/* (The @namespace and @brief thingies shouldn't be needed, but some Doxygen bug necessitated them.
291 * See flow::log::fs for explanation... same thing here.) */
292
293/**
294 * @namespace ipc::bipc
295 * @brief Short-hand for boost.interprocess namespace.
296 */
297namespace bipc = boost::interprocess;
298
299/**
300 * @namespace ipc::fs
301 * @brief Short-hand for `filesystem` namespace.
302 *
303 * ### Rationale for aliasing to `boost::filesystem` instead of `std::filesystem` ###
304 * `boost::filesystem` is rock-solid and the model/original impl; which is not to say that always is enough
305 * to take it over the `std::` counterpart. However, some experiences with gcc-7's `std::filesystem` were
306 * negative; it did not exist, and `std::experimental::filesystem` lacked basic chunks from the standard.
307 * This left a bad taste in the mouth; whereas in the author's (ygoldfel) experience Boost's has been great.
308 * It is very mature.
309 */
310namespace fs = boost::filesystem;
311
312/// Short-hand for `flow::Error_code` which is very common.
314
315/// Short-hand for polymorphic functor holder which is very common. This is essentially `std::function`.
316template<typename Signature>
317using Function = flow::Function<Signature>;
318
319#ifdef IPC_DOXYGEN_ONLY // Actual compilation will ignore the below; but Doxygen will scan it and generate docs.
320
321/**
322 * The `flow::log::Component` payload enumeration containing various log components used by Flow-IPC internal logging.
323 * Internal Flow-IPC code specifies members thereof when indicating the log component for each particular piece of
324 * logging code. Flow-IPC user specifies it, albeit very rarely, when configuring their program's logging
325 * such as via `flow::log::Config::init_component_to_union_idx_mapping()` and
326 * `flow::log::Config::init_component_names()`.
327 *
328 * If you are reading this in Doxygen-generated output (likely a web page), be aware that the individual
329 * `enum` values are not documented right here, because `flow::log` auto-generates those via certain macro
330 * magic, and Doxygen cannot understand what is happening. However, you will find the same information
331 * directly in the source file `log_component_enum_declare.macros.hpp` (if the latter is clickable, click to see
332 * the source).
333 *
334 * ### Details regarding overall log system init in user program ###
335 * See comment in similar place in `flow/common.hpp`.
336 */
338{
339 /**
340 * CAUTION -- see ipc::Log_component doc header for directions to find actual members of this
341 * `enum class`. This entry is a placeholder for Doxygen purposes only, because of the macro magic involved
342 * in generating the actual `enum class`.
343 */
345};
346
347// Constants.
348
349/**
350 * The map generated by `flow::log` macro magic that maps each enumerated value in ipc::Log_component to its
351 * string representation as used in log output and verbosity config. Flow-IPC user specifies, albeit very rarely,
352 * when configuring their program's logging via `flow::log::Config::init_component_names()`.
353 *
354 * As a Flow-IPC user, you can informally assume that if the component `enum` member is called `S_SOME_NAME`, then
355 * its string counterpart in this map will be auto-computed to be `"SOME_NAME"` (optionally prepended with a
356 * prefix as supplied to `flow::log::Config::init_component_names()`). This is achieved via `flow::log` macro magic.
357 *
358 * @see ipc::Log_component first.
359 */
360extern const boost::unordered_multimap<Log_component, std::string> S_IPC_LOG_COMPONENT_NAME_MAP;
361
362#endif // IPC_DOXYGEN_ONLY
363
364} // namespace ipc
Catch-all namespace for the Flow-IPC project: A library/API in modern C++17 providing high-performanc...
Definition: common.cpp:22
Log_component
The flow::log::Component payload enumeration containing various log components used by Flow-IPC inter...
Definition: common.hpp:338
@ S_END_SENTINEL
CAUTION – see ipc::Log_component doc header for directions to find actual members of this enum class.
const boost::unordered_multimap< Log_component, std::string > S_IPC_LOG_COMPONENT_NAME_MAP
The map generated by flow::log macro magic that maps each enumerated value in ipc::Log_component to i...
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Definition: common.hpp:313
flow::Function< Signature > Function
Short-hand for polymorphic functor holder which is very common. This is essentially std::function.
Definition: common.hpp:317