]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc/MemMap.cc
2 * Copyright (C) 1996-2022 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* DEBUG: section 54 Interprocess Communication */
12 #include "ipc/MemMap.h"
13 #include "store_key_md5.h"
16 Ipc::MemMap::MemMap(const char *const aPath
) :
19 shared(shm_old(Shared
)(aPath
))
21 assert(shared
->limit
> 0); // we should not be created otherwise
22 debugs(54, 5, "attached map [" << path
<< "] created: " <<
27 Ipc::MemMap::Init(const char *const path
, const int limit
, const size_t extrasSize
)
29 assert(limit
> 0); // we should not be created otherwise
30 Owner
*const owner
= shm_new(Shared
)(path
, limit
, extrasSize
);
31 debugs(54, 5, "new map [" << path
<< "] created: " << limit
);
36 Ipc::MemMap::Init(const char *const path
, const int limit
)
38 return Init(path
, limit
, 0);
42 Ipc::MemMap::openForWriting(const cache_key
*const key
, sfileno
&fileno
)
44 debugs(54, 5, "trying to open slot for key " << storeKeyText(key
)
45 << " for writing in map [" << path
<< ']');
46 const int idx
= slotIndexByKey(key
);
48 if (Slot
*slot
= openForWritingAt(idx
)) {
57 Ipc::MemMap::openForWritingAt(const sfileno fileno
, bool overwriteExisting
)
59 Slot
&s
= shared
->slots
[fileno
];
60 ReadWriteLock
&lock
= s
.lock
;
62 if (lock
.lockExclusive()) {
63 assert(s
.writing() && !s
.reading());
65 // bail if we cannot empty this position
66 if (!s
.waitingToBeFreed
&& !s
.empty() && !overwriteExisting
) {
67 lock
.unlockExclusive();
68 debugs(54, 5, "cannot open existing entry " << fileno
<<
69 " for writing " << path
);
73 // free if the entry was used, keeping the entry locked
74 if (s
.waitingToBeFreed
|| !s
.empty())
80 debugs(54, 5, "opened slot at " << fileno
<<
81 " for writing in map [" << path
<< ']');
82 return &s
; // and keep the entry locked
85 debugs(54, 5, "failed to open slot at " << fileno
<<
86 " for writing in map [" << path
<< ']');
91 Ipc::MemMap::closeForWriting(const sfileno fileno
)
93 debugs(54, 5, "stop writing slot at " << fileno
<<
94 " in map [" << path
<< ']');
95 assert(valid(fileno
));
96 Slot
&s
= shared
->slots
[fileno
];
98 s
.lock
.unlockExclusive();
102 Ipc::MemMap::switchWritingToReading(const sfileno fileno
)
104 debugs(54, 5, "switching writing slot at " << fileno
<<
105 " to reading in map [" << path
<< ']');
106 assert(valid(fileno
));
107 Slot
&s
= shared
->slots
[fileno
];
109 s
.lock
.switchExclusiveToShared();
112 /// terminate writing the entry, freeing its slot for others to use
114 Ipc::MemMap::abortWriting(const sfileno fileno
)
116 debugs(54, 5, "abort writing slot at " << fileno
<<
117 " in map [" << path
<< ']');
118 assert(valid(fileno
));
119 Slot
&s
= shared
->slots
[fileno
];
121 freeLocked(s
, false);
124 const Ipc::MemMap::Slot
*
125 Ipc::MemMap::peekAtReader(const sfileno fileno
) const
127 assert(valid(fileno
));
128 const Slot
&s
= shared
->slots
[fileno
];
130 return &s
; // immediate access by lock holder so no locking
132 return nullptr; // cannot read the slot when it is being written
133 assert(false); // must be locked for reading or writing
138 Ipc::MemMap::free(const sfileno fileno
)
140 debugs(54, 5, "marking slot at " << fileno
<< " to be freed in"
141 " map [" << path
<< ']');
143 assert(valid(fileno
));
144 Slot
&s
= shared
->slots
[fileno
];
146 if (s
.lock
.lockExclusive())
147 freeLocked(s
, false);
149 s
.waitingToBeFreed
= true; // mark to free it later
152 const Ipc::MemMap::Slot
*
153 Ipc::MemMap::openForReading(const cache_key
*const key
, sfileno
&fileno
)
155 debugs(54, 5, "trying to open slot for key " << storeKeyText(key
)
156 << " for reading in map [" << path
<< ']');
157 const int idx
= slotIndexByKey(key
);
158 if (const Slot
*slot
= openForReadingAt(idx
)) {
159 if (slot
->sameKey(key
)) {
161 debugs(54, 5, "opened slot at " << fileno
<< " for key "
162 << storeKeyText(key
) << " for reading in map [" << path
<<
164 return slot
; // locked for reading
166 slot
->lock
.unlockShared();
168 debugs(54, 5, "failed to open slot for key " << storeKeyText(key
)
169 << " for reading in map [" << path
<< ']');
173 const Ipc::MemMap::Slot
*
174 Ipc::MemMap::openForReadingAt(const sfileno fileno
)
176 debugs(54, 5, "trying to open slot at " << fileno
<< " for "
177 "reading in map [" << path
<< ']');
178 assert(valid(fileno
));
179 Slot
&s
= shared
->slots
[fileno
];
181 if (!s
.lock
.lockShared()) {
182 debugs(54, 5, "failed to lock slot at " << fileno
<< " for "
183 "reading in map [" << path
<< ']');
188 s
.lock
.unlockShared();
189 debugs(54, 7, "empty slot at " << fileno
<< " for "
190 "reading in map [" << path
<< ']');
194 if (s
.waitingToBeFreed
) {
195 s
.lock
.unlockShared();
196 debugs(54, 7, "dirty slot at " << fileno
<< " for "
197 "reading in map [" << path
<< ']');
201 debugs(54, 5, "opened slot at " << fileno
<< " for reading in"
202 " map [" << path
<< ']');
207 Ipc::MemMap::closeForReading(const sfileno fileno
)
209 debugs(54, 5, "closing slot at " << fileno
<< " for reading in "
210 "map [" << path
<< ']');
211 assert(valid(fileno
));
212 Slot
&s
= shared
->slots
[fileno
];
214 s
.lock
.unlockShared();
218 Ipc::MemMap::entryLimit() const
220 return shared
->limit
;
224 Ipc::MemMap::entryCount() const
226 return shared
->count
;
230 Ipc::MemMap::full() const
232 return entryCount() >= entryLimit();
236 Ipc::MemMap::updateStats(ReadWriteLockStats
&stats
) const
238 for (int i
= 0; i
< shared
->limit
; ++i
)
239 shared
->slots
[i
].lock
.updateStats(stats
);
243 Ipc::MemMap::valid(const int pos
) const
245 return 0 <= pos
&& pos
< entryLimit();
250 hash_key(const unsigned char *data
, unsigned int len
, unsigned int hashSize
)
254 for (j
= 0, n
= 0; j
< len
; j
++ ) {
258 return (n
^ (j
* 271)) % hashSize
;
262 Ipc::MemMap::slotIndexByKey(const cache_key
*const key
) const
264 const unsigned char *k
= reinterpret_cast<const unsigned char *>(key
);
265 return hash_key(k
, MEMMAP_SLOT_KEY_SIZE
, shared
->limit
);
269 Ipc::MemMap::slotByKey(const cache_key
*const key
)
271 return shared
->slots
[slotIndexByKey(key
)];
274 /// unconditionally frees the already exclusively locked slot and releases lock
276 Ipc::MemMap::freeLocked(Slot
&s
, bool keepLocked
)
278 if (!s
.empty() && cleaner
)
279 cleaner
->noteFreeMapSlot(&s
- shared
->slots
.raw());
281 s
.waitingToBeFreed
= false;
282 memset(s
.key
, 0, sizeof(s
.key
));
284 s
.lock
.unlockExclusive();
286 debugs(54, 5, "freed slot at " << (&s
- shared
->slots
.raw()) <<
287 " in map [" << path
<< ']');
290 /* Ipc::MemMapSlot */
291 Ipc::MemMapSlot::MemMapSlot() :
295 memset(key
, 0, sizeof(key
));
296 memset(p
, 0, sizeof(p
));
300 Ipc::MemMapSlot::set(const unsigned char *aKey
, const void *block
, size_t blockSize
, time_t expireAt
)
302 memcpy(key
, aKey
, sizeof(key
));
304 memcpy(p
, block
, blockSize
);
310 Ipc::MemMapSlot::sameKey(const cache_key
*const aKey
) const
312 return (memcmp(key
, aKey
, sizeof(key
)) == 0);
316 Ipc::MemMapSlot::empty() const
318 for (unsigned char const*u
= key
; u
< key
+ sizeof(key
); ++u
) {
325 /* Ipc::MemMap::Shared */
327 Ipc::MemMap::Shared::Shared(const int aLimit
, const size_t anExtrasSize
):
328 limit(aLimit
), extrasSize(anExtrasSize
), count(0), slots(aLimit
)
332 Ipc::MemMap::Shared::~Shared()
337 Ipc::MemMap::Shared::sharedMemorySize() const
339 return SharedMemorySize(limit
, extrasSize
);
343 Ipc::MemMap::Shared::SharedMemorySize(const int limit
, const size_t extrasSize
)
345 return sizeof(Shared
) + limit
* (sizeof(Slot
) + extrasSize
);