Flow-IPC 3.0.0
Flow-IPC project: Full implementation reference.
sparse_shm_object.cpp
1/* Flow-IPC: Shared Memory
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
19#include <boost/interprocess/exceptions.hpp>
20#include <fcntl.h>
21#include <unistd.h>
22#include <cerrno>
23
24#ifndef FLOW_OS_LINUX
25static_assert(false, "ipc::shm::bipc_ext is built around Linux SHM semantics: a POSIX SHM object is a tmpfs "
26 "file; ftruncate() merely sets its size, pages being committed (RAM taken) only once "
27 "first written; posix_fallocate() commits them all up-front. Whether and how any of that "
28 "holds elsewhere (macOS/ARM64 et al) is untested and will need thoughtful design when "
29 "porting.");
30#endif
31
32namespace ipc::shm::bipc_ext
33{
34
35// Sparse_shm_object implementations.
36
37void Sparse_shm_object::truncate(bipc::offset_t length)
38{
39 using ::ftruncate;
40 using bipc::interprocess_exception;
41 using bipc::error_info;
42 using bipc::system_error_code;
43
44 /* See our doc header for all relevant background. In short: an overzealous/non-sparse# Base::truncate() =
45 * posix_fallocate(hndl, length), then ftruncate(hndl, length). This truncate() = just the latter; and
46 * commit() performs the equivalent of the former (but re-determines `length` automatically itself).
47 *
48 * # - Whether Base::truncate() is actually overzealous/non-sparse depends on Boost version.
49 * We don't necessarily care; we just do what we advertised. Just pointing out that we internally do the same
50 * stuff as a certain vanilla bipc would, modulo *which* actual method does it. */
51 int rc;
52 do
53 {
54 rc = ftruncate(get_mapping_handle().handle, length);
55 }
56 while ((rc == -1) && (errno == EINTR));
57
58 if (rc == -1)
59 {
60 throw interprocess_exception{error_info{system_error_code()}};
61 }
62}
63
65{
66 using ::posix_fallocate;
67 using bipc::interprocess_exception;
68 using bipc::error_info;
69 using bipc::system_error_code;
70
71 /* This is the half of Base::truncate() that this->truncate() omits, made available on demand instead.
72 * posix_fallocate() commits every not-yet-committed page in [0, length): pages already written stay as they are.
73 * It is therefore idempotent and may be invoked at any time after truncate(), including after the object has
74 * been mapped and used. On tmpfs an ENOSPC failure rolls back whatever this call itself had allocated. */
75 bipc::offset_t length;
76 if (!get_size(length)) // Does fstat(); false means it failed.
77 {
78 throw interprocess_exception{error_info{system_error_code()}};
79 }
80 // else
81
82 int err;
83 do
84 {
85 err = posix_fallocate(get_mapping_handle().handle, 0, length);
86 }
87 while (err == EINTR);
88
89 if (err != 0)
90 {
91 throw interprocess_exception{error_info{err}};
92 }
93}
94
95} // namespace ipc::shm::bipc_ext
void truncate(bipc::offset_t length)
Hides Base::truncate(), which is not virtual; performs the truncate op; does not perform commit op.
void commit()
Commit (take RAM for) every page of the SHM-object's size as determined by the last truncate().
Extensions, informal or otherwise, of boost.ipc (boost::interprocess, bipc) SHM-related facilities,...