diff --git a/Libraries/LibThreading/BackgroundAction.h b/Libraries/LibThreading/BackgroundAction.h index c783c87696b..263b94f6741 100644 --- a/Libraries/LibThreading/BackgroundAction.h +++ b/Libraries/LibThreading/BackgroundAction.h @@ -56,12 +56,13 @@ public: private: BackgroundAction(ESCAPING Function(BackgroundAction&)> action, ESCAPING Function(Result)> on_complete, ESCAPING Optional> on_error = {}) - : m_promise(Promise::try_create().release_value_but_fixme_should_propagate_errors()) - , m_action(move(action)) + : m_action(move(action)) , m_on_complete(move(on_complete)) { + auto promise = Promise::construct(); + if (m_on_complete) { - m_promise->on_resolution = [](NonnullRefPtr& object) -> ErrorOr { + promise->on_resolution = [](NonnullRefPtr& object) -> ErrorOr { auto self = static_ptr_cast>(object); VERIFY(self->m_result.has_value()); if (auto maybe_error = self->m_on_complete(self->m_result.value()); maybe_error.is_error()) @@ -69,24 +70,27 @@ private: return {}; }; - Core::EventLoop::current().add_job(m_promise); + Core::EventLoop::current().add_job(promise); } if (on_error.has_value()) m_on_error = on_error.release_value(); - enqueue_work([self = NonnullRefPtr(*this), origin_event_loop = &Core::EventLoop::current()]() { + enqueue_work([self = NonnullRefPtr(*this), promise = move(promise), origin_event_loop = &Core::EventLoop::current()]() mutable { auto result = self->m_action(*self); + // The event loop cancels the promise when it exits. - self->m_canceled |= self->m_promise->is_rejected(); + self->m_canceled |= promise->is_rejected(); + // All of our work was successful and we weren't cancelled; resolve the event loop's promise. if (!self->m_canceled && !result.is_error()) { self->m_result = result.release_value(); + // If there is no completion callback, we don't rely on the user keeping around the event loop. if (self->m_on_complete) { - origin_event_loop->deferred_invoke([self] { + origin_event_loop->deferred_invoke([self, promise = move(promise)] { // Our promise's resolution function will never error. - (void)self->m_promise->resolve(*self); + (void)promise->resolve(*self); }); origin_event_loop->wake(); } @@ -96,7 +100,8 @@ private: if (result.is_error()) error = result.release_error(); - self->m_promise->reject(Error::from_errno(ECANCELED)); + promise->reject(Error::from_errno(ECANCELED)); + if (!self->m_canceled && self->m_on_error) { origin_event_loop->deferred_invoke([self, error = move(error)]() mutable { self->m_on_error(move(error)); @@ -109,7 +114,6 @@ private: }); } - NonnullRefPtr m_promise; Function(BackgroundAction&)> m_action; Function(Result)> m_on_complete; Function m_on_error = [](Error error) {