9#include "gaia/core/utility.h"
10#include "gaia/mem/mem_alloc.h"
11#include "gaia/mt/event.h"
12#include "gaia/mt/jobqueue.h"
17 template <
typename Signature>
23 enum class JobPriority : uint8_t {
30 static inline constexpr uint32_t JobPriorityCnt = 2;
33 enum JobCreationFlags : uint8_t {
61 struct is_move_func: std::false_type {};
62 template <
typename Signature>
63 struct is_move_func<util::MoveFunc<Signature>>: std::true_type {};
72 template <
typename TArg>
79 enum class Op : uint8_t { Invoke, Finish, Destroy, Move };
82 OpFn m_func =
nullptr;
83 alignas(std::max_align_t) uint8_t m_storage[
InlineSize];
87 auto*& pStorage = *
reinterpret_cast<void**
>(dst->m_storage);
90 GAIA_ASSERT(
false &&
"The callable was already destroyed by finish()");
98 GAIA_ASSERT(src !=
nullptr);
99 pStorage = *
reinterpret_cast<void**
>(src->m_storage);
100 dst->m_func = src->m_func;
101 src->m_func =
nullptr;
106 template <
typename Fn>
107 static constexpr bool invocable() {
108 if constexpr (std::is_void_v<TArg>)
109 return std::is_invocable_r_v<void, Fn&>;
111 return std::is_invocable_r_v<void, Fn&, const TArg&>;
114 template <
typename Fn>
115 static void invoke(Fn& fn, [[maybe_unused]]
const void* pArg) {
116 if constexpr (std::is_void_v<TArg>)
119 GAIA_ASSERT(pArg !=
nullptr);
120 fn(*
static_cast<const TArg*
>(pArg));
125 if (m_func !=
nullptr) {
126 m_func(Op::Destroy,
this,
nullptr,
nullptr);
131 void exec_inter(
const void* pArg)
const {
132 GAIA_ASSERT(m_func !=
nullptr);
133 m_func(Op::Invoke,
const_cast<JobCallable*
>(
this),
nullptr, pArg);
136 template <
typename F>
138 using Fn = std::decay_t<F>;
140 !std::is_same_v<Fn, util::SmallFunc> && !detail::is_move_func<Fn>::value,
141 "Pass the callable itself. SmallFunc and MoveFunc may keep it in SmallBlockAllocator, which job "
142 "threads must not free from");
143 static_assert(invocable<Fn>(),
"JobCallable requires a callable compatible with its signature");
144 static_assert(std::is_move_constructible_v<Fn>,
"Callable must be move-constructible");
146 alignof(Fn) <=
alignof(std::max_align_t),
"Over-aligned callables are not supported for JobCallable");
148 if constexpr (stores_inline<Fn>()) {
149 new (m_storage) Fn(GAIA_FWD(f));
151 m_func = [](Op op, JobCallable* dst, JobCallable* src,
const void* pArg) {
152 auto* pFn =
reinterpret_cast<Fn*
>(dst->m_storage);
159 if constexpr (!std::is_trivially_destructible_v<Fn>) {
161 dst->m_func =
nullptr;
165 if constexpr (!std::is_trivially_destructible_v<Fn>)
169 GAIA_ASSERT(src !=
nullptr);
170 auto* pSrcFn =
reinterpret_cast<Fn*
>(src->m_storage);
171 new (dst->m_storage) Fn(GAIA_MOV(*pSrcFn));
172 if constexpr (!std::is_trivially_destructible_v<Fn>)
174 dst->m_func = src->m_func;
175 src->m_func =
nullptr;
181 auto* pStorage = mem::AllocHelper::alloc<Fn>();
182 GAIA_ASSERT((uintptr_t)pStorage %
alignof(Fn) == 0);
183 auto* pFunc =
new (pStorage) Fn(GAIA_FWD(f));
184 *
reinterpret_cast<Fn**
>(m_storage) = pFunc;
186 m_func = [](Op op, JobCallable* dst, JobCallable* src,
const void* pArg) {
187 auto*& pFn = *
reinterpret_cast<Fn**
>(dst->m_storage);
190 GAIA_ASSERT(pFn !=
nullptr);
195 if constexpr (!std::is_trivially_destructible_v<Fn>) {
196 GAIA_ASSERT(pFn !=
nullptr);
198 dst->m_func = &op_storage;
202 GAIA_ASSERT(pFn !=
nullptr);
203 if constexpr (!std::is_trivially_destructible_v<Fn>)
208 GAIA_ASSERT(src !=
nullptr);
209 *
reinterpret_cast<Fn**
>(dst->m_storage) = *
reinterpret_cast<Fn**
>(src->m_storage);
210 dst->m_func = src->m_func;
211 *
reinterpret_cast<Fn**
>(src->m_storage) =
nullptr;
212 src->m_func =
nullptr;
223 template <
typename F>
225 using Fn = std::decay_t<F>;
226 return sizeof(Fn) <=
InlineSize &&
alignof(Fn) <=
alignof(std::max_align_t);
231 if (m_func !=
nullptr)
232 m_func(Op::Destroy,
this,
nullptr,
nullptr);
235 JobCallable(
const JobCallable&) =
delete;
236 JobCallable& operator=(
const JobCallable&) =
delete;
241 if (other.m_func !=
nullptr)
242 other.m_func(Op::Move,
this, &other,
nullptr);
249 if (
this != &other) {
251 if (other.m_func !=
nullptr)
252 other.m_func(Op::Move,
this, &other,
nullptr);
260 template <
typename F,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<F>, JobCallable>>>
269 template <
typename F,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<F>, JobCallable>>>
280 template <
typename F>
283 func.init(GAIA_FWD(f));
288 template <
typename T = TArg,
typename = std::enable_if_t<std::is_
void_v<T>>>
295 template <
typename T = TArg,
typename = std::enable_if_t<!std::is_
void_v<T>>>
296 void exec(
const T& arg)
const {
301 template <
typename T = TArg,
typename = std::enable_if_t<std::is_
void_v<T>>>
308 template <
typename T = TArg,
typename = std::enable_if_t<!std::is_
void_v<T>>>
323 if (m_func !=
nullptr)
324 m_func(Op::Finish,
this,
nullptr,
nullptr);
329 explicit operator bool()
const {
330 return m_func !=
nullptr;
335 using JobFunc = JobCallable<void>;
337 using JobArgsFunc = JobCallable<JobArgs>;
350 JobCreationFlags
flags = JobCreationFlags::Default;
Auto-reset synchronization primitive for waking one waiting thread. A successful wait consumes the si...
Definition event.h:20
Move-only type-erased callable owned by a job. Callables of up to InlineSize bytes are stored inline....
Definition jobcommon.h:73
void operator()(const T &arg) const
Invokes the stored callable with arg.
Definition jobcommon.h:309
JobCallable & operator=(JobCallable &&other) noexcept
Destroys the stored callable and takes over the callable of other, leaving it empty.
Definition jobcommon.h:248
static constexpr uint32_t InlineSize
Size in bytes of the inline callable storage.
Definition jobcommon.h:76
void exec(const T &arg) const
Invokes the stored callable with arg.
Definition jobcommon.h:296
JobCallable(JobCallable &&other) noexcept
Takes over the callable of other, leaving it empty.
Definition jobcommon.h:240
void finish()
Ends the lifetime of the stored callable and everything it captured, but keeps any heap storage until...
Definition jobcommon.h:322
void reset()
Destroys the stored callable and everything it captured, and releases its storage.
Definition jobcommon.h:314
JobCallable & operator=(F &&f)
Destroys the stored callable and wraps the callable f.
Definition jobcommon.h:270
JobCallable(F &&f)
Wraps the callable f.
Definition jobcommon.h:261
static JobCallable create(F &&f)
Creates a wrapper for the callable f.
Definition jobcommon.h:281
void exec() const
Invokes the stored callable.
Definition jobcommon.h:289
static GAIA_NODISCARD constexpr bool stores_inline()
Checks whether a callable of type F is stored inline, without a heap allocation.
Definition jobcommon.h:224
void operator()() const
Invokes the stored callable.
Definition jobcommon.h:302
Process-wide worker pool for dependent frame and background jobs.
Definition threadpool.h:78
Definition jobcommon.h:18
static void free(void *ptr)
Releases storage allocated through an adaptor.
Definition mem_alloc.h:276
Allocation metadata used when reserving a job slot.
Definition jobcommon.h:45
JobPriority priority
Priority encoded into the allocated job handle.
Definition jobcommon.h:47
Half-open item range passed to a parallel job callback.
Definition jobcommon.h:51
uint32_t idxStart
First item index processed by this invocation.
Definition jobcommon.h:53
uint32_t idxEnd
One-past-the-last item index processed by this invocation.
Definition jobcommon.h:55
Non-owning callback descriptor for parallel jobs.
Definition jobcommon.h:363
void(* invoke)(void *, const JobArgs &)
Function that invokes the callback stored in the context.
Definition jobcommon.h:367
void * pCtx
Non-owning callback context.
Definition jobcommon.h:365
JobPriority priority
Queue priority used for each range job.
Definition jobcommon.h:369
Callable and priority for a range-partitioned parallel job.
Definition jobcommon.h:354
JobPriority priority
Queue priority used for each range job.
Definition jobcommon.h:358
JobArgsFunc func
Callable invoked once for each scheduled range.
Definition jobcommon.h:356
Callable and scheduling options for a single job.
Definition jobcommon.h:340
JobFunc func
Callable executed by the worker. The job owns it until the job is deleted. An automatically deleted j...
Definition jobcommon.h:346
JobCreationFlags flags
Creation and lifetime options.
Definition jobcommon.h:350
JobPriority priority
Queue priority used to schedule the callable.
Definition jobcommon.h:348
Per-thread execution state owned by ThreadPool.
Definition jobcommon.h:375
bool background
True when the worker executes background jobs.
Definition jobcommon.h:383
JobPriority prio
Job priority.
Definition jobcommon.h:381
uint32_t workerIdx
Worker index.
Definition jobcommon.h:379
Event event
Event signaled when a job is executed.
Definition jobcommon.h:387
ThreadPool * tp
Thread pool pointer.
Definition jobcommon.h:377
bool threadCreated
True when the worker thread has been successfully created.
Definition jobcommon.h:385
JobQueue< 512 > jobQueue
Lock-free work stealing queue for the jobs.
Definition jobcommon.h:389