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