]>
git.ipfire.org Git - thirdparty/squid.git/blob - src/ipc/MemMap.cc
2 * Copyright (C) 1996-2017 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
, bool lockForReading
)
93 debugs(54, 5, "closing slot at " << fileno
<< " for writing and "
94 "openning for reading in map [" << path
<< ']');
95 assert(valid(fileno
));
96 Slot
&s
= shared
->slots
[fileno
];
99 s
.lock
.switchExclusiveToShared();
101 s
.lock
.unlockExclusive();
104 /// terminate writing the entry, freeing its slot for others to use
106 Ipc::MemMap::abortWriting(const sfileno fileno
)
108 debugs(54, 5, "abort writing slot at " << fileno
<<
109 " in map [" << path
<< ']');
110 assert(valid(fileno
));
111 Slot
&s
= shared
->slots
[fileno
];
113 freeLocked(s
, false);
116 const Ipc::MemMap::Slot
*
117 Ipc::MemMap::peekAtReader(const sfileno fileno
) const
119 assert(valid(fileno
));
120 const Slot
&s
= shared
->slots
[fileno
];
122 return &s
; // immediate access by lock holder so no locking
124 return NULL
; // cannot read the slot when it is being written
125 assert(false); // must be locked for reading or writing
130 Ipc::MemMap::free(const sfileno fileno
)
132 debugs(54, 5, "marking slot at " << fileno
<< " to be freed in"
133 " map [" << path
<< ']');
135 assert(valid(fileno
));
136 Slot
&s
= shared
->slots
[fileno
];
138 if (s
.lock
.lockExclusive())
139 freeLocked(s
, false);
141 s
.waitingToBeFreed
= true; // mark to free it later
144 const Ipc::MemMap::Slot
*
145 Ipc::MemMap::openForReading(const cache_key
*const key
, sfileno
&fileno
)
147 debugs(54, 5, "trying to open slot for key " << storeKeyText(key
)
148 << " for reading in map [" << path
<< ']');
149 const int idx
= slotIndexByKey(key
);
150 if (const Slot
*slot
= openForReadingAt(idx
)) {
151 if (slot
->sameKey(key
)) {
153 debugs(54, 5, "opened slot at " << fileno
<< " for key "
154 << storeKeyText(key
) << " for reading in map [" << path
<<
156 return slot
; // locked for reading
158 slot
->lock
.unlockShared();
160 debugs(54, 5, "failed to open slot for key " << storeKeyText(key
)
161 << " for reading in map [" << path
<< ']');
165 const Ipc::MemMap::Slot
*
166 Ipc::MemMap::openForReadingAt(const sfileno fileno
)
168 debugs(54, 5, "trying to open slot at " << fileno
<< " for "
169 "reading in map [" << path
<< ']');
170 assert(valid(fileno
));
171 Slot
&s
= shared
->slots
[fileno
];
173 if (!s
.lock
.lockShared()) {
174 debugs(54, 5, "failed to lock slot at " << fileno
<< " for "
175 "reading in map [" << path
<< ']');
180 s
.lock
.unlockShared();
181 debugs(54, 7, "empty slot at " << fileno
<< " for "
182 "reading in map [" << path
<< ']');
186 if (s
.waitingToBeFreed
) {
187 s
.lock
.unlockShared();
188 debugs(54, 7, "dirty slot at " << fileno
<< " for "
189 "reading in map [" << path
<< ']');
193 debugs(54, 5, "opened slot at " << fileno
<< " for reading in"
194 " map [" << path
<< ']');
199 Ipc::MemMap::closeForReading(const sfileno fileno
)
201 debugs(54, 5, "closing slot at " << fileno
<< " for reading in "
202 "map [" << path
<< ']');
203 assert(valid(fileno
));
204 Slot
&s
= shared
->slots
[fileno
];
206 s
.lock
.unlockShared();
210 Ipc::MemMap::entryLimit() const
212 return shared
->limit
;
216 Ipc::MemMap::entryCount() const
218 return shared
->count
;
222 Ipc::MemMap::full() const
224 return entryCount() >= entryLimit();
228 Ipc::MemMap::updateStats(ReadWriteLockStats
&stats
) const
230 for (int i
= 0; i
< shared
->limit
; ++i
)
231 shared
->slots
[i
].lock
.updateStats(stats
);
235 Ipc::MemMap::valid(const int pos
) const
237 return 0 <= pos
&& pos
< entryLimit();
242 hash_key(const unsigned char *data
, unsigned int len
, unsigned int hashSize
)
246 for (j
= 0, n
= 0; j
< len
; j
++ ) {
250 return (n
^ (j
* 271)) % hashSize
;
254 Ipc::MemMap::slotIndexByKey(const cache_key
*const key
) const
256 const unsigned char *k
= reinterpret_cast<const unsigned char *>(key
);
257 return hash_key(k
, MEMMAP_SLOT_KEY_SIZE
, shared
->limit
);
261 Ipc::MemMap::slotByKey(const cache_key
*const key
)
263 return shared
->slots
[slotIndexByKey(key
)];
266 /// unconditionally frees the already exclusively locked slot and releases lock
268 Ipc::MemMap::freeLocked(Slot
&s
, bool keepLocked
)
270 if (!s
.empty() && cleaner
)
271 cleaner
->noteFreeMapSlot(&s
- shared
->slots
.raw());
273 s
.waitingToBeFreed
= false;
274 memset(s
.key
, 0, sizeof(s
.key
));
276 s
.lock
.unlockExclusive();
278 debugs(54, 5, "freed slot at " << (&s
- shared
->slots
.raw()) <<
279 " in map [" << path
<< ']');
282 /* Ipc::MemMapSlot */
283 Ipc::MemMapSlot::MemMapSlot() :
287 memset(key
, 0, sizeof(key
));
288 memset(p
, 0, sizeof(p
));
292 Ipc::MemMapSlot::set(const unsigned char *aKey
, const void *block
, size_t blockSize
, time_t expireAt
)
294 memcpy(key
, aKey
, sizeof(key
));
296 memcpy(p
, block
, blockSize
);
302 Ipc::MemMapSlot::sameKey(const cache_key
*const aKey
) const
304 return (memcmp(key
, aKey
, sizeof(key
)) == 0);
308 Ipc::MemMapSlot::empty() const
310 for (unsigned char const*u
= key
; u
< key
+ sizeof(key
); ++u
) {
317 /* Ipc::MemMap::Shared */
319 Ipc::MemMap::Shared::Shared(const int aLimit
, const size_t anExtrasSize
):
320 limit(aLimit
), extrasSize(anExtrasSize
), count(0), slots(aLimit
)
324 Ipc::MemMap::Shared::~Shared()
329 Ipc::MemMap::Shared::sharedMemorySize() const
331 return SharedMemorySize(limit
, extrasSize
);
335 Ipc::MemMap::Shared::SharedMemorySize(const int limit
, const size_t extrasSize
)
337 return sizeof(Shared
) + limit
* (sizeof(Slot
) + extrasSize
);