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