summaryrefslogtreecommitdiffstats
path: root/library/cpp/actors/util/threadparkpad.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <[email protected]>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /library/cpp/actors/util/threadparkpad.cpp
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'library/cpp/actors/util/threadparkpad.cpp')
-rw-r--r--library/cpp/actors/util/threadparkpad.cpp148
1 files changed, 148 insertions, 0 deletions
diff --git a/library/cpp/actors/util/threadparkpad.cpp b/library/cpp/actors/util/threadparkpad.cpp
new file mode 100644
index 00000000000..74069ff15bf
--- /dev/null
+++ b/library/cpp/actors/util/threadparkpad.cpp
@@ -0,0 +1,148 @@
+#include "threadparkpad.h"
+#include <util/system/winint.h>
+
+#ifdef _linux_
+
+#include "futex.h"
+
+namespace NActors {
+ class TThreadParkPad::TImpl {
+ volatile bool Interrupted;
+ int Futex;
+
+ public:
+ TImpl()
+ : Interrupted(false)
+ , Futex(0)
+ {
+ }
+ ~TImpl() {
+ }
+
+ bool Park() noexcept {
+ __atomic_fetch_sub(&Futex, 1, __ATOMIC_SEQ_CST);
+ while (__atomic_load_n(&Futex, __ATOMIC_ACQUIRE) == -1)
+ SysFutex(&Futex, FUTEX_WAIT_PRIVATE, -1, nullptr, nullptr, 0);
+ return IsInterrupted();
+ }
+
+ void Unpark() noexcept {
+ const int old = __atomic_fetch_add(&Futex, 1, __ATOMIC_SEQ_CST);
+ if (old == -1)
+ SysFutex(&Futex, FUTEX_WAKE_PRIVATE, -1, nullptr, nullptr, 0);
+ }
+
+ void Interrupt() noexcept {
+ __atomic_store_n(&Interrupted, true, __ATOMIC_SEQ_CST);
+ Unpark();
+ }
+
+ bool IsInterrupted() const noexcept {
+ return __atomic_load_n(&Interrupted, __ATOMIC_ACQUIRE);
+ }
+ };
+
+#elif defined _win32_
+#include <util/generic/bt_exception.h>
+#include <util/generic/yexception.h>
+
+namespace NActors {
+ class TThreadParkPad::TImpl {
+ TAtomic Interrupted;
+ HANDLE EvHandle;
+
+ public:
+ TImpl()
+ : Interrupted(false)
+ {
+ EvHandle = ::CreateEvent(0, false, false, 0);
+ if (!EvHandle)
+ ythrow TWithBackTrace<yexception>() << "::CreateEvent failed";
+ }
+ ~TImpl() {
+ if (EvHandle)
+ ::CloseHandle(EvHandle);
+ }
+
+ bool Park() noexcept {
+ ::WaitForSingleObject(EvHandle, INFINITE);
+ return AtomicGet(Interrupted);
+ }
+
+ void Unpark() noexcept {
+ ::SetEvent(EvHandle);
+ }
+
+ void Interrupt() noexcept {
+ AtomicSet(Interrupted, true);
+ Unpark();
+ }
+
+ bool IsInterrupted() const noexcept {
+ return AtomicGet(Interrupted);
+ }
+ };
+
+#else
+
+#include <util/system/event.h>
+
+namespace NActors {
+ class TThreadParkPad::TImpl {
+ TAtomic Interrupted;
+ TSystemEvent Ev;
+
+ public:
+ TImpl()
+ : Interrupted(false)
+ , Ev(TSystemEvent::rAuto)
+ {
+ }
+ ~TImpl() {
+ }
+
+ bool Park() noexcept {
+ Ev.Wait();
+ return AtomicGet(Interrupted);
+ }
+
+ void Unpark() noexcept {
+ Ev.Signal();
+ }
+
+ void Interrupt() noexcept {
+ AtomicSet(Interrupted, true);
+ Unpark();
+ }
+
+ bool IsInterrupted() const noexcept {
+ return AtomicGet(Interrupted);
+ }
+ };
+#endif
+
+ TThreadParkPad::TThreadParkPad()
+ : Impl(new TThreadParkPad::TImpl())
+ {
+ }
+
+ TThreadParkPad::~TThreadParkPad() {
+ }
+
+ bool TThreadParkPad::Park() noexcept {
+ return Impl->Park();
+ }
+
+ void TThreadParkPad::Unpark() noexcept {
+ Impl->Unpark();
+ }
+
+ void TThreadParkPad::Interrupt() noexcept {
+ Impl->Interrupt();
+ }
+
+ bool TThreadParkPad::Interrupted() const noexcept {
+ return Impl->IsInterrupted();
+ }
+
+}