diff options
Diffstat (limited to 'third_party/nix/src/libutil/pool.hh')
-rw-r--r-- | third_party/nix/src/libutil/pool.hh | 274 |
1 files changed, 127 insertions, 147 deletions
diff --git a/third_party/nix/src/libutil/pool.hh b/third_party/nix/src/libutil/pool.hh index d49067bb95dc..592bd50897cc 100644 --- a/third_party/nix/src/libutil/pool.hh +++ b/third_party/nix/src/libutil/pool.hh @@ -1,13 +1,12 @@ #pragma once +#include <cassert> #include <functional> #include <limits> #include <list> #include <memory> -#include <cassert> - -#include "sync.hh" #include "ref.hh" +#include "sync.hh" namespace nix { @@ -29,159 +28,140 @@ namespace nix { */ template <class R> -class Pool -{ -public: - - /* A function that produces new instances of R on demand. */ - typedef std::function<ref<R>()> Factory; - - /* A function that checks whether an instance of R is still - usable. Unusable instances are removed from the pool. */ - typedef std::function<bool(const ref<R> &)> Validator; - -private: - - Factory factory; - Validator validator; - - struct State - { - size_t inUse = 0; - size_t max; - std::vector<ref<R>> idle; - }; - - Sync<State> state; - - std::condition_variable wakeup; - -public: - - Pool(size_t max = std::numeric_limits<size_t>::max(), - const Factory & factory = []() { return make_ref<R>(); }, - const Validator & validator = [](ref<R> r) { return true; }) - : factory(factory) - , validator(validator) - { - auto state_(state.lock()); - state_->max = max; - } - - void incCapacity() - { - auto state_(state.lock()); - state_->max++; - /* we could wakeup here, but this is only used when we're - * about to nest Pool usages, and we want to save the slot for - * the nested use if we can - */ +class Pool { + public: + /* A function that produces new instances of R on demand. */ + typedef std::function<ref<R>()> Factory; + + /* A function that checks whether an instance of R is still + usable. Unusable instances are removed from the pool. */ + typedef std::function<bool(const ref<R>&)> Validator; + + private: + Factory factory; + Validator validator; + + struct State { + size_t inUse = 0; + size_t max; + std::vector<ref<R>> idle; + }; + + Sync<State> state; + + std::condition_variable wakeup; + + public: + Pool( + size_t max = std::numeric_limits<size_t>::max(), + const Factory& factory = []() { return make_ref<R>(); }, + const Validator& validator = [](ref<R> r) { return true; }) + : factory(factory), validator(validator) { + auto state_(state.lock()); + state_->max = max; + } + + void incCapacity() { + auto state_(state.lock()); + state_->max++; + /* we could wakeup here, but this is only used when we're + * about to nest Pool usages, and we want to save the slot for + * the nested use if we can + */ + } + + void decCapacity() { + auto state_(state.lock()); + state_->max--; + } + + ~Pool() { + auto state_(state.lock()); + assert(!state_->inUse); + state_->max = 0; + state_->idle.clear(); + } + + class Handle { + private: + Pool& pool; + std::shared_ptr<R> r; + bool bad = false; + + friend Pool; + + Handle(Pool& pool, std::shared_ptr<R> r) : pool(pool), r(r) {} + + public: + Handle(Handle&& h) : pool(h.pool), r(h.r) { h.r.reset(); } + + Handle(const Handle& l) = delete; + + ~Handle() { + if (!r) return; + { + auto state_(pool.state.lock()); + if (!bad) state_->idle.push_back(ref<R>(r)); + assert(state_->inUse); + state_->inUse--; + } + pool.wakeup.notify_one(); } - void decCapacity() - { - auto state_(state.lock()); - state_->max--; - } - - ~Pool() - { - auto state_(state.lock()); - assert(!state_->inUse); - state_->max = 0; - state_->idle.clear(); - } - - class Handle - { - private: - Pool & pool; - std::shared_ptr<R> r; - bool bad = false; - - friend Pool; - - Handle(Pool & pool, std::shared_ptr<R> r) : pool(pool), r(r) { } - - public: - Handle(Handle && h) : pool(h.pool), r(h.r) { h.r.reset(); } - - Handle(const Handle & l) = delete; - - ~Handle() - { - if (!r) return; - { - auto state_(pool.state.lock()); - if (!bad) - state_->idle.push_back(ref<R>(r)); - assert(state_->inUse); - state_->inUse--; - } - pool.wakeup.notify_one(); - } - - R * operator -> () { return &*r; } - R & operator * () { return *r; } + R* operator->() { return &*r; } + R& operator*() { return *r; } - void markBad() { bad = true; } - }; + void markBad() { bad = true; } + }; - Handle get() + Handle get() { { - { - auto state_(state.lock()); - - /* If we're over the maximum number of instance, we need - to wait until a slot becomes available. */ - while (state_->idle.empty() && state_->inUse >= state_->max) - state_.wait(wakeup); - - while (!state_->idle.empty()) { - auto p = state_->idle.back(); - state_->idle.pop_back(); - if (validator(p)) { - state_->inUse++; - return Handle(*this, p); - } - } - - state_->inUse++; + auto state_(state.lock()); + + /* If we're over the maximum number of instance, we need + to wait until a slot becomes available. */ + while (state_->idle.empty() && state_->inUse >= state_->max) + state_.wait(wakeup); + + while (!state_->idle.empty()) { + auto p = state_->idle.back(); + state_->idle.pop_back(); + if (validator(p)) { + state_->inUse++; + return Handle(*this, p); } + } - /* We need to create a new instance. Because that might take a - while, we don't hold the lock in the meantime. */ - try { - Handle h(*this, factory()); - return h; - } catch (...) { - auto state_(state.lock()); - state_->inUse--; - wakeup.notify_one(); - throw; - } - } - - size_t count() - { - auto state_(state.lock()); - return state_->idle.size() + state_->inUse; + state_->inUse++; } - size_t capacity() - { - return state.lock()->max; - } - - void flushBad() - { - auto state_(state.lock()); - std::vector<ref<R>> left; - for (auto & p : state_->idle) - if (validator(p)) - left.push_back(p); - std::swap(state_->idle, left); + /* We need to create a new instance. Because that might take a + while, we don't hold the lock in the meantime. */ + try { + Handle h(*this, factory()); + return h; + } catch (...) { + auto state_(state.lock()); + state_->inUse--; + wakeup.notify_one(); + throw; } + } + + size_t count() { + auto state_(state.lock()); + return state_->idle.size() + state_->inUse; + } + + size_t capacity() { return state.lock()->max; } + + void flushBad() { + auto state_(state.lock()); + std::vector<ref<R>> left; + for (auto& p : state_->idle) + if (validator(p)) left.push_back(p); + std::swap(state_->idle, left); + } }; -} +} // namespace nix |