BackgroundAction.h 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. /*
  2. * Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
  3. * Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
  4. * Copyright (c) 2022-2023, the SerenityOS developers.
  5. *
  6. * SPDX-License-Identifier: BSD-2-Clause
  7. */
  8. #pragma once
  9. #include <AK/Function.h>
  10. #include <AK/NonnullRefPtr.h>
  11. #include <AK/Optional.h>
  12. #include <AK/Queue.h>
  13. #include <LibCore/Event.h>
  14. #include <LibCore/EventLoop.h>
  15. #include <LibCore/EventReceiver.h>
  16. #include <LibCore/Promise.h>
  17. #include <LibThreading/Thread.h>
  18. namespace Threading {
  19. template<typename Result>
  20. class BackgroundAction;
  21. class BackgroundActionBase {
  22. template<typename Result>
  23. friend class BackgroundAction;
  24. private:
  25. BackgroundActionBase() = default;
  26. static void enqueue_work(Function<void()>);
  27. static Thread& background_thread();
  28. };
  29. template<typename Result>
  30. class BackgroundAction final : public Core::EventReceiver
  31. , private BackgroundActionBase {
  32. C_OBJECT(BackgroundAction);
  33. public:
  34. // Promise is an implementation detail of BackgroundAction in order to communicate with EventLoop.
  35. // All of the promise's callbacks and state are either managed by us or by EventLoop.
  36. using Promise = Core::Promise<NonnullRefPtr<Core::EventReceiver>>;
  37. virtual ~BackgroundAction() = default;
  38. Optional<Result> const& result() const { return m_result; }
  39. Optional<Result>& result() { return m_result; }
  40. void cancel() { m_canceled = true; }
  41. // If your action is long-running, you should periodically check the cancel state and possibly return early.
  42. bool is_canceled() const { return m_canceled; }
  43. private:
  44. BackgroundAction(Function<ErrorOr<Result>(BackgroundAction&)> action, Function<ErrorOr<void>(Result)> on_complete, Optional<Function<void(Error)>> on_error = {})
  45. : m_promise(Promise::try_create().release_value_but_fixme_should_propagate_errors())
  46. , m_action(move(action))
  47. , m_on_complete(move(on_complete))
  48. {
  49. if (m_on_complete) {
  50. m_promise->on_resolution = [](NonnullRefPtr<Core::EventReceiver>& object) -> ErrorOr<void> {
  51. auto self = static_ptr_cast<BackgroundAction<Result>>(object);
  52. VERIFY(self->m_result.has_value());
  53. if (auto maybe_error = self->m_on_complete(self->m_result.value()); maybe_error.is_error())
  54. self->m_on_error(maybe_error.release_error());
  55. return {};
  56. };
  57. Core::EventLoop::current().add_job(m_promise);
  58. }
  59. if (on_error.has_value())
  60. m_on_error = on_error.release_value();
  61. enqueue_work([self = NonnullRefPtr(*this), origin_event_loop = &Core::EventLoop::current()]() {
  62. auto result = self->m_action(*self);
  63. // The event loop cancels the promise when it exits.
  64. self->m_canceled |= self->m_promise->is_rejected();
  65. // All of our work was successful and we weren't cancelled; resolve the event loop's promise.
  66. if (!self->m_canceled && !result.is_error()) {
  67. self->m_result = result.release_value();
  68. // If there is no completion callback, we don't rely on the user keeping around the event loop.
  69. if (self->m_on_complete) {
  70. origin_event_loop->deferred_invoke([self] {
  71. // Our promise's resolution function will never error.
  72. (void)self->m_promise->resolve(*self);
  73. });
  74. origin_event_loop->wake();
  75. }
  76. } else {
  77. // We were either unsuccessful or cancelled (in which case there is no error).
  78. auto error = Error::from_errno(ECANCELED);
  79. if (result.is_error())
  80. error = result.release_error();
  81. self->m_promise->reject(Error::from_errno(ECANCELED));
  82. if (!self->m_canceled && self->m_on_error) {
  83. origin_event_loop->deferred_invoke([self, error = move(error)]() mutable {
  84. self->m_on_error(move(error));
  85. });
  86. origin_event_loop->wake();
  87. } else if (self->m_on_error) {
  88. self->m_on_error(move(error));
  89. }
  90. }
  91. });
  92. }
  93. NonnullRefPtr<Promise> m_promise;
  94. Function<ErrorOr<Result>(BackgroundAction&)> m_action;
  95. Function<ErrorOr<void>(Result)> m_on_complete;
  96. Function<void(Error)> m_on_error = [](Error error) {
  97. dbgln("Error occurred while running a BackgroundAction: {}", error);
  98. };
  99. Optional<Result> m_result;
  100. bool m_canceled { false };
  101. };
  102. }