Project
Loading...
Searching...
No Matches
ShmManager.cxx
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11
12/*
13
14 * ShmManager.cxx
15 *
16 * Created on: Jun 17, 2018
17 * Author: swenzel
18 */
19
21#include <fairlogger/Logger.h>
22#include <sys/shm.h>
23#include <sys/ipc.h>
24#include <algorithm>
25
26#include <boost/interprocess/managed_external_buffer.hpp>
27#include <boost/interprocess/allocators/allocator.hpp>
28#include <sstream>
29#include <cstdlib>
30#include <cassert>
31
32using namespace boost::interprocess;
33
34namespace o2
35{
36namespace utils
37{
38
39// the shared mem id under which this is accessible
40const char* SHMIDNAME = "ALICEO2_SIMSHM_SHMID";
41// a common virtual address under which this should be mapped
42const char* SHMADDRNAME = "ALICEO2_SIMSHM_COMMONADDR";
43
44ShmManager::ShmManager() = default;
45
46void* ShmManager::tryAttach(bool& success)
47{
48 success = false;
49 if (auto id = getenv(SHMIDNAME)) {
50 mShmID = atoi(getenv(SHMIDNAME));
51 } else {
52 mShmID = -1;
53 return nullptr;
54 }
55 LOG(info) << "FOUND ID TO ATTACH " << mShmID;
56
57 // if the segment was not created in the first place ...
58 if (mShmID == -1) {
59 return nullptr;
60 }
61
62 void* addr_wanted;
63 if (auto addrstr = getenv(SHMADDRNAME)) {
64 addr_wanted = (void*)atoll(addrstr);
65 } else {
66 mShmID = -1;
67 return nullptr;
68 }
69 LOG(info) << "TRYING ADDRESS " << addr_wanted;
70 auto addr = shmat(mShmID, addr_wanted, 0);
71 if (addr != (void*)-1) {
72 // this means success
73 assert(addr == addr_wanted);
74 success = true;
75 mSegPtr = addr;
76 mSegInfoPtr = static_cast<o2::utils::ShmMetaInfo*>(mSegPtr);
77 return addr;
78 }
79
80 // trying without constraints
81 addr = shmat(mShmID, nullptr, 0);
82 if (addr == (void*)(-1)) {
83 LOG(fatal) << "SHOULD NOT HAPPEN";
84 }
85 // signal failure
86 auto info = static_cast<o2::utils::ShmMetaInfo*>(addr);
87 info->failures.fetch_add(1);
88 shmdt(addr);
89 mShmID = -1;
90 mSegInfoPtr = nullptr;
91 mSegPtr = nullptr;
92 // otherwise for now this means that we could not map the segment
93 // at the right place ...
94 return nullptr;
95}
96
98{
99 if (mSegInfoPtr) {
100 LOG(info) << "ATTACHED WORKERS " << mSegInfoPtr->counter;
101 LOG(info) << "CONNECTION FAILURES " << mSegInfoPtr->failures;
102 } else {
103 LOG(info) << "no segment info to print";
104 }
105}
106
108{
109 mIsMaster = true;
110 // first of all take a look if we really start from a clean state
111 if (mShmID != -1) {
112 LOG(warn) << "A SEGMENT IS ALREADY INITIALIZED";
113 return false;
114 }
115 // make sure no one else has created the shm pool
116 // TODO: this can be relaxed / generalized
117 if (getenv(SHMIDNAME) || getenv(SHMADDRNAME)) {
118 LOG(warn) << "A SEGMET IS ALREADY PRESENT ON THE SYSTEM";
119 return false;
120 }
121
122#ifdef USESHM
123 LOG(info) << "CREATING SIM SHARED MEM SEGMENT FOR " << nsegments << " WORKERS";
124 // LOG(info) << "SIZEOF ShmMetaInfo " << sizeof(ShmMetaInfo);
125 const auto totalsize = sizeof(ShmMetaInfo) + SHMPOOLSIZE * nsegments;
126 if ((mShmID = shmget(IPC_PRIVATE, totalsize, IPC_CREAT | 0666)) == -1) {
127 perror("shmget: shmget failed");
128 } else {
129 // We are attaching once to determine a common virtual address under which everyone else should attach.
130 // In this case (if it succeeds) we can also share objects with shm pointers
131 auto addr = shmat(mShmID, nullptr, 0);
132 mSegPtr = addr;
133 LOG(debug) << "COMMON ADDRESS " << addr << " AS NUMBER " << (unsigned long long)addr;
134
135 // initialize the meta information (counter)
137 std::memcpy(addr, &info, sizeof(info));
138 mSegInfoPtr = static_cast<o2::utils::ShmMetaInfo*>(mSegPtr);
139 mSegInfoPtr->allocedbytes = totalsize;
140
141 // communicating information about this segment via
142 // an environment variable
143 // TODO: consider using named posix shared memory segments to avoid this
144 setenv(SHMIDNAME, std::to_string(mShmID).c_str(), 1);
145 setenv(SHMADDRNAME, std::to_string((unsigned long long)(addr)).c_str(), 1);
146 return true;
147 }
148 LOG(info) << "SHARED MEM INITIALIZED AT ID " << mShmID;
149 if (mShmID == -1) {
150 LOG(warn) << "COULD NOT CREATE SHARED MEMORY ... FALLING BACK TO SIMPLE MODE";
151 setenv(SHMIDNAME, std::to_string(mShmID).c_str(), 1);
152 setenv(SHMADDRNAME, std::to_string(0).c_str(), 1);
153 }
154#endif
155 return false;
156}
157
159{
160 LOG(info) << "OCCUPYING A SEGMENT IN A SHARED REGION";
161 // get information about the global shared mem in which to occupy a region
162 if (!(getenv(SHMIDNAME) && getenv(SHMADDRNAME))) {
163 LOG(warn) << "NO INFORMATION ABOUT SHARED SEGMENT FOUND";
164 return false;
165 }
166
167 if (mShmID != -1) {
168 LOG(warn) << "REGION ALREADY OCCUPIED OR CREATED";
169 return false;
170 }
171
172 bool b;
173 tryAttach(b);
174 return b;
175}
176
178{
179 LOG(info) << "OCCUPYING A SEGMENT IN A SHARED REGION";
180 // get information about the global shared mem in which to occupy a region
181 if (!(getenv(SHMIDNAME) && getenv(SHMADDRNAME))) {
182 LOG(warn) << "NO INFORMATION ABOUT SHARED SEGMENT FOUND";
183 return;
184 }
185
186 if (mShmID != -1) {
187 LOG(warn) << "REGION ALREADY OCCUPIED OR CREATED";
188 return;
189 }
190
191 bool b;
192 auto addr = tryAttach(b);
193 if (b) {
194 // read meta information in the segment to determine the id of this segment
195 auto info = static_cast<o2::utils::ShmMetaInfo*>(addr);
196 const int segmentcounter = info->counter.fetch_add(1);
197 LOG(info) << "SEGMENTCOUNT " << segmentcounter;
198
199 const auto offset_in_bytes = sizeof(ShmMetaInfo) + segmentcounter * SHMPOOLSIZE;
200 mBufferPtr = (void*)(((char*)addr) + offset_in_bytes);
201
202 assert((unsigned long long)((char*)mBufferPtr - (char*)addr) + SHMPOOLSIZE <= info->allocedbytes);
203
204 boostmanagedbuffer = new boost::interprocess::wmanaged_external_buffer(create_only, mBufferPtr, SHMPOOLSIZE);
205 boostallocator = new boost::interprocess::allocator<char, wmanaged_external_buffer::segment_manager>(
206 boostmanagedbuffer->get_segment_manager());
207
208 LOG(info) << "SHARED MEM OCCUPIED AT ID " << mShmID << " AND SEGMENT COUNTER " << segmentcounter;
209 } else {
210 LOG(info) << "ATTACH NOT SUCCESSFUL";
211 }
212}
213
214ShmManager::~ShmManager()
215{
216 release();
217}
218
219// This implements a very malloc/free mechanism ...
220// ... but we are using available boost functionality
222{
223 void* addr = nullptr;
224 try {
225 addr = (void*)boostallocator->allocate(size).get();
226 } catch (const std::exception& e) {
227 LOG(fatal) << "THROW IN BOOST SHM ALLOCATION";
228 };
229 return addr;
230}
231
232void ShmManager::freememblock(void* ptr, size_t s)
233{
234 boostallocator->deallocate((char*)ptr, s);
235}
236
238{
239#ifdef USESHM
240 if (mIsMaster) {
241 LOG(debug) << "REMOVING SHARED MEM SEGMENT ID " << mShmID;
242 if (mShmID != -1) {
243 shmctl(mShmID, IPC_RMID, nullptr);
244 mShmID = -1;
245 }
246 }
247#endif
248}
249
250} // end namespace utils
251} // end namespace o2
TBranch * ptr
std::ostringstream debug
void * getmemblock(size_t size)
void printSegInfo() const
void freememblock(void *, std::size_t=1)
bool createGlobalSegment(int nsubsegments=1)
GLsizeiptr size
Definition glcorearb.h:659
GLboolean GLboolean GLboolean b
Definition glcorearb.h:1233
constexpr size_t SHMPOOLSIZE
Definition ShmManager.h:42
const char * SHMADDRNAME
const char * SHMIDNAME
a couple of static helper functions to create timestamp values for CCDB queries or override obsolete ...
std::string to_string(gsl::span< T, Size > span)
Definition common.h:52
Common utility functions.
std::atomic< int > failures
Definition ShmManager.h:49
std::atomic< int > counter
Definition ShmManager.h:47
unsigned long long allocedbytes
Definition ShmManager.h:46
LOG(info)<< "Compressed in "<< sw.CpuTime()<< " s"