Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
util_fwd.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#include "ipc/util/util_fwd.hpp"
23#include <flow/common.hpp>
24#include <boost/array.hpp>
25#include <boost/asio/readable_pipe.hpp>
26#include <boost/asio/writable_pipe.hpp>
27#include <iosfwd>
28
29namespace ipc::util
30{
31
32// Types.
33
34/// Short-hand for anonymous pipe write end.
35using Pipe_writer = boost::asio::writable_pipe;
36
37/// Short-hand for anonymous pipe read end.
38using Pipe_reader = boost::asio::readable_pipe;
39
40// Constants.
41
42/**
43 * Maps general Permissions_level specifier to low-level #Permissions value, when the underlying resource
44 * is in the file-system and is either accessible (read-write in terms of file system) or inaccessible.
45 * Examples of such resources are SHM pools (in Linux living in `/dev/shm`) and POSIX MQs (`/dev/mqueue`).
46 *
47 * See any additional user-facing notes in shared_resource_permissions() doc header.
48 */
49extern const boost::array<Permissions, size_t(Permissions_level::S_END_SENTINEL)>
51
52/**
53 * Maps general Permissions_level specifier to low-level #Permissions value, when the underlying resource
54 * is in the file-system (e.g., a file) and is *produced* (and therefore always writable) by the owning (creating,
55 * updating) user; but *consumed* (and therefore at most readable, never writable) by potentially other processes,
56 * and therefore possibly other users (e.g., group access or unrestricted access -- but only for reading either way).
57 * For example a PID file is typically only writable by the daemon's user but may be readable or inaccessible by
58 * other users.
59 */
60extern const boost::array<Permissions, size_t(Permissions_level::S_END_SENTINEL)>
62
63#ifndef FLOW_OS_LINUX
64static_assert(false, "IPC_KERNEL_PERSISTENT_RUN_DIR (/var/run) semantics require Unix; "
65 "tested in Linux specifically only.");
66#endif
67/**
68 * Absolute path to the directory (without trailing separator) in the file system where kernel-persistent
69 * runtime, but not temporary, information shall be placed. Kernel-persistent means that it'll disappear
70 * at reboot; runtime, but not temporary, means it's... not the designated temporary-data directory (informally:
71 * not `/tmp`). Informally: just know that it is `/var/run`, and that it stores things such as process-ID (PID)
72 * files.
73 *
74 * It is a Unix path, absolute (starts with forward-slash), and lexically normal (and lacks a root-name).
75 */
76extern const fs::path IPC_KERNEL_PERSISTENT_RUN_DIR;
77
78// Free functions.
79
80/**
81 * Internal (to ::ipc) utility that invokes the given function that invokes a boost.interprocess operation
82 * that is documented to throw `bipc::interprocess_exception` on failure; if indeed it throws the utility
83 * emits an error in the Flow error-reporting style. On error it logs WARNING with all available details.
84 *
85 * Only `bipc::interprocess_exception` is caught. Any other exception is not caught.
86 *
87 * ### Background ###
88 * boost.interprocess has a number of operations that are documented to throw the aforementioned exception
89 * on error -- without any alternate way of reporting an error such as through an out-arg. Moreover the
90 * exception itself is not any standard runtime-exception type but rather a custom thing. This is somewhat
91 * annoying; and various parts of ::ipc want to emit errors in a consistent way. That does *not* mean
92 * we must only emit some `transport::error::Code::*` or whatever, but we should emit (either as an out-arg or
93 * as a `flow::error::Runtime_error` wrapping it) a native-based #Error_code if applicable, or indeed one of our
94 * own codes otherwise.
95 *
96 * So this helper standardizes that stuff.
97 *
98 * @tparam Func
99 * Functor that takes no args and returns nothing.
100 * @param logger_ptr
101 * Logger to use for logging subsequently (null OK as usual).
102 * @param err_code
103 * `err_code` as-if passed to our API. `*err_code` shall be set if not null depending on success/failure;
104 * if null and no problem, won't throw; if null and problem will throw `Runtime_error` containing a truthy
105 * `Error_code`. Those are the usual Flow-style error emission semantics.
106 * @param misc_bipc_lib_error
107 * If `func` throws, and we are unable to suss out the system error that caused it, then emit
108 * this value. E.g.: transport::error::Code::S_MQ_BIPC_MISC_LIBRARY_ERROR makes sense if creating
109 * a `bipc::message_queue`; or a similar one for SHM-related parts of `bipc`; etc.
110 * @param context
111 * Description for logging of the op being attempted, in case there is an error. Compile-time-known strings
112 * are best, as this is not protected by a filtering macro and hence will be evaluated no matter what.
113 * @param func
114 * `func()` shall be executed synchronously.
115 */
116template<typename Func>
117void op_with_possible_bipc_exception(flow::log::Logger* logger_ptr, Error_code* err_code,
118 const Error_code& misc_bipc_lib_error,
119 String_view context,
120 const Func& func);
121
122/**
123 * Writes a byte to the given pipe writer. If any error occurs => undefined behavior (assert may trip).
124 * If it would-block... it will block. So: only use if your algorithm has made sure you will never reach the
125 * pipe's capacity.
126 *
127 * @param logger_ptr
128 * Logger to use for logging subsequently.
129 * @param pipe
130 * The pipe.
131 */
132void pipe_produce(flow::log::Logger* logger_ptr, Pipe_writer* pipe);
133
134/**
135 * Reads a byte via the given pipe reader. If any error occurs => undefined behavior (assert may trip).
136 * If it would-block... it will block. So: only use if your algorithm has made sure you have a byte in there.
137 *
138 * @param logger_ptr
139 * Logger to use for logging subsequently.
140 * @param pipe
141 * The pipe.
142 */
143void pipe_consume(flow::log::Logger* logger_ptr, Pipe_reader* pipe);
144
145/**
146 * Builds an absolute name according to the path convention explained in Shared_name class doc header;
147 * this overload applies to resources *outside* the ipc::session paradigm. Typically one
148 * would then add a Shared_name::S_SEPARATOR and then purpose-specific path component(s) (via `/=` or similar).
149 *
150 * Behavior is undefined if a path fragment argument is empty (assertion may trip).
151 *
152 * @param resource_type
153 * Resource type constant. Typically it is available as a `S_RESOURCE_TYPE_ID` constant in some class;
154 * otherwise as a `Shared_name::S_RESOURCE_TYPE_ID_*` constant.
155 * @return Absolute path not ending in `S_SEPARATOR`, typically to be appended with a `S_SEPARATOR` and more
156 * component(s) by the caller.
157 */
159
160/**
161 * Implementation of `Persistent_object::for_each_persistent()`; for example see
162 * shm::classic::Pool_arena::for_each_persistent(). It relies on the OS feature wherein each particular
163 * `Persistent_object` (kernel-persistent object) type is listed in flat fashion in a particular
164 * directory; `persistent_obj_dev_dir_path` must specify this directory.
165 *
166 * Conceptually, we shall perform `ls D/`, where `D` is `persistent_obj_dev_dir_path`. Then for each
167 * resulting `D/N`, we shall call `handle_name_func(N)`.
168 *
169 * ### Errors (or lack thereof) ###
170 * There is no error condition. If `persistent_obj_dev_dir_path` does not exist, or we lack permissions to
171 * look therein, it merely means it cannot contain any relevant items; hence `handle_name_func()` is not invoked.
172 *
173 * If `handle_name_func()` throws, this function does not go through any remaining entries; the exception
174 * is not caught.
175 *
176 * @tparam Handle_name_func
177 * See, e.g., shm::classic::Pool_arena::for_each_persistent().
178 * @param persistent_obj_dev_dir_path
179 * This must be an absolute path, or behavior is undefined (assertion may trip). See above.
180 * @param handle_name_func
181 * See `Handle_name_func`.
182 */
183template<typename Handle_name_func>
184void for_each_persistent_impl(const fs::path& persistent_obj_dev_dir_path, const Handle_name_func& handle_name_func);
185
186/**
187 * Equivalent to shm::classic::Pool_arena::for_each_persistent(). Provided here (for internal purposes as of this
188 * writing) to avoid a little circular-inter-component-dependent problem: Posix_mq_handle::for_each_persistent()
189 * needs us; but accessing `Pool_arena` would mean `ipc_core` Flow-IPC sub-component needing `ipc_shm`
190 * sub-component as a dependency... but the reverse is already naturally the case. See ::ipc namespace doc header
191 * for discussion of the component hierarchy, and how we prefer to avoid circular dependencies therein.
192 *
193 * @tparam Handle_name_func
194 * See above.
195 * @param handle_name_func
196 * See above.
197 */
198template<typename Handle_name_func>
199void for_each_persistent_shm_pool(const Handle_name_func& handle_name_func);
200
201/**
202 * Equivalent to shm::classic::Pool_arena::remove_persistent(). Provided for similar reason to that described
203 * in for_each_persistent_shm_pool() doc header nearby.
204 *
205 * @param logger_ptr
206 * See above.
207 * @param name
208 * See above.
209 * @param err_code
210 * See above.
211 */
212void remove_persistent_shm_pool(flow::log::Logger* logger_ptr, const Shared_name& name, Error_code* err_code);
213
214} // namespace ipc::util
215
217{
218
219// Types.
220
221// Find doc headers near the bodies of these compound types.
222
224
225// Free functions.
226
227/**
228 * Prints string representation of the given `Timer_event_emitter` to the given `ostream`.
229 *
230 * @relatesalso Timer_event_emitter
231 *
232 * @param os
233 * Stream to which to write.
234 * @param val
235 * Object to serialize.
236 * @return `os`.
237 */
238std::ostream& operator<<(std::ostream& os, const Timer_event_emitter& val);
239
240} // namespace ipc::util::sync_io
String-wrapping abstraction representing a name uniquely distinguishing a kernel-persistent entity fr...
An object of this type, used internally to implement sync_io-pattern objects that require timer event...
Contains common code, as well as important explanatory documentation in the following text,...
Definition: util_fwd.hpp:217
std::ostream & operator<<(std::ostream &os, const Timer_event_emitter &val)
Prints string representation of the given Timer_event_emitter to the given ostream.
Flow-IPC module containing miscellaneous general-use facilities that are ubiquitously used by ~all Fl...
Definition: util.cpp:31
bipc::permissions Permissions
Short-hand for Unix (POSIX) permissions class.
Definition: util_fwd.hpp:158
void remove_persistent_shm_pool(flow::log::Logger *logger_ptr, const Shared_name &pool_name, Error_code *err_code)
Equivalent to shm::classic::Pool_arena::remove_persistent().
Definition: util.cpp:112
@ S_END_SENTINEL
Sentinel: not a valid value. May be used to, e.g., size an array<> mapping from Permissions_level.
void for_each_persistent_impl(const fs::path &persistent_obj_dev_dir_path, const Handle_name_func &handle_name_func)
Implementation of Persistent_object::for_each_persistent(); for example see shm::classic::Pool_arena:...
Definition: util.hpp:91
void pipe_produce(flow::log::Logger *logger_ptr, Pipe_writer *pipe)
Writes a byte to the given pipe writer.
Definition: util.cpp:60
const boost::array< Permissions, size_t(Permissions_level::S_END_SENTINEL)> SHARED_RESOURCE_PERMISSIONS_LVL_MAP
Maps general Permissions_level specifier to low-level Permissions value, when the underlying resource...
Definition: util.cpp:38
Shared_name build_conventional_non_session_based_shared_name(const Shared_name &resource_type)
Builds an absolute name according to the path convention explained in Shared_name class doc header; t...
void for_each_persistent_shm_pool(const Handle_name_func &handle_name_func)
Equivalent to shm::classic::Pool_arena::for_each_persistent().
Definition: util.hpp:136
void pipe_consume(flow::log::Logger *logger_ptr, Pipe_reader *pipe)
Reads a byte via the given pipe reader.
Definition: util.cpp:89
boost::asio::writable_pipe Pipe_writer
Short-hand for anonymous pipe write end.
Definition: util_fwd.hpp:35
const boost::array< Permissions, size_t(Permissions_level::S_END_SENTINEL)> PRODUCER_CONSUMER_RESOURCE_PERMISSIONS_LVL_MAP
Maps general Permissions_level specifier to low-level Permissions value, when the underlying resource...
Definition: util.cpp:46
const fs::path IPC_KERNEL_PERSISTENT_RUN_DIR
Absolute path to the directory (without trailing separator) in the file system where kernel-persisten...
Definition: util.cpp:56
boost::asio::readable_pipe Pipe_reader
Short-hand for anonymous pipe read end.
Definition: util_fwd.hpp:38
void op_with_possible_bipc_exception(flow::log::Logger *logger_ptr, Error_code *err_code, const Error_code &misc_bipc_lib_error, String_view context, const Func &func)
Internal (to ipc) utility that invokes the given function that invokes a boost.interprocess operation...
Definition: util.hpp:35
flow::util::String_view String_view
Short-hand for Flow's String_view.
Definition: util_fwd.hpp:112
flow::Error_code Error_code
Short-hand for flow::Error_code which is very common.
Definition: common.hpp:313