]>
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"
19 // test cases change this
20 const char *Ipc::Mem::Segment::BasePath
= DEFAULT_STATEDIR
;
23 Ipc::Mem::Segment::reserve(size_t chunkSize
)
26 // check for overflows
27 // chunkSize >= 0 may result in warnings on systems where off_t is unsigned
28 assert(!chunkSize
|| static_cast<off_t
>(chunkSize
) > 0);
29 assert(static_cast<off_t
>(chunkSize
) <= theSize
);
30 assert(theReserved
<= theSize
- static_cast<off_t
>(chunkSize
));
31 void *result
= reinterpret_cast<char*>(theMem
) + theReserved
;
32 theReserved
+= chunkSize
;
38 Ipc::Mem::Segment::Segment(const char *const id
):
39 theFD(-1), theName(GenerateName(id
)), theMem(NULL
),
40 theSize(0), theReserved(0), doUnlink(false)
44 Ipc::Mem::Segment::~Segment()
48 if (close(theFD
) != 0)
49 debugs(54, 5, HERE
<< "close " << theName
<< ": " << xstrerror());
55 // fake Ipc::Mem::Segment::Enabled (!HAVE_SHM) is more selective
57 Ipc::Mem::Segment::Enabled()
63 Ipc::Mem::Segment::create(const off_t aSize
)
68 theFD
= shm_open(theName
.termedBuf(), O_CREAT
| O_RDWR
| O_TRUNC
,
71 debugs(54, 5, HERE
<< "shm_open " << theName
<< ": " << xstrerror());
72 fatalf("Ipc::Mem::Segment::create failed to shm_open(%s): %s\n",
73 theName
.termedBuf(), xstrerror());
76 if (ftruncate(theFD
, aSize
)) {
77 debugs(54, 5, HERE
<< "ftruncate " << theName
<< ": " << xstrerror());
78 fatalf("Ipc::Mem::Segment::create failed to ftruncate(%s): %s\n",
79 theName
.termedBuf(), xstrerror());
82 assert(statSize("Ipc::Mem::Segment::create") == aSize
); // paranoid
88 debugs(54, 3, HERE
<< "created " << theName
<< " segment: " << theSize
);
94 Ipc::Mem::Segment::open()
98 theFD
= shm_open(theName
.termedBuf(), O_RDWR
, 0);
100 debugs(54, 5, HERE
<< "shm_open " << theName
<< ": " << xstrerror());
101 fatalf("Ipc::Mem::Segment::open failed to shm_open(%s): %s\n",
102 theName
.termedBuf(), xstrerror());
105 theSize
= statSize("Ipc::Mem::Segment::open");
107 debugs(54, 3, HERE
<< "opened " << theName
<< " segment: " << theSize
);
112 /// Map the shared memory segment to the process memory space.
114 Ipc::Mem::Segment::attach()
119 // mmap() accepts size_t for the size; we give it off_t which might
120 // be bigger; assert overflows until we support multiple mmap()s?
121 assert(theSize
== static_cast<off_t
>(static_cast<size_t>(theSize
)));
124 mmap(NULL
, theSize
, PROT_READ
| PROT_WRITE
, MAP_SHARED
, theFD
, 0);
125 if (p
== MAP_FAILED
) {
126 debugs(54, 5, HERE
<< "mmap " << theName
<< ": " << xstrerror());
127 fatalf("Ipc::Mem::Segment::attach failed to mmap(%s): %s\n",
128 theName
.termedBuf(), xstrerror());
133 /// Unmap the shared memory segment from the process memory space.
135 Ipc::Mem::Segment::detach()
140 if (munmap(theMem
, theSize
)) {
141 debugs(54, 5, HERE
<< "munmap " << theName
<< ": " << xstrerror());
142 fatalf("Ipc::Mem::Segment::detach failed to munmap(%s): %s\n",
143 theName
.termedBuf(), xstrerror());
149 Ipc::Mem::Segment::unlink()
151 if (shm_unlink(theName
.termedBuf()) != 0)
152 debugs(54, 5, HERE
<< "shm_unlink(" << theName
<< "): " << xstrerror());
154 debugs(54, 3, HERE
<< "unlinked " << theName
<< " segment");
157 /// determines the size of the underlying "file"
159 Ipc::Mem::Segment::statSize(const char *context
) const
164 memset(&s
, 0, sizeof(s
));
166 if (fstat(theFD
, &s
) != 0) {
167 debugs(54, 5, HERE
<< context
<< " fstat " << theName
<< ": " << xstrerror());
168 fatalf("Ipc::Mem::Segment::statSize: %s failed to fstat(%s): %s\n",
169 context
, theName
.termedBuf(), xstrerror());
175 /// Generate name for shared memory segment. Starts with a prefix required
176 /// for cross-platform portability and replaces all slashes in ID with dots.
178 Ipc::Mem::Segment::GenerateName(const char *id
)
180 assert(BasePath
&& *BasePath
);
181 static const bool nameIsPath
= shm_portable_segment_name_is_path();
184 name
.append(BasePath
);
185 if (name
[name
.size()-1] != '/')
188 name
.append("/squid-");
190 // append id, replacing slashes with dots
191 for (const char *slash
= strchr(id
, '/'); slash
; slash
= strchr(id
, '/')) {
193 name
.append(id
, slash
- id
);
200 name
.append(".shm"); // to distinguish from non-segments when nameIsPath
208 typedef std::map
<String
, Ipc::Mem::Segment
*> SegmentMap
;
209 static SegmentMap Segments
;
211 Ipc::Mem::Segment::Segment(const char *const id
):
212 theName(id
), theMem(NULL
), theSize(0), theReserved(0), doUnlink(false)
216 Ipc::Mem::Segment::~Segment()
219 delete [] static_cast<char *>(theMem
);
221 Segments
.erase(theName
);
222 debugs(54, 3, HERE
<< "unlinked " << theName
<< " fake segment");
227 Ipc::Mem::Segment::Enabled()
229 return !UsingSmp() && IamWorkerProcess();
233 Ipc::Mem::Segment::create(const off_t aSize
)
237 checkSupport("Fake segment creation");
239 const bool inserted
= Segments
.insert(std::make_pair(theName
, this)).second
;
241 fatalf("Duplicate fake segment creation: %s", theName
.termedBuf());
243 theMem
= new char[aSize
];
247 debugs(54, 3, HERE
<< "created " << theName
<< " fake segment: " << theSize
);
251 Ipc::Mem::Segment::open()
254 checkSupport("Fake segment open");
256 const SegmentMap::const_iterator i
= Segments
.find(theName
);
257 if (i
== Segments
.end())
258 fatalf("Fake segment not found: %s", theName
.termedBuf());
260 const Segment
&segment
= *i
->second
;
261 theMem
= segment
.theMem
;
262 theSize
= segment
.theSize
;
264 debugs(54, 3, HERE
<< "opened " << theName
<< " fake segment: " << theSize
);
268 Ipc::Mem::Segment::checkSupport(const char *const context
)
271 debugs(54, 5, HERE
<< context
<<
272 ": True shared memory segments are not supported. "
273 "Cannot fake shared segments in SMP config.");
274 fatalf("Ipc::Mem::Segment: Cannot fake shared segments in SMP config (%s)\n",
282 Ipc::Mem::RegisteredRunner::run(const RunnerRegistry
&r
)
284 // If Squid is built with real segments, we create() real segments
285 // in the master process only. Otherwise, we create() fake
286 // segments in each worker process. We assume that only workers
287 // need and can work with fake segments.
289 if (IamMasterProcess())
291 if (IamWorkerProcess())
295 // we assume that master process does not need shared segments
296 // unless it is also a worker
297 if (!InDaemonMode() || !IamMasterProcess())