Skip to content

Commit

Permalink
[PC] add task manager
Browse files Browse the repository at this point in the history
  • Loading branch information
a8jan committed Nov 8, 2023
1 parent 5a5368e commit 9d9b8ee
Show file tree
Hide file tree
Showing 4 changed files with 403 additions and 0 deletions.
79 changes: 79 additions & 0 deletions lib/task/fnTask.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#ifndef ESP_PLATFORM

#include "fnTask.h"
#include "debug.h"

fnTask::fnTask()
{
Debug_println("fnTask::fnTask");
_id = 0;
_state = TASK_READY;
_reason = TASK_COMPLETED;
_callback = nullptr;
}


fnTask::~fnTask()
{
Debug_printf("fnTask::~fnTask #%d\n", _id);
}


fnTestTask::fnTestTask(int count)
{
Debug_printf("fnTestTask::fnTestTask(%d)\n", count);
_count = count;
_i = 0;
}

fnTestTask::~fnTestTask()
{
Debug_printf("fnTestTask::~fnTestTask #%d\n", _id);
}

int fnTestTask::get_progress()
{
Debug_printf("fnTestTask::get_progress #%d\n", _id);
return 0;
}

void * fnTestTask::get_result()
{
Debug_printf("fnTestTask::get_result #%d\n", _id);
return nullptr;
}


int fnTestTask::start()
{
Debug_printf("fnTestTask::start #%d\n", _id);
return 0;
}

int fnTestTask::pause()
{
Debug_printf("fnTestTask::pause #%d\n", _id);
return 0;
}

int fnTestTask::resume()
{
Debug_printf("fnTestTask::resume #%d\n", _id);
return 0;
}

int fnTestTask::abort()
{
Debug_printf("fnTestTask::abort #%d\n", _id);
return 0;
}

int fnTestTask::step()
{
Debug_printf("fnTestTask::step #%d - %d\n", _id, _i);
if (++_i<_count)
return 0; // continue
return 1; // done
}

#endif // !ESP_PLATFORM
75 changes: 75 additions & 0 deletions lib/task/fnTask.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
#ifndef _FN_TASK_H
#define _FN_TASK_H

#include <stdint.h>

class fnTaskManager;

class fnTask
{
public:
enum task_state
{
TASK_READY = 0,
TASK_RUNNING,
TASK_PAUSED,
TASK_DONE
};

enum done_reason
{
TASK_COMPLETED = 0,
TASK_ABORTED
};

fnTask();
virtual ~fnTask() = 0;

// state, progress and results
task_state get_state() {return _state;};
done_reason get_done_reason() {return _reason;};
virtual int get_progress() {return 0;}; // optional
virtual void * get_result() {return nullptr;}; // optional

protected:
// task state management
// READY -> RUNNING
virtual int start() = 0; // mandatory, must be implemented in sub-class
// RUNNING -> PAUSED
virtual int pause() {return 0;}; // optional
// PAUSED -> RUNNING
virtual int resume() {return 0;}; // optional
// -> DONE/ABORTED, result is not available
virtual int abort() {return 0;}; // optional
// do some work
virtual int step() = 0; // mandatory, must be implemented in sub-class

friend fnTaskManager;

uint8_t _id; // task ID 1..255, 0 is invalid / not yet assigned ID
task_state _state;
done_reason _reason;
void (*_callback)(fnTask *t, task_state new_state);
};

class fnTestTask : public fnTask
{
public:
fnTestTask(int count);
virtual ~fnTestTask() override;
virtual int get_progress() override;
virtual void * get_result() override;

protected:
virtual int start() override;
virtual int pause() override;
virtual int resume() override;
virtual int abort() override;
virtual int step() override;

private:
int _count;
int _i;
};

#endif // _FN_TASK_H
213 changes: 213 additions & 0 deletions lib/task/fnTaskManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
#ifndef ESP_PLATFORM

#include <list>

#include "fnTaskManager.h"
#include "debug.h"

// global task manager object
fnTaskManager taskMgr;


fnTaskManager::fnTaskManager()
{
// Debug_println("fnTaskManager::fnTaskManager");
_next_tid = 1;
_task_count = 0;
}

fnTaskManager::~fnTaskManager()
{
// Debug_println("fnTaskManager::~fnTaskManager");
shutdown();
}

void fnTaskManager::shutdown()
{
// abort tasks, if any
for (auto it = _task_map.begin(); it != _task_map.end(); ++it)
{
Debug_printf("Aborting task %d\n", it->first);
it->second->abort();
delete it->second;
}
_task_map.clear();
_task_count = 0;
}

int fnTaskManager::submit_task(fnTask * t)
{
Debug_println("submit_task");

for (auto it = _task_map.begin(); it != _task_map.end(); ++it)
{
if (it->second == t)
{
Debug_printf(" alredy submitted (task %d)!\n", it->first);
return 0;
}
}

uint8_t tid = get_free_tid();
if (tid == 0)
{
Debug_println(" failed to get free task ID");
}
else
{
// store task
t->_id = tid;
_task_count += 1;
_task_map[tid] = t;
_next_tid = tid+1;
Debug_printf(" submitted #%d\n", tid);
}
return tid;
}

uint8_t fnTaskManager::get_free_tid()
{
uint8_t stop = _next_tid;
uint8_t tid = _next_tid;
while(_task_map.find(tid) != _task_map.end())
{
// try next ID, skip ID 0
if (++tid == 0) ++tid;
if(tid == stop)
{
// wrapped around, no free ID
tid = 0;
break;
}
}
return tid;
}

fnTask * fnTaskManager::get_task(uint8_t tid)
{
Debug_printf("get_task %d\n", tid);
std::map<uint8_t, fnTask *>::iterator it = _task_map.find(tid);
if (it == _task_map.end())
return nullptr;
return it->second;
}

int fnTaskManager::pause_task(uint8_t tid)
{
Debug_printf("pause_task %d\n", tid);
fnTask *task = get_task(tid);
if (task == nullptr)
return -1;
if (task->_state != fnTask::TASK_RUNNING)
return -1;
int result = task->pause();
task->_state = fnTask::TASK_PAUSED;
// TODO callback
return result;
}

int fnTaskManager::resume_task(uint8_t tid)
{
Debug_printf("resume_task %d\n", tid);
fnTask *task = get_task(tid);
if (task == nullptr)
return -1;
if (task->_state != fnTask::TASK_PAUSED)
return -1;
int result = task->resume();
task->_state = fnTask::TASK_RUNNING;
// TODO callback
return result;
}

int fnTaskManager::abort_task(uint8_t tid)
{
Debug_printf("abort_task %d\n", tid);
fnTask *task = get_task(tid);
if (task == nullptr)
return -1;
int result = task->abort();
task->_state = fnTask::TASK_DONE;
task->_reason = fnTask::TASK_ABORTED;
// TODO callback
// remove aborted task
_task_count -= 1;
_task_map.erase(tid);
delete task;
return result;
}

int fnTaskManager::complete_task(uint8_t tid)
{
Debug_printf("complete_task %d\n", tid);
fnTask *task = get_task(tid);
if (task == nullptr)
return -1;
task->_state = fnTask::TASK_DONE;
task->_reason = fnTask::TASK_COMPLETED;
// TODO callback
// remove completed task
_task_count -= 1;
_task_map.erase(tid);
delete task;
return 0;
}

bool fnTaskManager::service()
{
if (_task_count == 0)
return true; // idle

bool idle = true; // was service() idle?
int result;
fnTask *task;
std::list <uint8_t> failed;
std::list <uint8_t> completed;

// update READY and RUNNING tasks
for (auto it = _task_map.begin(); it != _task_map.end(); ++it)
{
task = it->second;
switch (task->_state)
{
case fnTask::TASK_READY:
idle = false;
result = task->start();
if (result < 0)
// failed to start task
failed.push_back(it->first);
else
task->_state = fnTask::TASK_RUNNING;
break;

case fnTask::TASK_RUNNING:
idle = false;
result = task->step();
if (result < 0)
// failure in task execution
failed.push_back(it->first);
else if (result > 0)
{
// task completed
completed.push_back(it->first);
}
break;
default:
;
}
}

if (!idle)
{
// handle failed tasks, if any
for (auto it = failed.begin(); it != failed.end(); ++it)
abort_task(*it);
// handle completed tasks, if any
for (auto it = completed.begin(); it != completed.end(); ++it)
complete_task(*it);
}

return idle;
}

#endif // !ESP_PLATFORM
Loading

0 comments on commit 9d9b8ee

Please sign in to comment.