2020-01-18 05:38:21 -03:00
|
|
|
/*
|
2020-01-24 10:45:29 -03:00
|
|
|
* Copyright (c) 2019-2020, Sergey Bugaev <bugaevc@serenityos.org>
|
2024-10-04 08:19:50 -03:00
|
|
|
* Copyright (c) 2021, Andreas Kling <andreas@ladybird.org>
|
2022-12-29 10:57:00 -03:00
|
|
|
* Copyright (c) 2022-2023, the SerenityOS developers.
|
2020-01-18 05:38:21 -03:00
|
|
|
*
|
2021-04-22 05:24:48 -03:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2020-01-18 05:38:21 -03:00
|
|
|
*/
|
|
|
|
|
|
2019-08-25 12:55:56 -03:00
|
|
|
#pragma once
|
|
|
|
|
|
2026-01-19 16:50:33 -03:00
|
|
|
#include <AK/Atomic.h>
|
2019-08-25 12:55:56 -03:00
|
|
|
#include <AK/Function.h>
|
|
|
|
|
#include <AK/NonnullRefPtr.h>
|
|
|
|
|
#include <AK/Optional.h>
|
|
|
|
|
#include <AK/Queue.h>
|
2020-02-14 18:29:06 -03:00
|
|
|
#include <LibCore/Event.h>
|
2020-02-06 11:04:03 -03:00
|
|
|
#include <LibCore/EventLoop.h>
|
2023-08-06 13:09:39 -03:00
|
|
|
#include <LibCore/EventReceiver.h>
|
2022-12-29 10:57:00 -03:00
|
|
|
#include <LibCore/Promise.h>
|
2025-09-17 17:45:03 -03:00
|
|
|
#include <LibThreading/Forward.h>
|
2019-08-25 12:55:56 -03:00
|
|
|
|
2021-05-22 13:47:42 -03:00
|
|
|
namespace Threading {
|
2019-08-25 12:55:56 -03:00
|
|
|
|
|
|
|
|
template<typename Result>
|
|
|
|
|
class BackgroundAction;
|
|
|
|
|
|
|
|
|
|
class BackgroundActionBase {
|
|
|
|
|
template<typename Result>
|
|
|
|
|
friend class BackgroundAction;
|
|
|
|
|
|
|
|
|
|
private:
|
2022-03-04 17:26:44 -03:00
|
|
|
BackgroundActionBase() = default;
|
2019-08-25 12:55:56 -03:00
|
|
|
|
2024-05-17 21:14:06 -03:00
|
|
|
static void enqueue_work(ESCAPING Function<void()>);
|
2019-08-25 12:55:56 -03:00
|
|
|
static Thread& background_thread();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
template<typename Result>
|
2024-05-17 21:14:06 -03:00
|
|
|
class BackgroundAction final
|
|
|
|
|
: public Core::EventReceiver
|
2019-08-25 12:55:56 -03:00
|
|
|
, private BackgroundActionBase {
|
|
|
|
|
C_OBJECT(BackgroundAction);
|
2020-02-02 08:34:39 -03:00
|
|
|
|
2019-08-25 12:55:56 -03:00
|
|
|
public:
|
2022-03-04 17:26:44 -03:00
|
|
|
virtual ~BackgroundAction() = default;
|
2019-08-25 12:55:56 -03:00
|
|
|
|
2022-12-29 10:57:00 -03:00
|
|
|
Optional<Result> const& result() const { return m_result; }
|
|
|
|
|
Optional<Result>& result() { return m_result; }
|
|
|
|
|
|
2026-01-19 16:50:33 -03:00
|
|
|
// Cancellation is a best-effort cross-thread signal. No other state is protected by this flag.
|
|
|
|
|
// It is not used to synchronize access to any other state (m_result), so relaxed atomics are fine.
|
|
|
|
|
void cancel() { m_canceled.store(true, AK::MemoryOrder::memory_order_relaxed); }
|
2022-12-29 10:57:00 -03:00
|
|
|
// If your action is long-running, you should periodically check the cancel state and possibly return early.
|
2026-01-19 16:50:33 -03:00
|
|
|
bool is_canceled() const { return m_canceled.load(AK::MemoryOrder::memory_order_relaxed); }
|
2022-12-29 10:57:00 -03:00
|
|
|
|
2019-08-25 12:55:56 -03:00
|
|
|
private:
|
2026-02-27 01:50:26 -03:00
|
|
|
BackgroundAction(ESCAPING Function<ErrorOr<Result>(BackgroundAction&)> action, ESCAPING Function<void(Result)> on_complete, ESCAPING Function<void(Error)> on_error = {})
|
2025-02-09 15:00:10 -03:00
|
|
|
: m_action(move(action))
|
2019-08-25 12:55:56 -03:00
|
|
|
, m_on_complete(move(on_complete))
|
2026-02-27 01:50:26 -03:00
|
|
|
, m_on_error(move(on_error))
|
2019-08-25 12:55:56 -03:00
|
|
|
{
|
2026-02-27 01:50:26 -03:00
|
|
|
enqueue_work([self = NonnullRefPtr(*this), origin_event_loop = Core::EventLoop::current_weak()]() mutable {
|
2026-01-19 16:50:33 -03:00
|
|
|
auto result = self->m_action(*self);
|
2026-02-27 01:50:26 -03:00
|
|
|
|
|
|
|
|
auto event_loop = origin_event_loop->take();
|
|
|
|
|
if (!event_loop) {
|
|
|
|
|
dbgln("BackgroundAction {:p} was dropped, the origin loop is gone.", self.ptr());
|
2026-01-19 16:50:33 -03:00
|
|
|
return;
|
|
|
|
|
}
|
2026-02-27 01:50:26 -03:00
|
|
|
event_loop->deferred_invoke([self = move(self), result = move(result)]() mutable {
|
|
|
|
|
auto const canceled = self->m_canceled.load(AK::MemoryOrder::memory_order_relaxed);
|
|
|
|
|
|
|
|
|
|
if (canceled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (result.is_error()) {
|
|
|
|
|
if (self->m_on_error)
|
|
|
|
|
self->m_on_error(result.release_error());
|
|
|
|
|
return;
|
2022-12-29 10:57:00 -03:00
|
|
|
}
|
2026-02-27 01:50:26 -03:00
|
|
|
|
|
|
|
|
if (self->m_on_complete)
|
|
|
|
|
self->m_on_complete(result.release_value());
|
|
|
|
|
});
|
2019-08-25 12:55:56 -03:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-29 10:57:00 -03:00
|
|
|
Function<ErrorOr<Result>(BackgroundAction&)> m_action;
|
2026-02-27 01:50:26 -03:00
|
|
|
Function<void(Result)> m_on_complete;
|
|
|
|
|
Function<void(Error)> m_on_error;
|
2019-08-25 12:55:56 -03:00
|
|
|
Optional<Result> m_result;
|
2026-01-19 16:50:33 -03:00
|
|
|
Atomic<bool> m_canceled { false };
|
2019-08-25 12:55:56 -03:00
|
|
|
};
|
|
|
|
|
|
2024-04-23 21:57:28 -03:00
|
|
|
void quit_background_thread();
|
|
|
|
|
|
2019-08-25 12:55:56 -03:00
|
|
|
}
|