vulp  2.3.0
AgentInterface.cpp
Go to the documentation of this file.
1 // SPDX-License-Identifier: Apache-2.0
2 // Copyright 2022 Stéphane Caron
3 
5 
6 #include <spdlog/spdlog.h>
7 #include <unistd.h>
8 
9 namespace vulp::spine {
10 
16 void allocate_file(int file_descriptor, int bytes) {
17  struct ::stat file_stats;
18 
19  if (::ftruncate(file_descriptor, bytes) < 0) {
20  throw std::runtime_error("Error truncating file, errno is " +
21  std::to_string(errno));
22  }
23 
24  ::fstat(file_descriptor, &file_stats);
25  if (file_stats.st_size < bytes) {
26  throw std::runtime_error(
27  "Error allocating " + std::to_string(bytes) +
28  " bytes in shared memory. Errno is : " + std::to_string(errno));
29  }
30 }
31 
32 AgentInterface::AgentInterface(const std::string& name, size_t size)
33  : name_(name), size_(size) {
34  // Allocate shared memory
35  // About umask: see https://stackoverflow.com/a/11909753
36  mode_t existing_umask = ::umask(0);
37  int file_descriptor =
38  ::shm_open(name.c_str(), O_RDWR | O_CREAT | O_EXCL, 0666);
39  ::umask(existing_umask);
40  if (file_descriptor < 0) {
41  if (errno == EINVAL) {
42  spdlog::error("Cannot open shared memory \"{}\": file name is invalid.",
43  name);
44  } else if (errno == EEXIST) {
45  spdlog::error(
46  "Cannot open shared memory \"{}\": file already exists. Is a spine "
47  "already running?",
48  name);
49  spdlog::info(
50  "If not other spine is running but a previous spine did not exit "
51  "properly, you can run ``sudo rm /dev/shm{}`` to clean this error.",
52  name);
53  } else {
54  spdlog::error("Cannot open shared memory file: errno is {}", errno);
55  }
56  throw std::runtime_error("Error opening file");
57  }
58  allocate_file(file_descriptor, size);
59 
60  // Map shared memory
61  mmap_ = ::mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED,
62  file_descriptor, 0);
63  if (mmap_ == MAP_FAILED) {
64  throw std::runtime_error("Error mapping file");
65  }
66  if (::close(file_descriptor) < 0) {
67  throw std::runtime_error("Error closing file descriptor");
68  }
69 
70  // Initialize internal pointers
71  mmap_request_ = static_cast<uint32_t*>(mmap_);
72  mmap_size_ = static_cast<uint32_t*>(mmap_request_ + 1);
73  mmap_data_ = reinterpret_cast<char*>(mmap_size_ + 1);
74 }
75 
77  if (::munmap(mmap_, size_) < 0) {
78  spdlog::error("Failed to unmap memory; errno is {}", errno);
79  }
80  if (::shm_unlink(name_.c_str()) < 0) {
81  spdlog::error("Failed to unlink shared memory; errno is {}", errno);
82  }
83 }
84 
86  *mmap_request_ = static_cast<uint32_t>(request);
87 }
88 
89 void AgentInterface::write(char* data, size_t size) {
90  if (size_ <= size + 2 * sizeof(uint32_t)) {
91  spdlog::error(
92  "Trying to write {} bytes to agent interface buffer of size {} bytes",
93  size, size_);
94  throw std::runtime_error("Agent interface buffer overflow");
95  }
96  *mmap_size_ = size;
97  std::memcpy(mmap_data_, data, size);
98 }
99 
100 } // namespace vulp::spine
void set_request(Request request)
Set current request in shared memory.
void write(char *data, size_t size)
Write data to the data buffer in shared memory.
uint32_t size() const
Get size of current data buffer.
~AgentInterface()
Unmap memory and unlink shared memory object.
AgentInterface(const std::string &name, size_t size)
Open interface to the agent at a given shared-memory file.
const char * data() const
Get pointer to data buffer.
Request request() const
Get current request from shared memory.
Flag set by the agent to request an operation from the spine.
Definition: request.py:10
Inter-process communication protocol with the spine.
Definition: __init__.py:1
void allocate_file(int file_descriptor, int bytes)
Allocate file with some error handling.