Initial commit

This commit is contained in:
Gericom
2025-11-22 17:21:45 +01:00
commit 5d6f67c612
517 changed files with 63025 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
#include "common.h"
#include "Task.h"
void TaskBase::Execute()
{
u32 irqs = rtos_disableIrqs();
if (_state == TaskState::NotStarted)
{
_state = TaskState::Running;
rtos_restoreIrqs(irqs);
TaskState finalState = ExecuteDirect();
SetFinalState(finalState);
}
else
rtos_restoreIrqs(irqs);
}
void TaskBase::SetFinalState(TaskState finalState)
{
u32 irqs = rtos_disableIrqs();
if (_state == TaskState::Running)
{
_state = finalState;
rtos_wakeupQueue(&_threadQueue);
}
rtos_restoreIrqs(irqs);
}
bool TaskBase::Wait()
{
u32 irq = rtos_disableIrqs();
if (!IsCompleted())
rtos_queueThread(rtos_getCurThread(), &_threadQueue);
rtos_restoreIrqs(irq);
return IsCompletedSuccessfully();
}

View File

@@ -0,0 +1,89 @@
#pragma once
#include <type_traits>
#include <memory>
#include <libtwl/rtos/rtosIrq.h>
#include <libtwl/rtos/rtosThread.h>
#include "TaskResult.h"
class TaskBase
{
public:
virtual ~TaskBase() { }
void Execute();
TaskState GetState() const { return _state; }
bool IsCompleted() const { return _state >= TaskState::Completed; }
bool IsCanceled() const { return _state == TaskState::Canceled; }
bool IsFailed() const { return _state == TaskState::Failed; }
bool IsCompletedSuccessfully() const { return _state == TaskState::Completed; }
bool Wait();
bool GetDestroyWhenComplete() const { return _destroyWhenComplete; }
void SetDestroyWhenComplete() { _destroyWhenComplete = true; }
void RequestCancel() { _cancelRequested = true; }
bool IsCancelRequested() const { return _cancelRequested; }
protected:
volatile u8 _cancelRequested = false;
virtual TaskState ExecuteDirect() = 0;
private:
rtos_thread_queue_t _threadQueue = { NULL };
volatile TaskState _state = TaskState::NotStarted;
volatile u8 _destroyWhenComplete = false;
void SetFinalState(TaskState finalState);
};
template <class T>
class Task : public TaskBase
{
public:
const T& GetResult() const { return this->_result; }
protected:
virtual TaskResult<T> ExecuteFunc() const = 0;
private:
T _result;
TaskState ExecuteDirect()
{
auto result = ExecuteFunc();
if (result.GetFinalState() == TaskState::Completed)
this->_result = result.GetResult();
return result.GetFinalState();
}
};
template <>
class Task<void> : public TaskBase
{
protected:
virtual TaskResult<void> ExecuteFunc() const = 0;
private:
TaskState ExecuteDirect() override
{
auto result = ExecuteFunc();
return result.GetFinalState();
}
};
template <class T, typename FuncType>
class FuncTask : public Task<T>
{
public:
FuncTask(const FuncType& function)
: _function(function) { }
private:
const FuncType _function;
TaskResult<T> ExecuteFunc() const override { return _function((const volatile u8&)this->_cancelRequested); }
};

View File

@@ -0,0 +1,27 @@
#pragma once
#include "Task.h"
class TaskFactory
{
template <typename T>
static T TaskResultToResultType(TaskResult<T> arg);
public:
template <typename FuncType>
static auto Create(const FuncType& function)
{
return FuncTask<decltype(TaskResultToResultType(function())), FuncType>(function);
}
template <typename FuncType>
static auto CreateOnHeap(const FuncType& function) -> Task<decltype(TaskResultToResultType(function()))>*
{
return new FuncTask<decltype(TaskResultToResultType(function())), FuncType>(function);
}
template <typename FuncType>
static auto CreateOnHeapUnique(const FuncType& function) -> std::unique_ptr<Task<decltype(TaskResultToResultType(function()))>>
{
return std::make_unique<FuncTask<decltype(TaskResultToResultType(function())), FuncType>>(function);
}
};

View File

@@ -0,0 +1,43 @@
#include "common.h"
#include "TaskQueue.h"
void TaskQueueBase::ThreadMain(TaskBase** queue, u32 queueLength)
{
while (true)
{
_idle = false;
u32 readPtr = _queueReadPtr;
while (readPtr != _queueWritePtr)
{
TaskBase* task = queue[readPtr];
if (readPtr == queueLength - 1)
readPtr = 0;
else
readPtr++;
_queueReadPtr = readPtr;
if (!task)
continue;
task->Execute();
if (task->GetDestroyWhenComplete())
{
// this will destroy the task
ReturnOwnership(task);
}
}
if (_endThreadWhenDone)
return;
_idle = true;
rtos_waitEvent(&_event, false, true);
}
}
void QueueTaskBase::Dispose()
{
if (_task)
{
TaskBase* task = _task;
_task = nullptr;
_taskQueue->ReturnOwnership(task);
_taskQueue = nullptr;
}
}

View File

@@ -0,0 +1,212 @@
#pragma once
#include "common.h"
#include <libtwl/rtos/rtosIrq.h>
#include <libtwl/rtos/rtosEvent.h>
#include <libtwl/rtos/rtosThread.h>
#include "core/BitVector.h"
#include "Task.h"
class TaskQueueBase;
class QueueTaskBase
{
public:
// forbid copies
QueueTaskBase(const QueueTaskBase&) = delete;
QueueTaskBase& operator=(const QueueTaskBase&) = delete;
// move assignment
QueueTaskBase& operator=(QueueTaskBase&& other)
{
_taskQueue = other._taskQueue;
_task = other._task;
other._taskQueue = nullptr;
other._task = nullptr;
return *this;
}
~QueueTaskBase()
{
// extra check here for optimizing out the dispose call after move assignment
if (_task)
Dispose();
}
void Dispose();
void CancelTask()
{
if (_task)
{
_task->RequestCancel();
Dispose();
}
}
constexpr bool IsValid() const { return _task != nullptr; }
protected:
TaskBase* _task;
QueueTaskBase(TaskBase* task, TaskQueueBase* taskQueue)
: _task(task), _taskQueue(taskQueue) { }
private:
TaskQueueBase* _taskQueue;
};
template <typename T>
class QueueTask : public QueueTaskBase
{
public:
QueueTask()
: QueueTaskBase(nullptr, nullptr) { }
QueueTask(Task<T>* task, TaskQueueBase* taskQueue)
: QueueTaskBase(task, taskQueue) { }
const Task<T>& GetTask() const { return (const Task<T>&)*_task; }
};
class TaskQueueBase
{
protected:
template <typename T>
static T TaskResultToResultType(TaskResult<T> arg);
public:
virtual void ReturnOwnership(TaskBase* task) = 0;
template <typename FuncType>
[[gnu::noinline]]
auto Enqueue(const FuncType& function) -> QueueTask<decltype(TaskResultToResultType(function(*new vu8())))>
{
using TaskType = FuncTask<decltype(TaskResultToResultType(function(*new vu8()))), FuncType>;
// static_assert(sizeof(TaskType) <= MaxTaskSize, "Task is too big for this pool");
void* slot = GetSlot();
auto task = new (slot) TaskType(function);
Enqueue(task);
return QueueTask(task, this);
}
protected:
rtos_event_t _event;
vu32 _queueReadPtr = 0;
vu32 _queueWritePtr = 0;
volatile bool _endThreadWhenDone = false;
volatile bool _idle = true;
void ThreadMain(TaskBase** queue, u32 queueLength);
TaskQueueBase()
{
rtos_createEvent(&_event);
}
virtual void* GetSlot() = 0;
virtual void Enqueue(TaskBase* task) = 0;
};
template <u32 QueueLength, u32 MaxTaskSize>
class TaskQueue : public TaskQueueBase
{
public:
using TaskQueueBase::Enqueue;
~TaskQueue()
{
StopThread();
}
[[gnu::noinline]]
void ReturnOwnership(TaskBase* task) override
{
u32 irqs = rtos_disableIrqs();
if (task->IsCompleted())
{
task->~TaskBase();
u32 slot = ((u32)task - (u32)_taskPool) / ((MaxTaskSize + 3) & ~3);
_poolOccupation.Set(slot, 0);
}
else
{
task->SetDestroyWhenComplete();
}
rtos_restoreIrqs(irqs);
}
[[gnu::noinline]]
void StartThread(u8 threadPriority, u32* stack, u32 stackSize)
{
if (_threadStarted)
return;
_endThreadWhenDone = false;
_threadStarted = true;
rtos_createThread(&_thread, threadPriority, ThreadMain, this, stack, stackSize);
rtos_wakeupThread(&_thread);
}
[[gnu::noinline]]
void StopThread()
{
if (!_threadStarted)
return;
_endThreadWhenDone = true;
rtos_signalEvent(&_event);
rtos_joinThread(&_thread);
_threadStarted = false;
}
bool IsIdle() const
{
return _queueReadPtr == _queueWritePtr && _idle;
}
private:
u32 _taskPool[QueueLength][(MaxTaskSize + 3) / 4];
BitVector<QueueLength> _poolOccupation;
TaskBase* _queue[QueueLength];
rtos_thread_t _thread;
bool _threadStarted = false;
[[gnu::noinline]]
u32 AcquireSlot()
{
u32 slot;
u32 irqs = rtos_disableIrqs();
{
slot = _poolOccupation.FindFirstZero();
_poolOccupation.Set(slot, 1);
}
rtos_restoreIrqs(irqs);
LOG_DEBUG("AcquireSlot: %d\n", slot);
return slot;
}
void* GetSlot() override
{
return _taskPool[AcquireSlot()];
}
[[gnu::noinline]]
void Enqueue(TaskBase* task) override
{
u32 writePtr = _queueWritePtr;
_queue[writePtr] = task;
if (writePtr == QueueLength - 1)
_queueWritePtr = 0;
else
_queueWritePtr = writePtr + 1;
rtos_signalEvent(&_event);
}
static void ThreadMain(void* arg)
{
((TaskQueue*)arg)->ThreadMain();
}
void ThreadMain()
{
TaskQueueBase::ThreadMain(&_queue[0], QueueLength);
}
};

View File

@@ -0,0 +1,39 @@
#pragma once
#include "TaskState.h"
template <class T>
class TaskResult
{
const TaskState _finalState;
const T _result;
TaskResult(TaskState finalState)
: _finalState(finalState) { }
TaskResult(const T& result)
: _finalState(TaskState::Completed), _result(result) { }
public:
static TaskResult<T> Failed() { return TaskResult<T>(TaskState::Failed); }
static TaskResult<T> Canceled() { return TaskResult<T>(TaskState::Canceled); }
static TaskResult<T> Completed(const T& result) { return TaskResult<T>(result); }
TaskState GetFinalState() const { return _finalState; }
const T& GetResult() const { return _result; }
};
template <>
class TaskResult<void>
{
const TaskState _finalState;
TaskResult(TaskState finalState)
: _finalState(finalState) { }
public:
static TaskResult<void> Failed() { return TaskResult<void>(TaskState::Failed); }
static TaskResult<void> Canceled() { return TaskResult<void>(TaskState::Canceled); }
static TaskResult<void> Completed() { return TaskResult<void>(TaskState::Completed); }
TaskState GetFinalState() const { return _finalState; }
};

View File

@@ -0,0 +1,10 @@
#pragma once
enum class TaskState : u8
{
NotStarted,
Running,
Completed,
Canceled,
Failed
};