diff --git a/include/maxscale/mainworker.hh b/include/maxscale/mainworker.hh index b122e1843..e864c361f 100644 --- a/include/maxscale/mainworker.hh +++ b/include/maxscale/mainworker.hh @@ -15,6 +15,7 @@ #include #include +#include namespace maxscale { @@ -41,10 +42,34 @@ public: */ static MainWorker& get(); + void add_task(const char* zName, TASKFN func, void* pData, int frequency); + void remove_task(const char* zName); + private: bool pre_run() override; void post_run() override; void epoll_tick() override; + + struct Task + { + public: + Task(const char* zName, TASKFN func, void* pData) + : name(zName) + , func(func) + , pData(pData) + , id(0) + { + }; + + std::string name; + TASKFN func; + void* pData; + uint32_t id; + }; + + bool call_task(Worker::Call::action_t action, Task* pTask); + + std::map m_tasks_by_name; }; } diff --git a/server/core/mainworker.cc b/server/core/mainworker.cc index fb65240d0..555d808cd 100644 --- a/server/core/mainworker.cc +++ b/server/core/mainworker.cc @@ -49,6 +49,41 @@ MainWorker& MainWorker::get() return *this_unit.pThis; } +void MainWorker::add_task(const char* zName, TASKFN func, void* pData, int frequency) +{ + call([=]() { + mxb_assert(m_tasks_by_name.find(zName) == m_tasks_by_name.end()); + + Task task(zName, func, pData); + + auto p = m_tasks_by_name.insert(std::make_pair(std::string(zName), task)); + Task& inserted_task = (*p.first).second; + + inserted_task.id = delayed_call(frequency * 1000, + &MainWorker::call_task, + this, + &inserted_task); + }, + EXECUTE_AUTO); +} + +void MainWorker::remove_task(const char* zName) +{ + call([this, zName]() { + auto it = m_tasks_by_name.find(zName); + mxb_assert(it != m_tasks_by_name.end()); + + if (it != m_tasks_by_name.end()) + { + MXB_AT_DEBUG(bool cancelled =) cancel_delayed_call(it->second.id); + mxb_assert(cancelled); + + m_tasks_by_name.erase(it); + } + }, + EXECUTE_AUTO); +} + bool MainWorker::pre_run() { return true; @@ -62,4 +97,28 @@ void MainWorker::epoll_tick() { } +bool MainWorker::call_task(Worker::Call::action_t action, MainWorker::Task* pTask) +{ + bool call_again = false; + + if (action == Worker::Call::EXECUTE) + { + mxb_assert(m_tasks_by_name.find(pTask->name) != m_tasks_by_name.end()); + + call_again = pTask->func(pTask->pData); + + if (!call_again) + { + auto it = m_tasks_by_name.find(pTask->name); + + if (it != m_tasks_by_name.end()) // Not found, if task function removes task. + { + m_tasks_by_name.erase(it); + } + } + } + + return call_again; +} + }