From b138f99f4c20ead0471358ed95de048e233a2c4e Mon Sep 17 00:00:00 2001 From: Myles Busig Date: Mon, 22 Jul 2024 18:43:08 -0600 Subject: [PATCH] Add fiber interface --- include/mtl/fiber.hpp | 164 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 include/mtl/fiber.hpp diff --git a/include/mtl/fiber.hpp b/include/mtl/fiber.hpp new file mode 100644 index 0000000..be20222 --- /dev/null +++ b/include/mtl/fiber.hpp @@ -0,0 +1,164 @@ +#pragma once + +#include +#include +#include + +#ifndef MTL_FIBER_MAX_ACTIVE +#define MTL_FIBER_MAX_ACTIVE 4 +#endif + +#ifndef MTL_FIBER_MAX_QUEUE +#define MTL_FIBER_MAX_QUEUE 256 +#endif + +#ifndef MTL_FIBER_MAX_QUEUE_LOW +#define MTL_FIBER_MAX_QUEUE_LOW MTL_FIBER_MAX_QUEUE +#endif + +#ifndef MTL_FIBER_MAX_QUEUE_MED +#define MTL_FIBER_MAX_QUEUE_MED MTL_FIBER_MAX_QUEUE +#endif + +#ifndef MTL_FIBER_MAX_QUEUE_HI +#define MTL_FIBER_MAX_QUEUE_HI MTL_FIBER_MAX_QUEUE +#endif + +#ifndef MTL_FIBER_STACK_SIZE +#define MTL_FIBER_STACK_SIZE 4096 +#endif + +#ifndef MTL_FIBER_MAX_DEPENDENTS +#define MTL_FIBER_MAX_DEPENDENTS 8 +#endif + +extern "C" void mtl_yield(); + +namespace mtl { + +constexpr auto yield = mtl_yield; + +// TEMPORARY +template +class vector { +public: + void push_back(T x) {} + + T* begin() {return nullptr;} + T* end() { return nullptr;} + void clear(); + constexpr size_t capacity() { return N; } + size_t size() { return 0; } +}; + +using fiber_stack = uint8_t[MTL_FIBER_STACK_SIZE]; + +class ifiber; + +class ifiber_dependency { +protected: + mtl::vector m_dependents; + void clear(); + +public: + void add_dependent(ifiber* dependent); +}; + +class fiber_trigger; + +extern ifiber* this_fiber; + +class ifiber : public ifiber_dependency { +public: + enum class priority { + low, + med, + hi, + }; + +protected: + friend class ifiber_dependency; + + static mtl::vector s_queue_low; + static mtl::vector s_queue_med; + static mtl::vector s_queue_hi; + + bool m_finished; + priority m_priority; + uint32_t m_dependencies; + + ifiber(priority priority) : m_priority(priority), m_finished(false), m_dependencies(0) { + switch (priority) { + case priority::low: + // If the queue is already full, a currently running + // fiber must finish first to free room in the queue. + // If all currently running fibers are waiting for a + // dependency, we will throw an exception. + if (s_queue_low.size() == s_queue_low.capacity()) { + mtl::yield(); + } + s_queue_low.push_back(this); + break; + case priority::med: + if (s_queue_med.size() == s_queue_med.capacity()) { + mtl::yield(); + } + s_queue_med.push_back(this); + break; + case priority::hi: + if (s_queue_hi.size() == s_queue_hi.capacity()) { + mtl::yield(); + } + s_queue_hi.push_back(this); + break; + } + } + +public: +}; + +class fiber_trigger : public ifiber_dependency { +public: + void trigger() { + clear(); + } +}; + + +template +class fiber : public ifiber { +public: + using FuncType = RetType(*)(ArgTypes...); + +private: + FuncType m_func; + std::tuple m_args; + +public: + fiber(FuncType func, ArgTypes... args) + : ifiber(priority::med), m_func(func), m_args(args...) {} + + fiber(FuncType func, ArgTypes... args, priority priority) + : ifiber(priority), m_func(func), m_args(args...) {} + + // TODO: Add priority+dependency constructors + + fiber(FuncType func, ArgTypes... args, const ifiber_dependency& dep) + : ifiber(priority::med), m_func(func), m_args(args...) { + dep.add_dependent(this); + } + + template + fiber(FuncType func, ArgTypes... args, It begin, It end) + : ifiber(priority::med), m_func(func), m_args(args...) { + for (; begin != end; ++begin) { + begin->add_dependent(this); + } + } + + void join() { + this_fiber->add_dependent(this); + } +}; + +} // namespace mtl