#pragma once #include "lfqueue.h" #include #include #include #include #include #include #include namespace NNeh { template class TBlockedQueue: public TLockFreeQueue, public TSystemEvent { public: inline TBlockedQueue() noexcept : TSystemEvent(TSystemEvent::rAuto) { } inline void Notify(T t) noexcept { this->Enqueue(t); Signal(); } }; class TWaitQueue: public TThrRefBase { public: class TWaitHandle { public: ~TWaitHandle() { SwapWaitQueue(nullptr); } void Signal() noexcept { Signalled_ = true; if (TIntrusivePtr q = SwapWaitQueue(nullptr)) { q->Notify(this); } } void Register(TIntrusivePtr& waitQueue) noexcept { if (Signalled_) { waitQueue->Notify(this); SwapWaitQueue(nullptr); return; } waitQueue->Ref(); SwapWaitQueue(waitQueue.Get()); if (Signalled_) { if (TIntrusivePtr q = SwapWaitQueue(nullptr)) { q->Notify(this); } } } bool Signalled() const { return Signalled_; } void ResetState() { Signalled_ = false; SwapWaitQueue(nullptr); } private: TIntrusivePtr SwapWaitQueue(TWaitQueue* newQueue) noexcept { return TIntrusivePtr(AtomicSwap(&WaitQueue_, newQueue), TIntrusivePtr::TNoIncrement()); } private: NAtomic::TBool Signalled_ = false; TWaitQueue* WaitQueue_ = nullptr; }; inline bool Wait(const TInstant& deadLine) noexcept { return Q_.WaitD(deadLine); } inline void Notify(TWaitHandle* wq) noexcept { Q_.Notify(wq); } inline bool Dequeue(TWaitHandle** wq) noexcept { return Q_.Dequeue(wq); } private: TBlockedQueue Q_; }; typedef TWaitQueue::TWaitHandle TWaitHandle; template static inline void WaitForMultipleObj(TWaitQueue& hndl, const TInstant& deadLine, T& func) { do { TWaitHandle* ret = nullptr; if (hndl.Dequeue(&ret)) { do { func(ret); } while (hndl.Dequeue(&ret)); return; } } while (hndl.Wait(deadLine)); } struct TSignalled { inline TSignalled() : Signalled(false) { } inline void operator()(const TWaitHandle*) noexcept { Signalled = true; } bool Signalled; }; static inline bool WaitForOne(TWaitHandle& wh, const TInstant& deadLine) { TSignalled func; auto hndl = MakeIntrusive(); wh.Register(hndl); WaitForMultipleObj(*hndl, deadLine, func); return func.Signalled; } }