Add fiber interface

This commit is contained in:
Myles Busig 2024-07-22 18:43:08 -06:00
parent f4e4ef353a
commit b138f99f4c

164
include/mtl/fiber.hpp Normal file
View File

@ -0,0 +1,164 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <tuple>
#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 <typename T, size_t N>
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<ifiber*, MTL_FIBER_MAX_DEPENDENTS> 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<ifiber*, MTL_FIBER_MAX_QUEUE_LOW> s_queue_low;
static mtl::vector<ifiber*, MTL_FIBER_MAX_QUEUE_MED> s_queue_med;
static mtl::vector<ifiber*, MTL_FIBER_MAX_QUEUE_HI> 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 <typename RetType, typename... ArgTypes>
class fiber : public ifiber {
public:
using FuncType = RetType(*)(ArgTypes...);
private:
FuncType m_func;
std::tuple<ArgTypes...> 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 <typename It>
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