]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc/mem/Segment.cc
2 * DEBUG: section 54 Interprocess Communication
7 #include "base/TextException.h"
8 #include "compat/shm.h"
11 #include "ipc/mem/Segment.h"
20 // test cases change this
21 const char *Ipc::Mem::Segment::BasePath
= DEFAULT_STATEDIR
;
24 Ipc::Mem::Segment::reserve(size_t chunkSize
)
27 // check for overflows
28 // chunkSize >= 0 may result in warnings on systems where off_t is unsigned
29 assert(!chunkSize
|| static_cast<off_t
>(chunkSize
) > 0);
30 assert(static_cast<off_t
>(chunkSize
) <= theSize
);
31 assert(theReserved
<= theSize
- static_cast<off_t
>(chunkSize
));
32 void *result
= reinterpret_cast<char*>(theMem
) + theReserved
;
33 theReserved
+= chunkSize
;
38 Ipc::Mem::Segment::Name(const SBuf
&prefix
, const char *suffix
)
42 result
.append(suffix
);
48 Ipc::Mem::Segment::Segment(const char *const id
):
49 theFD(-1), theName(GenerateName(id
)), theMem(NULL
),
50 theSize(0), theReserved(0), doUnlink(false)
54 Ipc::Mem::Segment::~Segment()
58 if (close(theFD
) != 0)
59 debugs(54, 5, HERE
<< "close " << theName
<< ": " << xstrerror());
65 // fake Ipc::Mem::Segment::Enabled (!HAVE_SHM) is more selective
67 Ipc::Mem::Segment::Enabled()
73 Ipc::Mem::Segment::create(const off_t aSize
)
78 theFD
= shm_open(theName
.termedBuf(), O_CREAT
| O_RDWR
| O_TRUNC
,
81 debugs(54, 5, HERE
<< "shm_open " << theName
<< ": " << xstrerror());
82 fatalf("Ipc::Mem::Segment::create failed to shm_open(%s): %s\n",
83 theName
.termedBuf(), xstrerror());
86 if (ftruncate(theFD
, aSize
)) {
87 debugs(54, 5, HERE
<< "ftruncate " << theName
<< ": " << xstrerror());
88 fatalf("Ipc::Mem::Segment::create failed to ftruncate(%s): %s\n",
89 theName
.termedBuf(), xstrerror());
92 assert(statSize("Ipc::Mem::Segment::create") == aSize
); // paranoid
98 debugs(54, 3, HERE
<< "created " << theName
<< " segment: " << theSize
);
104 Ipc::Mem::Segment::open()
108 theFD
= shm_open(theName
.termedBuf(), O_RDWR
, 0);
110 debugs(54, 5, HERE
<< "shm_open " << theName
<< ": " << xstrerror());
111 fatalf("Ipc::Mem::Segment::open failed to shm_open(%s): %s\n",
112 theName
.termedBuf(), xstrerror());
115 theSize
= statSize("Ipc::Mem::Segment::open");
117 debugs(54, 3, HERE
<< "opened " << theName
<< " segment: " << theSize
);
122 /// Map the shared memory segment to the process memory space.
124 Ipc::Mem::Segment::attach()
129 // mmap() accepts size_t for the size; we give it off_t which might
130 // be bigger; assert overflows until we support multiple mmap()s?
131 assert(theSize
== static_cast<off_t
>(static_cast<size_t>(theSize
)));
134 mmap(NULL
, theSize
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, theFD
, 0);
135 if (p
== MAP_FAILED
) {
136 debugs(54, 5, HERE
<< "mmap " << theName
<< ": " << xstrerror());
137 fatalf("Ipc::Mem::Segment::attach failed to mmap(%s): %s\n",
138 theName
.termedBuf(), xstrerror());
143 /// Unmap the shared memory segment from the process memory space.
145 Ipc::Mem::Segment::detach()
150 if (munmap(theMem
, theSize
)) {
151 debugs(54, 5, HERE
<< "munmap " << theName
<< ": " << xstrerror());
152 fatalf("Ipc::Mem::Segment::detach failed to munmap(%s): %s\n",
153 theName
.termedBuf(), xstrerror());
159 Ipc::Mem::Segment::unlink()
161 if (shm_unlink(theName
.termedBuf()) != 0)
162 debugs(54, 5, HERE
<< "shm_unlink(" << theName
<< "): " << xstrerror());
164 debugs(54, 3, HERE
<< "unlinked " << theName
<< " segment");
167 /// determines the size of the underlying "file"
169 Ipc::Mem::Segment::statSize(const char *context
) const
174 memset(&s
, 0, sizeof(s
));
176 if (fstat(theFD
, &s
) != 0) {
177 debugs(54, 5, HERE
<< context
<< " fstat " << theName
<< ": " << xstrerror());
178 fatalf("Ipc::Mem::Segment::statSize: %s failed to fstat(%s): %s\n",
179 context
, theName
.termedBuf(), xstrerror());
185 /// Generate name for shared memory segment. Starts with a prefix required
186 /// for cross-platform portability and replaces all slashes in ID with dots.
188 Ipc::Mem::Segment::GenerateName(const char *id
)
190 assert(BasePath
&& *BasePath
);
191 static const bool nameIsPath
= shm_portable_segment_name_is_path();
194 name
.append(BasePath
);
195 if (name
[name
.size()-1] != '/')
198 name
.append("/squid-");
200 // append id, replacing slashes with dots
201 for (const char *slash
= strchr(id
, '/'); slash
; slash
= strchr(id
, '/')) {
203 name
.append(id
, slash
- id
);
210 name
.append(".shm"); // to distinguish from non-segments when nameIsPath
218 typedef std::map
<String
, Ipc::Mem::Segment
*> SegmentMap
;
219 static SegmentMap Segments
;
221 Ipc::Mem::Segment::Segment(const char *const id
):
222 theName(id
), theMem(NULL
), theSize(0), theReserved(0), doUnlink(false)
226 Ipc::Mem::Segment::~Segment()
229 delete [] static_cast<char *>(theMem
);
231 Segments
.erase(theName
);
232 debugs(54, 3, HERE
<< "unlinked " << theName
<< " fake segment");
237 Ipc::Mem::Segment::Enabled()
239 return !UsingSmp() && IamWorkerProcess();
243 Ipc::Mem::Segment::create(const off_t aSize
)
247 checkSupport("Fake segment creation");
249 const bool inserted
= Segments
.insert(std::make_pair(theName
, this)).second
;
251 fatalf("Duplicate fake segment creation: %s", theName
.termedBuf());
253 theMem
= new char[aSize
];
257 debugs(54, 3, HERE
<< "created " << theName
<< " fake segment: " << theSize
);
261 Ipc::Mem::Segment::open()
264 checkSupport("Fake segment open");
266 const SegmentMap::const_iterator i
= Segments
.find(theName
);
267 if (i
== Segments
.end())
268 fatalf("Fake segment not found: %s", theName
.termedBuf());
270 const Segment
&segment
= *i
->second
;
271 theMem
= segment
.theMem
;
272 theSize
= segment
.theSize
;
274 debugs(54, 3, HERE
<< "opened " << theName
<< " fake segment: " << theSize
);
278 Ipc::Mem::Segment::checkSupport(const char *const context
)
281 debugs(54, 5, HERE
<< context
<<
282 ": True shared memory segments are not supported. "
283 "Cannot fake shared segments in SMP config.");
284 fatalf("Ipc::Mem::Segment: Cannot fake shared segments in SMP config (%s)\n",
292 Ipc::Mem::RegisteredRunner::useConfig()
294 // If Squid is built with real segments, we create() real segments
295 // in the master process only. Otherwise, we create() fake
296 // segments in each worker process. We assume that only workers
297 // need and can work with fake segments.
299 if (IamMasterProcess())
301 if (IamWorkerProcess())
305 // we assume that master process does not need shared segments
306 // unless it is also a worker
307 if (!InDaemonMode() || !IamMasterProcess())