Add fiber interface
This commit is contained in:
parent
f4e4ef353a
commit
b138f99f4c
164
include/mtl/fiber.hpp
Normal file
164
include/mtl/fiber.hpp
Normal 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
|
||||
Loading…
x
Reference in New Issue
Block a user