Gaia-ECS v1.0.0
A simple and powerful entity component system
Loading...
Searching...
No Matches
jobcommon.h
1#pragma once
2
3#include <cstddef>
4#include <inttypes.h>
5#include <new>
6#include <type_traits>
7#include <utility>
8
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"
13#include "gaia/util/small_func.h"
14
15namespace gaia {
16 namespace mt {
18 enum class JobPriority : uint8_t {
20 High = 0,
22 Low = 1
23 };
25 static inline constexpr uint32_t JobPriorityCnt = 2;
26
28 enum JobCreationFlags : uint8_t {
30 Default = 0,
32 ManualDelete = 0x01,
34 CanWait = 0x02,
36 Background = 0x04
37 };
38
40 struct JobAllocCtx {
42 JobPriority priority;
43 };
44
46 struct Job {
50 JobPriority priority = JobPriority::High;
52 JobCreationFlags flags = JobCreationFlags::Default;
53 };
54
56 struct JobArgs {
58 uint32_t idxStart;
60 uint32_t idxEnd;
61 };
62
65 static constexpr uint32_t BufferSize = 24;
66
67 enum class Op : uint8_t { Invoke, Destroy, Move };
68 using OpFn = void (*)(Op op, JobArgsFunc* dst, JobArgsFunc* src, const JobArgs* pArgs);
69
70 OpFn m_func = nullptr;
71 alignas(std::max_align_t) uint8_t m_storage[BufferSize];
72
73 void destroy() {
74 if (m_func != nullptr) {
75 m_func(Op::Destroy, this, nullptr, nullptr);
76 m_func = nullptr;
77 }
78 }
79
80 template <typename F>
81 void init(F&& f) {
82 using Fn = std::decay_t<F>;
83 static_assert(std::is_invocable_r_v<void, Fn&, const JobArgs&>, "JobArgsFunc requires a compatible callable");
84 static_assert(std::is_move_constructible_v<Fn>, "Callable must be move-constructible");
85 static_assert(
86 alignof(Fn) <= alignof(std::max_align_t), "Over-aligned callables are not supported for JobArgsFunc");
87
88 if constexpr (sizeof(Fn) <= BufferSize) {
89 new (m_storage) Fn(GAIA_FWD(f));
90
91 m_func = [](Op op, JobArgsFunc* dst, JobArgsFunc* src, const JobArgs* pArgs) {
92 auto* pFn = reinterpret_cast<Fn*>(dst->m_storage);
93 switch (op) {
94 case Op::Invoke:
95 GAIA_ASSERT(pArgs != nullptr);
96 (*pFn)(*pArgs);
97 break;
98 case Op::Destroy:
99 if constexpr (!std::is_trivially_destructible_v<Fn>)
100 pFn->~Fn();
101 break;
102 case Op::Move: {
103 GAIA_ASSERT(src != nullptr);
104 auto* pSrcFn = reinterpret_cast<Fn*>(src->m_storage);
105 new (dst->m_storage) Fn(GAIA_MOV(*pSrcFn));
106 if constexpr (!std::is_trivially_destructible_v<Fn>)
107 pSrcFn->~Fn();
108 dst->m_func = src->m_func;
109 src->m_func = nullptr;
110 break;
111 }
112 }
113 };
114 } else {
115 auto* pStorage = mem::AllocHelper::alloc<Fn>();
116 GAIA_ASSERT((uintptr_t)pStorage % alignof(Fn) == 0);
117 auto* pFunc = new (pStorage) Fn(GAIA_FWD(f));
118 *reinterpret_cast<Fn**>(m_storage) = pFunc;
119
120 m_func = [](Op op, JobArgsFunc* dst, JobArgsFunc* src, const JobArgs* pArgs) {
121 auto*& pFn = *reinterpret_cast<Fn**>(dst->m_storage);
122 switch (op) {
123 case Op::Invoke:
124 GAIA_ASSERT(pArgs != nullptr);
125 GAIA_ASSERT(pFn != nullptr);
126 (*pFn)(*pArgs);
127 break;
128 case Op::Destroy:
129 GAIA_ASSERT(pFn != nullptr);
130 if constexpr (!std::is_trivially_destructible_v<Fn>)
131 pFn->~Fn();
133 pFn = nullptr;
134 break;
135 case Op::Move:
136 GAIA_ASSERT(src != nullptr);
137 *reinterpret_cast<Fn**>(dst->m_storage) = *reinterpret_cast<Fn**>(src->m_storage);
138 dst->m_func = src->m_func;
139 *reinterpret_cast<Fn**>(src->m_storage) = nullptr;
140 src->m_func = nullptr;
141 break;
142 }
143 };
144 }
145 }
146
147 public:
148 JobArgsFunc() = default;
149 ~JobArgsFunc() {
150 destroy();
151 }
152
153 JobArgsFunc(const JobArgsFunc&) = delete;
154 JobArgsFunc& operator=(const JobArgsFunc&) = delete;
155
156 JobArgsFunc(JobArgsFunc&& other) noexcept {
157 if (other.m_func != nullptr)
158 other.m_func(Op::Move, this, &other, nullptr);
159 }
160
161 JobArgsFunc& operator=(JobArgsFunc&& other) noexcept {
162 if (this != &other) {
163 destroy();
164 if (other.m_func != nullptr)
165 other.m_func(Op::Move, this, &other, nullptr);
166 }
167 return *this;
168 }
169
170 template <typename F, typename = std::enable_if_t<!std::is_same_v<std::decay_t<F>, JobArgsFunc>>>
171 JobArgsFunc(F&& f) {
172 init(GAIA_FWD(f));
173 }
174
175 template <typename F, typename = std::enable_if_t<!std::is_same_v<std::decay_t<F>, JobArgsFunc>>>
176 JobArgsFunc& operator=(F&& f) {
177 destroy();
178 init(GAIA_FWD(f));
179 return *this;
180 }
181
182 template <typename F>
183 static JobArgsFunc create(F&& f) {
184 JobArgsFunc func;
185 func.init(GAIA_FWD(f));
186 return func;
187 }
188
189 void exec(const JobArgs& args) const {
190 GAIA_ASSERT(m_func != nullptr);
191 m_func(Op::Invoke, const_cast<JobArgsFunc*>(this), nullptr, &args);
192 }
193
194 void operator()(const JobArgs& args) const {
195 exec(args);
196 }
197
198 void reset() {
199 destroy();
200 }
201
202 explicit operator bool() const {
203 return m_func != nullptr;
204 }
205 };
206
208 struct JobParallel {
212 JobPriority priority = JobPriority::High;
213 };
214
219 void* pCtx = nullptr;
221 void (*invoke)(void*, const JobArgs&) = nullptr;
223 JobPriority priority = JobPriority::High;
224 };
225
226 class ThreadPool;
227
229 struct ThreadCtx {
233 uint32_t workerIdx;
235 JobPriority prio;
237 bool background = false;
239 bool threadCreated = false;
243 JobQueue<512> jobQueue;
244
245 ThreadCtx() = default;
246 ~ThreadCtx() = default;
247
248 void reset() {
249 background = false;
250 threadCreated = false;
251 event.reset();
252 jobQueue.clear();
253 }
254
255 ThreadCtx(const ThreadCtx& other) = delete;
256 ThreadCtx& operator=(const ThreadCtx& other) = delete;
257 ThreadCtx(ThreadCtx&& other) = delete;
258 ThreadCtx& operator=(ThreadCtx&& other) = delete;
259 };
260 } // namespace mt
261} // namespace gaia
Auto-reset synchronization primitive for waking one waiting thread. A successful wait consumes the si...
Definition event.h:20
Move-only callback wrapper specialized for parallel job ranges.
Definition jobcommon.h:64
Process-wide worker pool for dependent frame and background jobs.
Definition threadpool.h:88
Move-only function wrapper with inline storage for small callables. Callables too large for the inlin...
Definition small_func.h:19
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:40
JobPriority priority
Priority encoded into the allocated job handle.
Definition jobcommon.h:42
Half-open item range passed to a parallel job callback.
Definition jobcommon.h:56
uint32_t idxStart
First item index processed by this invocation.
Definition jobcommon.h:58
uint32_t idxEnd
One-past-the-last item index processed by this invocation.
Definition jobcommon.h:60
Non-owning callback descriptor for parallel jobs.
Definition jobcommon.h:217
void(* invoke)(void *, const JobArgs &)
Function that invokes the callback stored in the context.
Definition jobcommon.h:221
void * pCtx
Non-owning callback context.
Definition jobcommon.h:219
JobPriority priority
Queue priority used for each range job.
Definition jobcommon.h:223
Callable and priority for a range-partitioned parallel job.
Definition jobcommon.h:208
JobPriority priority
Queue priority used for each range job.
Definition jobcommon.h:212
JobArgsFunc func
Callable invoked once for each scheduled range.
Definition jobcommon.h:210
Callable and scheduling options for a single job.
Definition jobcommon.h:46
JobCreationFlags flags
Creation and lifetime options.
Definition jobcommon.h:52
JobPriority priority
Queue priority used to schedule the callable.
Definition jobcommon.h:50
util::SmallFunc func
Callable executed by the worker.
Definition jobcommon.h:48
Per-thread execution state owned by ThreadPool.
Definition jobcommon.h:229
bool background
True when the worker executes background jobs.
Definition jobcommon.h:237
JobPriority prio
Job priority.
Definition jobcommon.h:235
uint32_t workerIdx
Worker index.
Definition jobcommon.h:233
Event event
Event signaled when a job is executed.
Definition jobcommon.h:241
ThreadPool * tp
Thread pool pointer.
Definition jobcommon.h:231
bool threadCreated
True when the worker thread has been successfully created.
Definition jobcommon.h:239
JobQueue< 512 > jobQueue
Lock-free work stealing queue for the jobs.
Definition jobcommon.h:243