jaffarCommon
Loading...
Searching...
No Matches
dethreader.hpp
Go to the documentation of this file.
1#pragma once
2
8#include "exceptions.hpp"
9#include "timing.hpp"
10#include <functional>
11#include <libco/libco.h>
12#include <memory>
13#include <queue>
14#include <set>
15
19#define __JAFFAR_COMMON_DETHREADER_STATE \
20 namespace jaffarCommon \
21 { \
22 namespace dethreader \
23 { \
24 Runtime* __runtime = nullptr; \
25 } \
26 }
27
31#define __JAFFAR_COMMON_DETHREADER_STACK_SIZE 4 * 1024 * 1024
32
33namespace jaffarCommon
34{
35
36namespace dethreader
37{
38
39class Runtime;
40
44extern Runtime* __runtime;
45
49typedef std::function<void()> threadFc_t;
50
54typedef uint64_t threadId_t;
55
62{
63public:
67 class Thread
68 {
69 public:
95
96 friend class Runtime;
97
98 Thread() = delete;
99 Thread(const Thread&) = delete;
100 void operator=(const Thread&) = delete;
101
110 Thread(const threadFc_t fc, const threadId_t id) : _id(id), _fc(fc)
111 {
112 constexpr size_t stackSize = __JAFFAR_COMMON_DETHREADER_STACK_SIZE;
113 _coroutine = co_create(stackSize, Thread::coroutineWrapper);
114 }
115
119 ~Thread() { co_delete(_coroutine); }
120
126 __JAFFAR_COMMON__INLINE__ void run() const
127 {
128 // If the thread is sleep, checking if it has finished
129 if (_returnReason == returnReason_t::sleeping)
130 {
131 auto timeDelta = timing::timeDeltaMicroseconds(timing::now(), _sleepStartTime);
132
133 // If not, return now without continuing
134 if (timeDelta < _sleepDuration) return;
135 }
136
137 // If the thread is waiting for another to finish, check it now
138 if (_returnReason == returnReason_t::waiting)
139 if (__runtime->getFinishedThreads().contains(_threadWaitedFor) == false) return;
140
141 // Starting or continuing execution
142 co_switch(_coroutine);
143 }
144
148 __JAFFAR_COMMON__INLINE__ void yield()
149 {
150 _returnReason = returnReason_t::none;
152 }
153
159 __JAFFAR_COMMON__INLINE__ returnReason_t getReturnReason() const { return _returnReason; }
160
166 __JAFFAR_COMMON__INLINE__ void sleep(const size_t sleepDuration)
167 {
168 _sleepDuration = sleepDuration;
169 _returnReason = returnReason_t::sleeping;
170 _sleepStartTime = timing::now();
172 }
173
179 __JAFFAR_COMMON__INLINE__ bool joinable() { return true; }
180
186 __JAFFAR_COMMON__INLINE__ void join(const threadId_t threadId)
187 {
188 _threadWaitedFor = threadId;
189 _returnReason = returnReason_t::waiting;
191 }
192
198 __JAFFAR_COMMON__INLINE__ threadId_t getThreadId() const { return _id; }
199
204
205 private:
211 __JAFFAR_COMMON__INLINE__ void setReturnReason(const returnReason_t returnReason) { _returnReason = returnReason; }
212
216 __JAFFAR_COMMON__INLINE__ static void coroutineWrapper()
217 {
218 auto currentThread = __runtime->getCurrentThread();
219 currentThread->_fc();
220 currentThread->setReturnReason(returnReason_t::finished);
222 }
223
227 const threadId_t _id;
228
232 const threadFc_t _fc;
233
237 cothread_t _coroutine;
238
242 returnReason_t _returnReason = none;
243
247 size_t _sleepDuration;
248
252 timing::timePoint _sleepStartTime;
253 };
254
255 Runtime() = default;
256
263 __JAFFAR_COMMON__INLINE__ threadId_t createThread(const threadFc_t fc)
264 {
265 const auto threadId = _uniqueThreadIdCounter;
266 _threadQueue.push(std::make_unique<Thread>(fc, threadId));
267 _uniqueThreadIdCounter++;
268 return threadId;
269 }
270
274 __JAFFAR_COMMON__INLINE__ void initialize()
275 {
276 // Setting singleton
278 }
279
283 __JAFFAR_COMMON__INLINE__ void finalize()
284 {
285 // unsetting singleton
287 }
288
292 __JAFFAR_COMMON__INLINE__ void run()
293 {
294 // Getting main coroutine
295 _coroutine = co_active();
296
297 // Starting to run threads until they are all finished
298 while (_threadQueue.empty() == false)
299 {
300 // Obtaining next thread to run
301 auto thread = std::move(_threadQueue.front());
302
303 // Removing thread from the front
304 _threadQueue.pop();
305
306 // Setting current thread for execution
307 setCurrentThread(thread.get());
308
309 // Running thread
310 thread->run();
311
312 // If thread not finished, re-add to the back of the queue
313 if (thread->getReturnReason() != Thread::returnReason_t::finished)
314 _threadQueue.push(std::move(thread));
315 else // Otherwise add it to the set of finished threads
316 _finishedThreads.insert(thread->getThreadId());
317 }
318 }
319
325 __JAFFAR_COMMON__INLINE__ void setCurrentThread(Thread* const thread) { _currentThread = thread; }
326
332 __JAFFAR_COMMON__INLINE__ Thread* getCurrentThread() const { return _currentThread; }
333
337 __JAFFAR_COMMON__INLINE__ void yieldToRuntime() { co_switch(_coroutine); }
338
344 __JAFFAR_COMMON__INLINE__ const std::set<threadId_t>& getFinishedThreads() const { return _finishedThreads; }
345
346private:
350 threadId_t _uniqueThreadIdCounter = 0;
351
355 std::set<threadId_t> _finishedThreads;
356
360 Thread* _currentThread = nullptr;
361
365 std::queue<std::unique_ptr<Thread>> _threadQueue;
366
370 cothread_t _coroutine;
371};
372
378__JAFFAR_COMMON__INLINE__ Runtime::Thread* getCurrentThread() { return __runtime->getCurrentThread(); }
379
386__JAFFAR_COMMON__INLINE__ threadId_t createThread(const threadFc_t fc)
387{
388 if (__runtime == nullptr) JAFFAR_THROW_LOGIC("Trying to use dethreader runtime before it is initialized");
389 return __runtime->createThread(fc);
390}
391
395__JAFFAR_COMMON__INLINE__ void yield()
396{
397 if (__runtime == nullptr) JAFFAR_THROW_LOGIC("Trying to use dethreader runtime before it is initialized");
399}
400
406__JAFFAR_COMMON__INLINE__ void sleep(const size_t sleepDuration)
407{
408 if (__runtime == nullptr) JAFFAR_THROW_LOGIC("Trying to use dethreader runtime before it is initialized");
409 __runtime->getCurrentThread()->sleep(sleepDuration);
410}
411
417__JAFFAR_COMMON__INLINE__ void join(const threadId_t threadId)
418{
419 if (__runtime == nullptr) JAFFAR_THROW_LOGIC("Trying to use dethreader runtime before it is initialized");
420 __runtime->getCurrentThread()->join(threadId);
421}
422
423} // namespace dethreader
424
425} // namespace jaffarCommon
Definition dethreader.hpp:68
threadId_t _threadWaitedFor
Definition dethreader.hpp:203
Thread(const threadFc_t fc, const threadId_t id)
Definition dethreader.hpp:110
__JAFFAR_COMMON__INLINE__ void join(const threadId_t threadId)
Definition dethreader.hpp:186
returnReason_t
Definition dethreader.hpp:74
@ none
Definition dethreader.hpp:78
@ finished
Definition dethreader.hpp:83
@ waiting
Definition dethreader.hpp:93
@ sleeping
Definition dethreader.hpp:88
__JAFFAR_COMMON__INLINE__ returnReason_t getReturnReason() const
Definition dethreader.hpp:159
__JAFFAR_COMMON__INLINE__ bool joinable()
Definition dethreader.hpp:179
__JAFFAR_COMMON__INLINE__ void yield()
Definition dethreader.hpp:148
~Thread()
Definition dethreader.hpp:119
__JAFFAR_COMMON__INLINE__ threadId_t getThreadId() const
Definition dethreader.hpp:198
__JAFFAR_COMMON__INLINE__ void sleep(const size_t sleepDuration)
Definition dethreader.hpp:166
__JAFFAR_COMMON__INLINE__ void run() const
Definition dethreader.hpp:126
Definition dethreader.hpp:62
__JAFFAR_COMMON__INLINE__ void setCurrentThread(Thread *const thread)
Definition dethreader.hpp:325
__JAFFAR_COMMON__INLINE__ void run()
Definition dethreader.hpp:292
__JAFFAR_COMMON__INLINE__ void initialize()
Definition dethreader.hpp:274
__JAFFAR_COMMON__INLINE__ Thread * getCurrentThread() const
Definition dethreader.hpp:332
__JAFFAR_COMMON__INLINE__ const std::set< threadId_t > & getFinishedThreads() const
Definition dethreader.hpp:344
__JAFFAR_COMMON__INLINE__ threadId_t createThread(const threadFc_t fc)
Definition dethreader.hpp:263
__JAFFAR_COMMON__INLINE__ void yieldToRuntime()
Definition dethreader.hpp:337
__JAFFAR_COMMON__INLINE__ void finalize()
Definition dethreader.hpp:283
uint64_t threadId_t
Definition dethreader.hpp:54
__JAFFAR_COMMON__INLINE__ void sleep(const size_t sleepDuration)
Definition dethreader.hpp:406
#define __JAFFAR_COMMON_DETHREADER_STACK_SIZE
Definition dethreader.hpp:31
__JAFFAR_COMMON__INLINE__ threadId_t createThread(const threadFc_t fc)
Definition dethreader.hpp:386
__JAFFAR_COMMON__INLINE__ void join(const threadId_t threadId)
Definition dethreader.hpp:417
__JAFFAR_COMMON__INLINE__ Runtime::Thread * getCurrentThread()
Definition dethreader.hpp:378
__JAFFAR_COMMON__INLINE__ void yield()
Definition dethreader.hpp:395
std::function< void()> threadFc_t
Definition dethreader.hpp:49
Contains common functions for exception throwing.
#define JAFFAR_THROW_LOGIC(...)
Definition exceptions.hpp:27
Contains common functions related to time measurement.
std::chrono::high_resolution_clock::time_point timePoint
Definition timing.hpp:21