123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132 |
- #pragma once
- #include <iterator>
- #include <util/datetime/base.h>
- #include <library/cpp/deprecated/atomic/atomic.h>
- #include <util/system/defaults.h>
- #include <util/system/event.h>
- #include <util/system/guard.h>
- #include <util/system/mutex.h>
- #include <util/generic/list.h>
- #include <util/generic/vector.h>
- #include <util/generic/noncopyable.h>
- class TMuxEvent: public TNonCopyable {
- friend inline int WaitForAnyEvent(TMuxEvent** array, const int size, TDuration timeout);
- public:
- enum ResetMode {
- rManual,
- // TODO: rAuto is not supported yet
- };
- TMuxEvent(ResetMode rmode = rManual) {
- Y_UNUSED(rmode);
- }
- ~TMuxEvent() {
- Y_ABORT_UNLESS(WaitList.empty(), "");
- }
- // TODO: potentially unsafe, but currently I can't add "virtual" to TSystemEvent methods
- operator TSystemEvent&() {
- return MyEvent;
- }
- operator const TSystemEvent&() const {
- return MyEvent;
- }
- bool WaitD(TInstant deadLine) noexcept {
- return MyEvent.WaitD(deadLine);
- }
- // for rManual it's OK to ignore WaitList
- void Reset() noexcept {
- TGuard<TMutex> lock(WaitListLock);
- MyEvent.Reset(); // TODO: do we actually need to be locked here?
- }
- void Signal() noexcept {
- TGuard<TMutex> lock(WaitListLock);
- for (auto& i : WaitList) {
- i->Signal();
- }
- MyEvent.Signal(); // TODO: do we actually need to be locked here?
- }
- // same as in TSystemEvent
- inline bool WaitT(TDuration timeOut) noexcept {
- return WaitD(timeOut.ToDeadLine());
- }
- inline void WaitI() noexcept {
- WaitD(TInstant::Max());
- }
- inline bool Wait(ui32 timer) noexcept {
- return WaitT(TDuration::MilliSeconds(timer));
- }
- inline bool Wait() noexcept {
- WaitI();
- return true;
- }
- private:
- TSystemEvent MyEvent;
- TMutex WaitListLock;
- TList<TSystemEvent*> WaitList;
- };
- ///////////////////////////////////////////////////////////////////////////////
- inline int WaitForAnyEvent(TMuxEvent** array, const int size, const TDuration timeout = TDuration::Max()) {
- TVector<TList<TSystemEvent*>::iterator> listIters;
- listIters.reserve(size);
- int result = -1;
- TSystemEvent e;
- for (int i = 0; i != size; ++i) {
- TMuxEvent& me = *array[i];
- TGuard<TMutex> lock(me.WaitListLock);
- if (me.MyEvent.Wait(0)) {
- result = i;
- break;
- }
- listIters.push_back(me.WaitList.insert(me.WaitList.end(), &e));
- }
- const bool timedOut = result == -1 && !e.WaitT(timeout);
- for (int i = 0; i != size; ++i) {
- TMuxEvent& me = *array[i];
- TGuard<TMutex> lock(me.WaitListLock);
- if (i < listIters.ysize()) {
- me.WaitList.erase(listIters[i]);
- }
- if (!timedOut && result == -1 && me.MyEvent.Wait(0)) { // always returns first signalled event
- result = i;
- }
- }
- Y_ASSERT(timedOut == (result == -1));
- return result;
- }
- ///////////////////////////////////////////////////////////////////////////////
- // TODO: rewrite via template<class TIter...>
- inline int WaitForAnyEvent(TMuxEvent& e0, const TDuration timeout = TDuration::Max()) {
- TMuxEvent* array[] = {&e0};
- return WaitForAnyEvent(array, Y_ARRAY_SIZE(array), timeout);
- }
- inline int WaitForAnyEvent(TMuxEvent& e0, TMuxEvent& e1, const TDuration timeout = TDuration::Max()) {
- TMuxEvent* array[] = {&e0, &e1};
- return WaitForAnyEvent(array, Y_ARRAY_SIZE(array), timeout);
- }
- inline int WaitForAnyEvent(TMuxEvent& e0, TMuxEvent& e1, TMuxEvent& e2, const TDuration timeout = TDuration::Max()) {
- TMuxEvent* array[] = {&e0, &e1, &e2};
- return WaitForAnyEvent(array, Y_ARRAY_SIZE(array), timeout);
- }
|