BackgroundAction.h 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. #pragma once
  2. #include <AK/Function.h>
  3. #include <AK/NonnullRefPtr.h>
  4. #include <AK/Optional.h>
  5. #include <AK/Queue.h>
  6. #include <LibCore/CEventLoop.h>
  7. #include <LibCore/CObject.h>
  8. #include <LibThread/Lock.h>
  9. #include <LibThread/Thread.h>
  10. namespace LibThread {
  11. template<typename Result>
  12. class BackgroundAction;
  13. class BackgroundActionBase {
  14. template<typename Result>
  15. friend class BackgroundAction;
  16. private:
  17. BackgroundActionBase() {}
  18. static Lockable<Queue<Function<void()>>>& all_actions();
  19. static Thread& background_thread();
  20. };
  21. template<typename Result>
  22. class BackgroundAction final : public CObject
  23. , private BackgroundActionBase {
  24. C_OBJECT(BackgroundAction);
  25. public:
  26. static NonnullRefPtr<BackgroundAction<Result>> create(
  27. Function<Result()> action,
  28. Function<void(Result)> on_complete = nullptr
  29. )
  30. {
  31. return adopt(*new BackgroundAction(move(action), move(on_complete)));
  32. }
  33. virtual ~BackgroundAction() {}
  34. private:
  35. BackgroundAction(Function<Result()> action, Function<void(Result)> on_complete)
  36. : CObject(&background_thread())
  37. , m_action(move(action))
  38. , m_on_complete(move(on_complete))
  39. {
  40. LOCKER(all_actions().lock());
  41. this->ref();
  42. all_actions().resource().enqueue([this] {
  43. m_result = m_action();
  44. if (m_on_complete) {
  45. CEventLoop::main().post_event(*this, make<CDeferredInvocationEvent>([this](CObject&) {
  46. m_on_complete(m_result.release_value());
  47. this->deref();
  48. }));
  49. CEventLoop::main().wake();
  50. } else
  51. this->deref();
  52. });
  53. }
  54. Function<Result()> m_action;
  55. Function<void(Result)> m_on_complete;
  56. Optional<Result> m_result;
  57. };
  58. }