diff --git a/impeller/base/base_unittests.cc b/impeller/base/base_unittests.cc index a7c40d868df55..db2c97852be49 100644 --- a/impeller/base/base_unittests.cc +++ b/impeller/base/base_unittests.cc @@ -3,6 +3,7 @@ // found in the LICENSE file. #include "flutter/testing/testing.h" +#include "impeller/base/promise.h" #include "impeller/base/strings.h" #include "impeller/base/thread.h" @@ -233,5 +234,21 @@ TEST(ConditionVariableTest, TestsCriticalSectionAfterWait) { ASSERT_EQ(sum, kThreadCount); } +TEST(BaseTest, NoExceptionPromiseValue) { + NoExceptionPromise wrapper; + std::future future = wrapper.get_future(); + wrapper.set_value(123); + ASSERT_EQ(future.get(), 123); +} + +TEST(BaseTest, NoExceptionPromiseEmpty) { + auto wrapper = std::make_shared>(); + std::future future = wrapper->get_future(); + + // Destroy the empty promise with the future still pending. Verify that the + // process does not abort while destructing the promise. + wrapper.reset(); +} + } // namespace testing } // namespace impeller diff --git a/impeller/base/promise.h b/impeller/base/promise.h index 30d45ae4d3f5f..9f7205eaab60b 100644 --- a/impeller/base/promise.h +++ b/impeller/base/promise.h @@ -17,6 +17,34 @@ std::future RealizedFuture(T t) { return future; } +// Wraps a std::promise and completes the promise with a value during +// destruction if the promise does not already have a value. +// +// By default the std::promise destructor will complete an empty promise with an +// exception. This will fail because Flutter is built without exception support. +template +class NoExceptionPromise { + public: + NoExceptionPromise() = default; + + ~NoExceptionPromise() { + if (!value_set_) { + promise_.set_value({}); + } + } + + std::future get_future() { return promise_.get_future(); } + + void set_value(const T& value) { + promise_.set_value(value); + value_set_ = true; + } + + private: + std::promise promise_; + bool value_set_ = false; +}; + } // namespace impeller #endif // FLUTTER_IMPELLER_BASE_PROMISE_H_ diff --git a/impeller/renderer/backend/vulkan/pipeline_library_vk.cc b/impeller/renderer/backend/vulkan/pipeline_library_vk.cc index 600ef830450d5..130cabd36ae98 100644 --- a/impeller/renderer/backend/vulkan/pipeline_library_vk.cc +++ b/impeller/renderer/backend/vulkan/pipeline_library_vk.cc @@ -170,7 +170,7 @@ PipelineFuture PipelineLibraryVK::GetPipeline( } auto promise = std::make_shared< - std::promise>>>(); + NoExceptionPromise>>>(); auto pipeline_future = PipelineFuture{descriptor, promise->get_future()}; pipelines_[descriptor] = pipeline_future;