From d05ee55474cfed03c10e4740a0c0b66a97e7e3d3 Mon Sep 17 00:00:00 2001 From: Bulat Gayazov Date: Tue, 22 Apr 2025 14:47:13 +0000 Subject: [PATCH 1/6] Supported TFuture in coroutines --- library/cpp/threading/future/CMakeLists.txt | 26 +++ .../future/benchmark/coroutine_traits.cpp | 82 +++++++ .../threading/future/core/coroutine_traits.h | 129 +++++++++++ .../cpp/threading/future/core/future-inl.h | 23 ++ library/cpp/threading/future/core/future.h | 22 ++ library/cpp/threading/future/future.h | 2 + library/cpp/threading/future/future_ut.cpp | 4 + library/cpp/threading/future/perf/main.cpp | 50 ----- .../future/ut_gtest/coroutine_traits_ut.cpp | 209 ++++++++++++++++++ 9 files changed, 497 insertions(+), 50 deletions(-) create mode 100644 library/cpp/threading/future/benchmark/coroutine_traits.cpp create mode 100644 library/cpp/threading/future/core/coroutine_traits.h delete mode 100644 library/cpp/threading/future/perf/main.cpp create mode 100644 library/cpp/threading/future/ut_gtest/coroutine_traits_ut.cpp diff --git a/library/cpp/threading/future/CMakeLists.txt b/library/cpp/threading/future/CMakeLists.txt index 0d4aca09b92..6cef855eee1 100644 --- a/library/cpp/threading/future/CMakeLists.txt +++ b/library/cpp/threading/future/CMakeLists.txt @@ -9,7 +9,33 @@ target_sources(threading-future async_semaphore.cpp async.cpp core/future.cpp + core/fwd.cpp + fwd.cpp + wait/fwd.cpp wait/wait.cpp + wait/wait_group.cpp + wait/wait_policy.cpp ) _ydb_sdk_install_targets(TARGETS threading-future) + +if (YDB_SDK_TESTS) + add_ydb_test(NAME future-ut + SOURCES + future_mt_ut.cpp + future_ut.cpp + LINK_LIBRARIES + threading-future + LABELS + unit + ) + + add_ydb_test(NAME future-coroutine-ut GTEST + SOURCES + ut_gtest/coroutine_traits_ut.cpp + LINK_LIBRARIES + threading-future + LABELS + unit + ) +endif() diff --git a/library/cpp/threading/future/benchmark/coroutine_traits.cpp b/library/cpp/threading/future/benchmark/coroutine_traits.cpp new file mode 100644 index 00000000000..93528bfac06 --- /dev/null +++ b/library/cpp/threading/future/benchmark/coroutine_traits.cpp @@ -0,0 +1,82 @@ +#include +#include + +#include + +class TContext { +public: + TContext() + : NextInputPromise_(NThreading::NewPromise()) + {} + ~TContext() { + UpdateNextInput(false); + } + + NThreading::TFuture NextInput() { + return NextInputPromise_.GetFuture(); + } + + void UpdateNextInput(bool hasInput = true) { + auto prevNextInputPromise = NextInputPromise_; + NextInputPromise_ = NThreading::NewPromise(); + prevNextInputPromise.SetValue(hasInput); + } + +private: + NThreading::TPromise NextInputPromise_; +}; + +static void TestPureFutureChainSubscribe(benchmark::State& state) { + TContext context; + size_t cnt = 0; + std::function&)> processInput = [&context, &cnt, &processInput](const NThreading::TFuture& hasInput) { + if (hasInput.GetValue()) { + benchmark::DoNotOptimize(++cnt); + context.NextInput().Subscribe(processInput); + } + }; + + processInput(NThreading::MakeFuture(true)); + for (auto _ : state) { + context.UpdateNextInput(); + } + context.UpdateNextInput(false); +} + +static void TestPureFutureChainApply(benchmark::State& state) { + TContext context; + size_t cnt = 0; + std::function&)> processInput = [&context, &cnt, &processInput](const NThreading::TFuture& hasInput) { + if (hasInput.GetValue()) { + benchmark::DoNotOptimize(++cnt); + context.NextInput().Apply(processInput); + } + }; + + processInput(NThreading::MakeFuture(true)); + for (auto _ : state) { + context.UpdateNextInput(); + } + context.UpdateNextInput(false); +} + +static void TestCoroFutureChain(benchmark::State& state) { + TContext context; + size_t cnt = 0; + auto coroutine = [&context, &cnt]() -> NThreading::TFuture { + while (co_await context.NextInput()) { + benchmark::DoNotOptimize(++cnt); + } + }; + + auto coroutineFuture = coroutine(); + for (auto _ : state) { + context.UpdateNextInput(); + } + context.UpdateNextInput(false); + coroutineFuture.GetValueSync(); +} + +BENCHMARK(TestPureFutureChainSubscribe); +BENCHMARK(TestPureFutureChainApply); +BENCHMARK(TestCoroFutureChain); diff --git a/library/cpp/threading/future/core/coroutine_traits.h b/library/cpp/threading/future/core/coroutine_traits.h new file mode 100644 index 00000000000..cdd3eeeff3e --- /dev/null +++ b/library/cpp/threading/future/core/coroutine_traits.h @@ -0,0 +1,129 @@ +#pragma once + +#include + +#include + +template +struct std::coroutine_traits, Args...> { + struct promise_type { + + NThreading::TFuture get_return_object() { + return Promise_.GetFuture(); + } + + std::suspend_never initial_suspend() { return {}; } + std::suspend_never final_suspend() noexcept { return {}; } + + void unhandled_exception() { + Promise_.SetException(std::current_exception()); + } + + void return_void() { + Promise_.SetValue(); + } + + private: + NThreading::TPromise Promise_ = NThreading::NewPromise(); + }; +}; + +template +struct std::coroutine_traits, Args...> { + struct promise_type { + NThreading::TFuture get_return_object() { + return Promise_.GetFuture(); + } + + std::suspend_never initial_suspend() { return {}; } + std::suspend_never final_suspend() noexcept { return {}; } + + void unhandled_exception() { + Promise_.SetException(std::current_exception()); + } + + void return_value(auto&& val) { + Promise_.SetValue(std::forward(val)); + } + + private: + NThreading::TPromise Promise_ = NThreading::NewPromise(); + }; +}; + +namespace NThreading { + + template + struct TFutureAwaitable { + NThreading::TFuture Future; + + TFutureAwaitable(const NThreading::TFuture& future) noexcept requires (!Extracting) + : Future{future} + { + } + + TFutureAwaitable(NThreading::TFuture&& future) noexcept + : Future{std::move(future)} + { + } + + bool await_ready() const noexcept { + return Future.IsReady(); + } + + void await_suspend(auto h) noexcept { + /* + * This library assumes that resume never throws an exception. + * This assumption is made due to the fact that the users of these library in most cases do not need to write their own coroutine handlers, + * and all coroutine handlers provided by the library do not throw exception from resume. + * + * WARNING: do not change subscribe to apply or something other here, creating an extra future state degrades performance. + */ + Future.NoexceptSubscribe( + [h](auto) mutable noexcept { + h(); + } + ); + } + + decltype(auto) await_resume() { + if constexpr (Extracting && !std::is_same_v) { // Future has only GetValue() + return Future.ExtractValue(); + } else { + return Future.GetValue(); + } + } + }; + + template + using TExtractingFutureAwaitable = TFutureAwaitable; + +} // namespace NThreading + +template +auto operator co_await(const NThreading::TFuture& future) noexcept { + return NThreading::TFutureAwaitable{future}; +} + +template +auto operator co_await(NThreading::TFuture&& future) noexcept { + // Not TExtractongFutureAwaitable, because TFuture works like std::shared_future. + // auto value = co_await GetCachedFuture(); + // If GetCachedFuture stores a future in some cache and returns its copies, + // then subsequent uses of co_await will return a moved-from value. + return NThreading::TFutureAwaitable{std::move(future)}; +} + +namespace NThreading { + + template + auto AsAwaitable(const NThreading::TFuture& fut) noexcept { + return TFutureAwaitable(fut); + } + + template + auto AsExtractingAwaitable(NThreading::TFuture&& fut) noexcept { + return TExtractingFutureAwaitable(std::move(fut)); + } + +} // namespace NThreading diff --git a/library/cpp/threading/future/core/future-inl.h b/library/cpp/threading/future/core/future-inl.h index df6b7c21b2f..1ce1cbd4e21 100644 --- a/library/cpp/threading/future/core/future-inl.h +++ b/library/cpp/threading/future/core/future-inl.h @@ -2,6 +2,7 @@ #if !defined(INCLUDE_FUTURE_INL_H) #error "you should never include future-inl.h directly" +#include "future.h" // Fix LSP #endif // INCLUDE_FUTURE_INL_H namespace NThreading { @@ -116,6 +117,9 @@ namespace NThreading { bool HasException() const { return AtomicGet(State) == ExceptionSet; } + bool IsReady() const { + return AtomicGet(State) != NotReady; + } const T& GetValue(TDuration timeout = TDuration::Zero()) const { AccessValue(timeout, ValueRead); @@ -297,6 +301,9 @@ namespace NThreading { bool HasException() const { return AtomicGet(State) == ExceptionSet; } + bool IsReady() const { + return AtomicGet(State) != NotReady; + } void GetValue(TDuration timeout = TDuration::Zero()) const { TAtomicBase state = AtomicGet(State); @@ -583,6 +590,10 @@ namespace NThreading { inline bool TFuture::HasException() const { return State && State->HasException(); } + template + inline bool TFuture::IsReady() const { + return State && State->IsReady(); + } template inline void TFuture::Wait() const { @@ -688,6 +699,9 @@ namespace NThreading { inline bool TFuture::HasException() const { return State && State->HasException(); } + inline bool TFuture::IsReady() const { + return State && State->IsReady(); + } inline void TFuture::Wait() const { EnsureInitialized(); @@ -823,6 +837,11 @@ namespace NThreading { return State && State->HasException(); } + template + inline bool TPromise::IsReady() const { + return State && State->IsReady(); + } + template inline void TPromise::SetException(const TString& e) { EnsureInitialized(); @@ -904,6 +923,10 @@ namespace NThreading { return State && State->HasException(); } + inline bool TPromise::IsReady() const { + return State && State->IsReady(); + } + inline void TPromise::SetException(const TString& e) { EnsureInitialized(); State->SetException(std::make_exception_ptr(yexception() << e)); diff --git a/library/cpp/threading/future/core/future.h b/library/cpp/threading/future/core/future.h index 598336282a0..1e76a04d3f1 100644 --- a/library/cpp/threading/future/core/future.h +++ b/library/cpp/threading/future/core/future.h @@ -98,6 +98,12 @@ namespace NThreading { void TryRethrow() const; bool HasException() const; + // returns true if exception or value was set. + // allows to check readiness without locking cheker-thread + // NOTE: returns true even if value was extracted from promise + // good replace for HasValue() || HasException() + bool IsReady() const; + void Wait() const; bool Wait(TDuration timeout) const; bool Wait(TInstant deadline) const; @@ -153,6 +159,11 @@ namespace NThreading { void TryRethrow() const; bool HasException() const; + // returns true if exception or value was set. + // allows to check readiness without locking cheker-thread + // good replace for HasValue() || HasException() + bool IsReady() const; + void Wait() const; bool Wait(TDuration timeout) const; bool Wait(TInstant deadline) const; @@ -216,6 +227,12 @@ namespace NThreading { void TryRethrow() const; bool HasException() const; + + // returns true if exception or value was set. + // allows to check readiness without locking cheker-thread + // NOTE: returns true even if value was extracted from promise + // good replace for HasValue() || HasException() + bool IsReady() const; void SetException(const TString& e); void SetException(std::exception_ptr e); bool TrySetException(std::exception_ptr e); @@ -256,6 +273,11 @@ namespace NThreading { void TryRethrow() const; bool HasException() const; + + // returns true if exception or value was set. + // allows to check readiness without locking cheker-thread + // good replace for HasValue() || HasException() + bool IsReady() const; void SetException(const TString& e); void SetException(std::exception_ptr e); bool TrySetException(std::exception_ptr e); diff --git a/library/cpp/threading/future/future.h b/library/cpp/threading/future/future.h index 35db9abbe22..91ade3f6e50 100644 --- a/library/cpp/threading/future/future.h +++ b/library/cpp/threading/future/future.h @@ -1,4 +1,6 @@ #pragma once +// IWYU pragma: begin_exports #include "core/future.h" #include "wait/wait.h" +// IWYU pragma: end_exports diff --git a/library/cpp/threading/future/future_ut.cpp b/library/cpp/threading/future/future_ut.cpp index 26f8fa9e9c3..ceb07cae934 100644 --- a/library/cpp/threading/future/future_ut.cpp +++ b/library/cpp/threading/future/future_ut.cpp @@ -105,6 +105,7 @@ namespace { future = MakeFuture(345); UNIT_ASSERT(future.HasValue()); + UNIT_ASSERT(future.IsReady()); UNIT_ASSERT_EQUAL(future.GetValue(), 345); } @@ -115,6 +116,7 @@ namespace { TFuture future = promise.GetFuture(); UNIT_ASSERT(future.HasValue()); + UNIT_ASSERT(future.IsReady()); future = MakeFuture(); UNIT_ASSERT(future.HasValue()); @@ -523,6 +525,7 @@ namespace { { auto future1 = MakeErrorFuture(std::make_exception_ptr(TFutureException())); UNIT_ASSERT(future1.HasException()); + UNIT_ASSERT(future1.IsReady()); UNIT_CHECK_GENERATED_EXCEPTION(future1.GetValue(), TFutureException); auto future2 = MakeErrorFuture(std::make_exception_ptr(TFutureException())); @@ -563,6 +566,7 @@ namespace { promise2.SetException("foo-exception"); wait.Wait(); UNIT_ASSERT(future2.HasException()); + UNIT_ASSERT(!future1.IsReady()); UNIT_ASSERT(!future1.HasValue() && !future1.HasException()); } diff --git a/library/cpp/threading/future/perf/main.cpp b/library/cpp/threading/future/perf/main.cpp deleted file mode 100644 index 5a0690af473..00000000000 --- a/library/cpp/threading/future/perf/main.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include -#include - -#include -#include - -using namespace NThreading; - -template -void TestAllocPromise(const NBench::NCpu::TParams& iface) { - for (const auto it : xrange(iface.Iterations())) { - Y_UNUSED(it); - Y_DO_NOT_OPTIMIZE_AWAY(NewPromise()); - } -} - -template -TPromise SetPromise(T value) { - auto promise = NewPromise(); - promise.SetValue(value); - return promise; -} - -template -void TestSetPromise(const NBench::NCpu::TParams& iface, T value) { - for (const auto it : xrange(iface.Iterations())) { - Y_UNUSED(it); - Y_DO_NOT_OPTIMIZE_AWAY(SetPromise(value)); - } -} - -Y_CPU_BENCHMARK(AllocPromiseVoid, iface) { - TestAllocPromise(iface); -} - -Y_CPU_BENCHMARK(AllocPromiseUI64, iface) { - TestAllocPromise(iface); -} - -Y_CPU_BENCHMARK(AllocPromiseStroka, iface) { - TestAllocPromise(iface); -} - -Y_CPU_BENCHMARK(SetPromiseUI64, iface) { - TestSetPromise(iface, 1234567890ull); -} - -Y_CPU_BENCHMARK(SetPromiseStroka, iface) { - TestSetPromise(iface, "test test test"); -} diff --git a/library/cpp/threading/future/ut_gtest/coroutine_traits_ut.cpp b/library/cpp/threading/future/ut_gtest/coroutine_traits_ut.cpp new file mode 100644 index 00000000000..70738ac753d --- /dev/null +++ b/library/cpp/threading/future/ut_gtest/coroutine_traits_ut.cpp @@ -0,0 +1,209 @@ +#include +#include +#include + +#include +#include +#include +#include + + +TEST(TestFutureTraits, Simple) { + TVector result; + + auto coroutine1 = [&result]() -> NThreading::TFuture { + result.push_back("coroutine1"); + co_return 1; + }; + + NThreading::TPromise coroutine2SuspendPromise = NThreading::NewPromise(); + auto coroutine2 = [&result, coroutine2SuspendFuture = coroutine2SuspendPromise.GetFuture()]() -> NThreading::TFuture { + result.push_back("coroutine2"); + + result.push_back("pre_coroutine2_suspend_future"); + size_t futureResult = co_await coroutine2SuspendFuture; + result.push_back("post_coroutine2_suspend_future"); + + co_return 2 + futureResult; + }; + + auto coroutineAll = [&]() -> NThreading::TFuture { + Y_DEFER { + result.push_back("coroutine_all_destroy"); + }; + + result.push_back("pre_coroutine1"); + size_t coroutine1Res = co_await coroutine1(); + result.push_back("post_coroutine1"); + + result.push_back("pre_coroutine2"); + size_t coroutine2Res = co_await coroutine2(); + result.push_back("post_coroutine2"); + + co_return coroutine1Res + coroutine2Res; + }; + + NThreading::TFuture coroutineAllFuture = coroutineAll(); + EXPECT_FALSE(coroutineAllFuture.HasValue()); + EXPECT_FALSE(coroutineAllFuture.HasException()); + EXPECT_THAT( + result, + ::testing::ContainerEq( + TVector({ + "pre_coroutine1", + "coroutine1", + "post_coroutine1", + + "pre_coroutine2", + "coroutine2", + "pre_coroutine2_suspend_future" + }) + ) + ); + + coroutine2SuspendPromise.SetValue(3u); + EXPECT_TRUE(coroutineAllFuture.HasValue()); + EXPECT_EQ(coroutineAllFuture.GetValue(), 6u); + EXPECT_THAT( + result, + ::testing::ContainerEq( + TVector({ + "pre_coroutine1", + "coroutine1", + "post_coroutine1", + + "pre_coroutine2", + "coroutine2", + "pre_coroutine2_suspend_future", + "post_coroutine2_suspend_future", + "post_coroutine2", + + "coroutine_all_destroy" + }) + ) + ); +} + +TEST(TestFutureTraits, Exception) { + TVector result; + + auto coroutine1 = [&result]() -> NThreading::TFuture { + result.push_back("coroutine1"); + co_return 1; + }; + + auto coroutine2 = [&result]() -> NThreading::TFuture { + result.push_back("coroutine2"); + ythrow yexception() << "coroutine2 exception"; + }; + + auto coroutineAll = [&]() -> NThreading::TFuture { + Y_DEFER { + result.push_back("coroutine_all_destroy"); + }; + + result.push_back("pre_coroutine1"); + size_t coroutine1Res = co_await coroutine1(); + result.push_back("post_coroutine1"); + + result.push_back("pre_coroutine2"); + size_t coroutine2Res = co_await coroutine2(); + result.push_back("post_coroutine2"); + + co_return coroutine1Res + coroutine2Res; + }; + + try { + coroutineAll().GetValueSync(); + ADD_FAILURE() << "Expected yexception"; + } catch (const yexception& e) { + EXPECT_THAT(e.AsStrBuf(), ::testing::HasSubstr("coroutine2 exception")); + } + EXPECT_THAT( + result, + ::testing::ContainerEq( + TVector({ + "pre_coroutine1", + "coroutine1", + "post_coroutine1", + + "pre_coroutine2", + "coroutine2", + + "coroutine_all_destroy" + }) + ) + ); +} + +TEST(TestFutureTraits, CrashOnExceptionInCoroutineHandlerResume) { + EXPECT_DEATH( + { + struct TBadPromise; + struct TBadCoroutine : std::coroutine_handle { + using promise_type = TBadPromise; + }; + + struct TBadPromise { + TBadCoroutine get_return_object() { + return {TBadCoroutine::from_promise(*this)}; + } + + std::suspend_never initial_suspend() noexcept { + return {}; + } + std::suspend_never final_suspend() noexcept { + return {}; + } + void return_void() { + } + void unhandled_exception() { + throw; + } + }; + + auto badCoroutine = []() -> TBadCoroutine { + ythrow yexception() << "bad coroutine exception"; + }; + // Sanity check + try { + badCoroutine(); + ADD_FAILURE() << "Expected yexception"; + } catch (const yexception& e) { + EXPECT_THAT(e.AsStrBuf(), ::testing::HasSubstr("bad coroutine exception")); + } + + NThreading::TPromise promise = NThreading::NewPromise(); + auto badCoroutineWithFutureAwait = [future = promise.GetFuture()]() -> TBadCoroutine { + co_await future; + ythrow yexception() << "bad coroutine with future await exception"; + }; + + badCoroutineWithFutureAwait(); + promise.SetValue(); + }, +#if defined(_win_) + ".*" +#else + "bad coroutine with future await exception" +#endif + ); +} + +TEST(ExtractingFutureAwaitable, Simple) { + NThreading::TPromise> suspendPromise = NThreading::NewPromise>(); + auto coro = [](NThreading::TFuture> future) -> NThreading::TFuture> { + auto value = co_await NThreading::AsExtractingAwaitable(std::move(future)); + co_return value; + }; + + NThreading::TFuture> getHolder = coro(suspendPromise.GetFuture()); + EXPECT_FALSE(getHolder.HasValue()); + EXPECT_FALSE(getHolder.HasException()); + suspendPromise.SetValue(MakeHolder(42)); + + EXPECT_TRUE(getHolder.HasValue()); + auto holder = getHolder.ExtractValue(); + ASSERT_NE(holder, nullptr); + EXPECT_EQ(*holder, 42u); +} From d1f7ef77e65882c4333b3a1eff79ea0a08190934 Mon Sep 17 00:00:00 2001 From: Bulat Gayazov Date: Tue, 13 May 2025 16:38:22 +0000 Subject: [PATCH 2/6] Fixed future-ut build for GCC --- library/cpp/testing/unittest/registar.h | 4 ++-- library/cpp/threading/future/CMakeLists.txt | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/library/cpp/testing/unittest/registar.h b/library/cpp/testing/unittest/registar.h index 312796ccf03..54b9b0364c0 100644 --- a/library/cpp/testing/unittest/registar.h +++ b/library/cpp/testing/unittest/registar.h @@ -371,12 +371,12 @@ public: \ #define UNIT_FAIL_IMPL(R, M) \ do { \ - ::NUnitTest::NPrivate::RaiseError(R, ::TStringBuilder() << R << " at " << __LOCATION__ << ", " << __PRETTY_FUNCTION__ << ": " << M, true); \ + ::NUnitTest::NPrivate::RaiseError(R, ::TStringBuilder() << R << " at " << __LOCATION__ << ", " << std::string{__PRETTY_FUNCTION__} << ": " << M, true); \ } while (false) #define UNIT_FAIL_NONFATAL_IMPL(R, M) \ do { \ - ::NUnitTest::NPrivate::RaiseError(R, ::TStringBuilder() << R << " at " << __LOCATION__ << ", " << __PRETTY_FUNCTION__ << ": " << M, false); \ + ::NUnitTest::NPrivate::RaiseError(R, ::TStringBuilder() << R << " at " << __LOCATION__ << ", " << std::string{__PRETTY_FUNCTION__} << ": " << M, false); \ } while (false) #define UNIT_FAIL(M) UNIT_FAIL_IMPL("forced failure", M) diff --git a/library/cpp/threading/future/CMakeLists.txt b/library/cpp/threading/future/CMakeLists.txt index 6cef855eee1..9b1c3c0c9a4 100644 --- a/library/cpp/threading/future/CMakeLists.txt +++ b/library/cpp/threading/future/CMakeLists.txt @@ -25,6 +25,7 @@ if (YDB_SDK_TESTS) future_mt_ut.cpp future_ut.cpp LINK_LIBRARIES + yutil threading-future LABELS unit @@ -34,6 +35,7 @@ if (YDB_SDK_TESTS) SOURCES ut_gtest/coroutine_traits_ut.cpp LINK_LIBRARIES + yutil threading-future LABELS unit From a89e117040a0ef947c836426f99193ac8184b939 Mon Sep 17 00:00:00 2001 From: Bulat Gayazov Date: Wed, 21 May 2025 14:42:33 +0000 Subject: [PATCH 3/6] Skip WaitAny test --- library/cpp/threading/future/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/cpp/threading/future/CMakeLists.txt b/library/cpp/threading/future/CMakeLists.txt index 9b1c3c0c9a4..12fc3d13df9 100644 --- a/library/cpp/threading/future/CMakeLists.txt +++ b/library/cpp/threading/future/CMakeLists.txt @@ -27,10 +27,16 @@ if (YDB_SDK_TESTS) LINK_LIBRARIES yutil threading-future + TEST_ARG + --filter-file filter.txt LABELS unit ) + file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/filter.txt + "-TFutureMultiThreadedTest::WaitAny" + ) + add_ydb_test(NAME future-coroutine-ut GTEST SOURCES ut_gtest/coroutine_traits_ut.cpp From a21fdcf6747387ef07e1c45c9d467f8cbc06447d Mon Sep 17 00:00:00 2001 From: Bulat Gayazov Date: Thu, 22 May 2025 19:07:11 +0000 Subject: [PATCH 4/6] Mute test --- library/cpp/threading/future/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/library/cpp/threading/future/CMakeLists.txt b/library/cpp/threading/future/CMakeLists.txt index 12fc3d13df9..a52442adf77 100644 --- a/library/cpp/threading/future/CMakeLists.txt +++ b/library/cpp/threading/future/CMakeLists.txt @@ -35,6 +35,7 @@ if (YDB_SDK_TESTS) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/filter.txt "-TFutureMultiThreadedTest::WaitAny" + "-TFutureMultiThreadedTest::WaitExceptionOrAll" ) add_ydb_test(NAME future-coroutine-ut GTEST From d1e55d704edf13e69610093545b4b893130b9d16 Mon Sep 17 00:00:00 2001 From: Bulat Gayazov Date: Thu, 22 May 2025 19:48:02 +0000 Subject: [PATCH 5/6] fix --- library/cpp/threading/future/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/cpp/threading/future/CMakeLists.txt b/library/cpp/threading/future/CMakeLists.txt index a52442adf77..d2ad5ac4dc8 100644 --- a/library/cpp/threading/future/CMakeLists.txt +++ b/library/cpp/threading/future/CMakeLists.txt @@ -21,6 +21,8 @@ _ydb_sdk_install_targets(TARGETS threading-future) if (YDB_SDK_TESTS) add_ydb_test(NAME future-ut + WORKING_DIRECTORY + ${CMAKE_CURRENT_BINARY_DIR} SOURCES future_mt_ut.cpp future_ut.cpp From 3a1b56789655be937daad283525e1623f76daa70 Mon Sep 17 00:00:00 2001 From: Bulat Gayazov Date: Thu, 22 May 2025 20:23:03 +0000 Subject: [PATCH 6/6] fix --- library/cpp/threading/future/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/library/cpp/threading/future/CMakeLists.txt b/library/cpp/threading/future/CMakeLists.txt index d2ad5ac4dc8..3ae66ecf4dc 100644 --- a/library/cpp/threading/future/CMakeLists.txt +++ b/library/cpp/threading/future/CMakeLists.txt @@ -21,8 +21,6 @@ _ydb_sdk_install_targets(TARGETS threading-future) if (YDB_SDK_TESTS) add_ydb_test(NAME future-ut - WORKING_DIRECTORY - ${CMAKE_CURRENT_BINARY_DIR} SOURCES future_mt_ut.cpp future_ut.cpp @@ -36,7 +34,7 @@ if (YDB_SDK_TESTS) ) file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/filter.txt - "-TFutureMultiThreadedTest::WaitAny" + "-TFutureMultiThreadedTest::WaitAny\n" "-TFutureMultiThreadedTest::WaitExceptionOrAll" )