MCPcopy Create free account
hub / github.com/3rdparty/libprocess / DecomissionableLastInFirstOutFixedSizeSemaphore

Class DecomissionableLastInFirstOutFixedSizeSemaphore

src/semaphore.hpp:244–416  ·  view source on GitHub ↗

Source from the content-addressed store, hash-verified

242 : __semaphore__)
243
244class DecomissionableLastInFirstOutFixedSizeSemaphore
245{
246public:
247 // TODO(benh): enable specifying the number of threads that will use
248 // this semaphore. Currently this is difficult because we construct
249 // the `RunQueue` and later this class before we've determined the
250 // number of worker threads we'll create.
251 DecomissionableLastInFirstOutFixedSizeSemaphore()
252 {
253 for (size_t i = 0; i < semaphores.size(); i++) {
254 semaphores[i] = nullptr;
255 }
256 }
257
258 void signal()
259 {
260 // NOTE: we _always_ increment `count` which means that even if we
261 // try and signal a thread another thread might have come in and
262 // decremented `count` already. This is deliberate, but it would
263 // be interesting to also investigate the performance where we
264 // always signal a new thread.
265 count.fetch_add(1);
266
267 while (waiters.load() > 0 && count.load() > 0) {
268 for (size_t i = 0; i < semaphores.size(); i++) {
269 // Don't bother finding a semaphore to signal if there isn't
270 // anybody to signal (`waiters` == 0) or anything to do
271 // (`count` == 0).
272 if (waiters.load() == 0 || count.load() == 0) {
273 return;
274 }
275
276 // Try and find and then signal a waiter.
277 //
278 // TODO(benh): we `load()` first and then do a
279 // compare-and-swap because the read shouldn't require a lock
280 // instruction or synchronizing the bus. In addition, we
281 // should be able to optimize the loads in the future to a
282 // weaker memory ordering. That being said, if we don't see
283 // performance wins when trying that we should consider just
284 // doing a `std::atomic::exchange()` instead.
285 KernelSemaphore* semaphore = semaphores[i].load();
286 if (semaphore != nullptr) {
287 if (!semaphores[i].compare_exchange_strong(semaphore, nullptr)) {
288 continue;
289 }
290
291 // NOTE: we decrement `waiters` _here_ rather than in `wait`
292 // so that future signalers won't bother looping here
293 // (potentially for a long time) trying to find a waiter
294 // that might have already been signaled but just hasn't
295 // woken up yet. We even go as far as decrementing `waiters`
296 // _before_ we signal to really keep a thread from having to
297 // loop.
298 waiters.fetch_sub(1);
299
300 semaphore->signal();
301

Callers

nothing calls this directly

Calls

no outgoing calls

Tested by

no test coverage detected