libutil: add AsyncMutex lock waits
this is like a condition variable associated with the mutex. it's all we'll need for the async transition, so we don't add a separate type. Change-Id: Id9aefadd3b50e5f14f7b4d6bad41721f5249ce59
This commit is contained in:
@@ -168,6 +168,9 @@ private:
|
||||
std::mutex waitMutex;
|
||||
std::list<kj::Own<kj::CrossThreadPromiseFulfiller<void>>> waiters;
|
||||
|
||||
std::mutex conditionMutex;
|
||||
std::list<kj::Own<kj::CrossThreadPromiseFulfiller<void>>> conditionWaiters;
|
||||
|
||||
public:
|
||||
Sync() = default;
|
||||
Sync(T && data) : base_type(std::move(data)) {}
|
||||
@@ -198,8 +201,45 @@ public:
|
||||
}
|
||||
|
||||
using base_type::Lock::operator->, base_type::Lock::operator*;
|
||||
|
||||
/**
|
||||
* Releases the lock, waits for another promise to call `Sync::notify`,
|
||||
* and reacquires the lock. There is no `condition_variable`-equivalent
|
||||
* object to allow multiple wait queues on the same lock since we don't
|
||||
* need that yet. There's no reason not to add such a type when needed.
|
||||
*/
|
||||
kj::Promise<void> wait()
|
||||
{
|
||||
auto * s = static_cast<Sync *>(this->s);
|
||||
|
||||
{
|
||||
auto unlock = std::move(*this);
|
||||
}
|
||||
|
||||
auto pfp = kj::newPromiseAndCrossThreadFulfiller<void>();
|
||||
{
|
||||
std::lock_guard clk(s->conditionMutex);
|
||||
s->conditionWaiters.push_back(std::move(pfp.fulfiller));
|
||||
}
|
||||
co_await pfp.promise;
|
||||
|
||||
*this = co_await s->lock();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Notify all promises awaiting `Lock::wait`. There is no `notify_one` like
|
||||
* `std::condition_variable` provides owing to implementation complexities.
|
||||
*/
|
||||
void notify()
|
||||
{
|
||||
std::lock_guard clk(conditionMutex);
|
||||
for (auto & f : conditionWaiters) {
|
||||
f->fulfill();
|
||||
}
|
||||
conditionWaiters.clear();
|
||||
}
|
||||
|
||||
auto lockSync(NeverAsync = {})
|
||||
{
|
||||
return base_type::lock();
|
||||
|
||||
Reference in New Issue
Block a user