1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
#include "Task.h"
#include "TaskMan.h"
#include "Exceptions.h"
#include "Printer.h"
#include "Local.h"
static Balau::LocalTmpl<Balau::Task> localTask;
Balau::Task::Task() {
size_t size = stackSize();
m_stack = malloc(size);
coro_create(&m_ctx, coroutine, this, m_stack, size);
m_taskMan = TaskMan::getTaskMan();
m_taskMan->registerTask(this);
m_tls = g_tlsManager->createTLS();
void * oldTLS = g_tlsManager->getTLS();
g_tlsManager->setTLS(m_tls);
localTask.set(this);
g_tlsManager->setTLS(oldTLS);
m_status = STARTING;
m_loop = NULL;
}
Balau::Task::~Task() {
if (m_loop)
ev_loop_destroy(m_loop);
free(m_stack);
free(m_tls);
}
void Balau::Task::coroutine(void * arg) {
Task * task = reinterpret_cast<Task *>(arg);
Assert(task);
try {
task->m_status = RUNNING;
task->Do();
task->m_status = STOPPED;
}
catch (GeneralException & e) {
Printer::log(M_WARNING, "Task %s caused an exception: `%s' - stopping.", task->getName(), e.getMsg());
task->m_status = FAULTED;
}
catch (...) {
Printer::log(M_WARNING, "Task %s caused an unknown exception - stopping.", task->getName());
task->m_status = FAULTED;
}
coro_transfer(&task->m_ctx, &task->m_taskMan->m_returnContext);
}
void Balau::Task::switchTo() {
m_status = RUNNING;
void * oldTLS = g_tlsManager->getTLS();
g_tlsManager->setTLS(m_tls);
coro_transfer(&m_taskMan->m_returnContext, &m_ctx);
g_tlsManager->setTLS(oldTLS);
if (m_status == RUNNING)
m_status = IDLE;
}
void Balau::Task::yield(bool override) {
if (m_loop && override) {
ev_run(m_loop, 0);
} else {
coro_transfer(&m_ctx, &m_taskMan->m_returnContext);
}
}
Balau::Task * Balau::Task::getCurrentTask() {
return localTask.get();
}
void Balau::Task::waitFor(Balau::Events::BaseEvent * e, bool override) {
struct ev_loop * loop = m_loop;
if (!override)
m_loop = NULL;
e->registerOwner(this);
m_loop = loop;
}
void Balau::Task::setPreemptible(bool enable) {
if (!m_loop && !enable) {
m_loop = ev_loop_new(EVFLAG_AUTO);
} else if (m_loop) {
ev_loop_destroy(m_loop);
m_loop = NULL;
}
}
struct ev_loop * Balau::Task::getLoop() {
if (m_loop)
return m_loop;
else
return getTaskMan()->getLoop();
}
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) {
set(tstamp);
}
void Balau::Events::Timeout::set(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->getLoop());
m_evt.start();
}
void Balau::Events::Timeout::evt_cb(ev::timer & w, int revents) {
doSignal();
}
void Balau::Events::Custom::gotOwner(Task * task) {
m_loop = task->getLoop();
}
|