diff options
-rw-r--r-- | includes/Task.h | 17 | ||||
-rw-r--r-- | includes/TaskMan.h | 6 | ||||
-rw-r--r-- | linux-config.h | 1 | ||||
-rw-r--r-- | src/Task.cc | 20 | ||||
-rw-r--r-- | src/TaskMan.cc | 23 | ||||
-rw-r--r-- | tests/test-Tasks.cc | 14 |
6 files changed, 72 insertions, 9 deletions
diff --git a/includes/Task.h b/includes/Task.h index c2777fe..f0c1bbb 100644 --- a/includes/Task.h +++ b/includes/Task.h @@ -2,6 +2,7 @@ #include <stdlib.h> #include <coro.h> +#include <ev++.h> #include <Exceptions.h> #include <vector> @@ -16,14 +17,25 @@ class BaseEvent { public: BaseEvent() : m_signal(false), m_task(NULL) { } bool gotSignal() { return m_signal; } - void doSignal() { m_signal = true; } + void doSignal(); Task * taskWaiting() { Assert(m_task); return m_task; } - void registerOwner(Task * task) { Assert(m_task == NULL); m_task = task; } + void registerOwner(Task * task) { Assert(m_task == NULL); m_task = task; gotOwner(task); } + protected: + virtual void gotOwner(Task * task) { } private: bool m_signal; Task * m_task; }; +class Timeout : public BaseEvent { + public: + Timeout(ev_tstamp tstamp); + void evt_cb(ev::timer & w, int revents); + private: + virtual void gotOwner(Task * task); + ev::timer m_evt; +}; + class TaskEvent : public BaseEvent { public: TaskEvent(Task * taskWaited); @@ -48,6 +60,7 @@ class Task { virtual const char * getName() = 0; Status getStatus() { return m_status; } static Task * getCurrentTask(); + TaskMan * getTaskMan() { return m_taskMan; } protected: void suspend(); virtual void Do() = 0; diff --git a/includes/TaskMan.h b/includes/TaskMan.h index 585fb7f..d8d0c80 100644 --- a/includes/TaskMan.h +++ b/includes/TaskMan.h @@ -2,6 +2,7 @@ #include <stdint.h> #include <coro.h> +#include <ev++.h> #include <ext/hash_set> #include <vector> @@ -18,6 +19,8 @@ class TaskMan { void mainLoop(); void stop() { m_stopped = true; } static TaskMan * getTaskMan(); + struct ev_loop * getLoop() { return m_loop; } + void signalTask(Task * t); private: void registerTask(Task * t); @@ -27,9 +30,10 @@ class TaskMan { struct taskHasher { size_t operator()(const Task * t) const { return reinterpret_cast<uintptr_t>(t); } }; typedef gnu::hash_set<Task *, taskHasher> taskHash_t; typedef std::vector<Task *> taskList_t; - taskHash_t m_tasks; + taskHash_t m_tasks, m_signaledTasks; taskList_t m_pendingAdd; volatile bool m_stopped; + struct ev_loop * m_loop; }; }; diff --git a/linux-config.h b/linux-config.h index 10e8bee..cb3b1b1 100644 --- a/linux-config.h +++ b/linux-config.h @@ -26,6 +26,7 @@ #define HAVE_UTIMES 1 /* libev config */ +#define EV_STANDALONE 1 #define HAVE_CLOCK_SYSCALL 1 #define HAVE_EPOLL_CTL 1 #define HAVE_EVENTFD 1 diff --git a/src/Task.cc b/src/Task.cc index 73a2329..e5c971d 100644 --- a/src/Task.cc +++ b/src/Task.cc @@ -67,9 +67,27 @@ Balau::Task * Balau::Task::getCurrentTask() { void Balau::Task::waitFor(Balau::Events::BaseEvent * e) { e->registerOwner(this); - // probably have to register the event in the Task manager +} + +void Balau::Events::BaseEvent::doSignal() { + m_signal = true; + m_task->getTaskMan()->signalTask(m_task); } Balau::Events::TaskEvent::TaskEvent(Task * taskWaited) : m_taskWaited(taskWaited) { m_taskWaited->m_waitedBy.push_back(this); } + +Balau::Events::Timeout::Timeout(ev_tstamp tstamp) { + m_evt.set<Timeout, &Timeout::evt_cb>(this); + m_evt.set(tstamp); +} + +void Balau::Events::Timeout::gotOwner(Task * task) { + m_evt.set(task->getTaskMan()->getLoop()); + m_evt.start(); +} + +void Balau::Events::Timeout::evt_cb(ev::timer & w, int revents) { + doSignal(); +} diff --git a/src/TaskMan.cc b/src/TaskMan.cc index 6730f13..a9ad709 100644 --- a/src/TaskMan.cc +++ b/src/TaskMan.cc @@ -8,14 +8,19 @@ static Balau::LocalTmpl<Balau::TaskMan> localTaskMan; Balau::TaskMan::TaskMan() : m_stopped(false) { coro_create(&m_returnContext, 0, 0, 0, 0); - if (!localTaskMan.getGlobal()) + if (!localTaskMan.getGlobal()) { localTaskMan.setGlobal(this); + m_loop = ev_default_loop(EVFLAG_AUTO); + } else { + m_loop = ev_loop_new(EVFLAG_AUTO); + } } Balau::TaskMan * Balau::TaskMan::getTaskMan() { return localTaskMan.get(); } Balau::TaskMan::~TaskMan() { Assert(localTaskMan.getGlobal() != this); + ev_loop_destroy(m_loop); } void Balau::TaskMan::mainLoop() { @@ -33,8 +38,6 @@ void Balau::TaskMan::mainLoop() { } } - // That's probably where we poll for events - // lock pending // Adding tasks that were added, maybe from other threads for (iL = m_pendingAdd.begin(); iL != m_pendingAdd.end(); iL++) { @@ -45,6 +48,14 @@ void Balau::TaskMan::mainLoop() { m_pendingAdd.clear(); // unlock pending + ev_run(m_loop, EVRUN_ONCE); + + // let's check who got signaled, and call them + for (iH = m_signaledTasks.begin(); iH != m_signaledTasks.end(); iH++) { + t = *iH; + t->switchTo(); + } + // Dealing with stopped and faulted tasks. // First by signalling the waiters. for (iH = m_tasks.begin(); iH != m_tasks.end(); iH++) { @@ -60,6 +71,7 @@ void Balau::TaskMan::mainLoop() { } } } + m_signaledTasks.clear(); // Then, by destroying them. bool didDelete; @@ -85,3 +97,8 @@ void Balau::TaskMan::registerTask(Balau::Task * t) { m_pendingAdd.push_back(t); // unlock pending } + +void Balau::TaskMan::signalTask(Task * t) { + Assert(m_tasks.find(t) != m_tasks.end()); + m_signaledTasks.insert(t); +} diff --git a/tests/test-Tasks.cc b/tests/test-Tasks.cc index 8de9cf1..148f943 100644 --- a/tests/test-Tasks.cc +++ b/tests/test-Tasks.cc @@ -25,10 +25,20 @@ class TestTask : public Task { void MainTask::Do() { customPrinter = new CustomPrinter(); Printer::log(M_STATUS, "Test::Tasks running."); + Task * testTask = new TestTask(); - Events::TaskEvent e(testTask); - waitFor(&e); + Events::TaskEvent taskEvt(testTask); + waitFor(&taskEvt); + Assert(!taskEvt.gotSignal()); + suspend(); + Assert(taskEvt.gotSignal()); + + Events::Timeout timeout(0.1); + waitFor(&timeout); + Assert(!timeout.gotSignal()); suspend(); + Assert(timeout.gotSignal()); + Printer::log(M_STATUS, "Test::Tasks passed."); Printer::log(M_DEBUG, "You shouldn't see that message."); } |