summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/BLua.cc2
-rw-r--r--src/BStream.cc14
-rw-r--r--src/Exceptions.cc21
-rw-r--r--src/Handle.cc12
-rw-r--r--src/HttpServer.cc52
-rw-r--r--src/Input.cc8
-rw-r--r--src/Local.cc3
-rw-r--r--src/Main.cc85
-rw-r--r--src/Output.cc8
-rw-r--r--src/SimpleMustache.cc50
-rw-r--r--src/Socket.cc94
-rw-r--r--src/Task.cc34
-rw-r--r--src/TaskMan.cc46
-rw-r--r--src/Threads.cc18
14 files changed, 293 insertions, 154 deletions
diff --git a/src/BLua.cc b/src/BLua.cc
index 9cfccf1..2f0a5c4 100644
--- a/src/BLua.cc
+++ b/src/BLua.cc
@@ -197,7 +197,7 @@ int Balau::LuaStatics::print(lua_State * __L) {
L.error("`tostring' must return a string to `print'");
if (i > 1)
Printer::print("\t");
- Printer::print(s);
+ Printer::print("%s", s);
L.pop();
}
Printer::print("\n");
diff --git a/src/BStream.cc b/src/BStream.cc
index 89e38b0..cd7a121 100644
--- a/src/BStream.cc
+++ b/src/BStream.cc
@@ -4,7 +4,7 @@
static const int s_blockSize = 16 * 1024;
Balau::BStream::BStream(const IO<Handle> & h) : m_h(h), m_buffer((uint8_t *) malloc(s_blockSize)), m_availBytes(0), m_cursor(0), m_passThru(false) {
- Assert(m_h->canRead());
+ AAssert(m_h->canRead(), "You can't create a buffered stream with a Handle that can't read");
m_name.set("Stream(%s)", m_h->getName());
if ((m_h.isA<Buffer>()) || (m_h.isA<BStream>()))
m_passThru = true;
@@ -50,9 +50,9 @@ ssize_t Balau::BStream::read(void * _buf, size_t count) throw (Balau::GeneralExc
return m_h->read(buf, count) + copied;
m_cursor = 0;
- Assert(m_availBytes == 0);
+ IAssert(m_availBytes == 0, "At this point, our internal buffer should be empty, but it's not: %lu", m_availBytes);
ssize_t r = m_h->read(m_buffer, s_blockSize);
- Assert(r >= 0);
+ RAssert(r >= 0, "BStream got an error while reading: %li", r);
m_availBytes = r;
if (toCopy > m_availBytes)
@@ -74,9 +74,9 @@ int Balau::BStream::peekNextByte() {
ssize_t r = read(&b, 1);
if (!r)
return -1;
- Assert(r == 1);
- Assert(m_cursor > 0);
- Assert(m_availBytes < s_blockSize);
+ RAssert(r == 1, "We asked for one byte, yet we got %li", r);
+ IAssert(m_cursor > 0, "m_cursor is %li", m_cursor);
+ IAssert(m_availBytes < s_blockSize, "m_availBytes = %li; s_blockSize = %i", m_availBytes, s_blockSize);
m_cursor--;
m_availBytes++;
}
@@ -109,7 +109,7 @@ Balau::String Balau::BStream::readString(bool putNL) {
if (isClosed() || isEOF())
return ret;
peekNextByte();
- Assert(m_cursor == 0);
+ IAssert(m_cursor == 0, "m_cursor is %li", m_cursor);
cr = (uint8_t *) memchr(m_buffer, '\r', m_availBytes);
lf = (uint8_t *) memchr(m_buffer, '\n', m_availBytes);
if (cr && lf) {
diff --git a/src/Exceptions.cc b/src/Exceptions.cc
index 94de408..d7d360f 100644
--- a/src/Exceptions.cc
+++ b/src/Exceptions.cc
@@ -52,7 +52,7 @@ void Balau::GeneralException::genTrace() {
String line;
for (int i = 0; i < n; i++)
- line += String().set("%08x ", trace[i]);
+ line += String().set("%08lx ", (uintptr_t) trace[i]);
m_trace.push_back(line);
Dl_info info;
@@ -68,7 +68,7 @@ void Balau::GeneralException::genTrace() {
} else {
demangled = NULL;
}
- line.set("%i: %s(%s%c0x%x) [0x%08x]", i, info.dli_fname, info.dli_sname ? (demangled ? (status == 0 ? demangled : info.dli_sname) : info.dli_sname) : "??", dist < 0 ? '-' : '+', dist < 0 ? -dist : dist, trace[i]);
+ line.set("%i: %s(%s%c0x%lx) [0x%08lx]", i, info.dli_fname, info.dli_sname ? (demangled ? (status == 0 ? demangled : info.dli_sname) : info.dli_sname) : "??", dist < 0 ? '-' : '+', dist < 0 ? -dist : dist, (uintptr_t) trace[i]);
m_trace.push_back(line);
if (demangled)
free(demangled);
@@ -79,3 +79,20 @@ void Balau::GeneralException::genTrace() {
#endif
+
+static void ExitHelperInner(const Balau::String & msg, const char * details) throw (Balau::RessourceException) {
+ throw Balau::RessourceException(msg, details);
+}
+
+void Balau::ExitHelper(const String & msg, const char * fmt, ...) {
+ if (fmt) {
+ String details;
+ va_list ap;
+ va_start(ap, fmt);
+ details.set(fmt, ap);
+ va_end(ap);
+ ExitHelperInner(msg, details.to_charp());
+ } else {
+ ExitHelperInner(msg, NULL);
+ }
+}
diff --git a/src/Handle.cc b/src/Handle.cc
index b8dd45e..f3444d6 100644
--- a/src/Handle.cc
+++ b/src/Handle.cc
@@ -44,7 +44,7 @@ void eioInterface::doStart() {
Balau::Printer::elog(Balau::E_HANDLE, "Starting the eio interface");
Balau::TaskMan * taskMan = Balau::TaskMan::getDefaultTaskMan();
- Assert(taskMan);
+ IAssert(taskMan, "The eio interface shouldn't have started before the task manager");
struct ev_loop * loop = taskMan->getLoop();
m_repeat.set(loop);
@@ -162,7 +162,7 @@ off_t Balau::Handle::wtell() throw (GeneralException) {
bool Balau::SeekableHandle::canSeek() { return true; }
void Balau::SeekableHandle::rseek(off_t offset, int whence) throw (GeneralException) {
- Assert(canRead() || canWrite());
+ AAssert(canRead() || canWrite(), "Can't use a SeekableHandle with a Handle that can neither read or write...");
off_t size;
if (!canRead())
wseek(offset, whence);
@@ -185,7 +185,7 @@ void Balau::SeekableHandle::rseek(off_t offset, int whence) throw (GeneralExcept
}
void Balau::SeekableHandle::wseek(off_t offset, int whence) throw (GeneralException) {
- Assert(canRead() || canWrite());
+ AAssert(canRead() || canWrite(), "Can't use a SeekableHandle with a Handle that can neither read or write...");
off_t size;
if (!canWrite())
rseek(offset, whence);
@@ -208,14 +208,14 @@ void Balau::SeekableHandle::wseek(off_t offset, int whence) throw (GeneralExcept
}
off_t Balau::SeekableHandle::rtell() throw (GeneralException) {
- Assert(canRead() || canWrite());
+ AAssert(canRead() || canWrite(), "Can't use a SeekableHandle with a Handle that can neither read or write...");
if (!canRead())
return wtell();
return m_rOffset;
}
off_t Balau::SeekableHandle::wtell() throw (GeneralException) {
- Assert(canRead() || canWrite());
+ AAssert(canRead() || canWrite(), "Can't use a SeekableHandle with a Handle that can neither read or write...");
if (!canWrite())
return rtell();
return m_wOffset;
@@ -241,7 +241,7 @@ static int eioDone(eio_req * req) {
int Balau::FileSystem::mkdir(const char * path) throw (GeneralException) {
cbResults_t cbResults;
eio_req * r = eio_mkdir(path, 0755, 0, eioDone, &cbResults);
- Assert(r != 0);
+ RAssert(r != NULL, "eio_mkdir returned a NULL eio_req");
Task::yield(&cbResults.evt);
char str[4096];
diff --git a/src/HttpServer.cc b/src/HttpServer.cc
index e80f032..d96dd2b 100644
--- a/src/HttpServer.cc
+++ b/src/HttpServer.cc
@@ -7,7 +7,7 @@
class OutputCheck : public Balau::Handle {
public:
- OutputCheck(Balau::IO<Balau::Handle> h) : m_h(h), m_wrote(false) { Assert(m_h->canWrite()); m_name.set("OutputCheck(%s)", m_h->getName()); }
+ OutputCheck(Balau::IO<Balau::Handle> h) : m_h(h), m_wrote(false) { IAssert(m_h->canWrite(), "We haven't been passed a writable Handle to our HttpWorker... ?"); m_name.set("OutputCheck(%s)", m_h->getName()); }
virtual void close() throw (Balau::GeneralException) { m_h->close(); }
virtual bool isClosed() { return m_h->isClosed(); }
virtual bool isEOF() { return m_h->isEOF(); }
@@ -42,10 +42,10 @@ class HttpWorker : public Task {
virtual const char * getName();
bool handleClient();
- void sendError(int error, const char * msg, bool closeConnection, std::vector<String> trace);
- void send400() { std::vector<String> d2; sendError(400, "The HTTP request you've sent is invalid", true, d2); }
- void send404() { std::vector<String> d2; sendError(404, "The HTTP request you've sent didn't match any action on this server.", false, d2); }
- void send500(const char * msg, std::vector<String> trace) { String smsg; smsg.set("The HTTP request you've sent triggered an internal error: `%s\xc2\xb4", msg); sendError(500, smsg.to_charp(), true, trace); }
+ void sendError(int error, const char * msg, const char * details, bool closeConnection, std::vector<String> trace);
+ void send400() { std::vector<String> d2; sendError(400, "The HTTP request you've sent is invalid", NULL, true, d2); }
+ void send404() { std::vector<String> d2; sendError(404, "The HTTP request you've sent didn't match any action on this server.", NULL, false, d2); }
+ void send500(const char * msg, const char * details, std::vector<String> trace) { String smsg; smsg.set("The HTTP request you've sent triggered an internal error: `%s\xc2\xb4", msg); sendError(500, smsg.to_charp(), details, true, trace); }
String httpUnescape(const char * in);
void readVariables(Http::StringMap & variables, char * str);
@@ -85,6 +85,7 @@ const Balau::String SetDefaultTemplate::m_defaultErrorTemplate(
" <body>\n"
" <h1>{{title}}</h1>\n"
" <h2>{{msg}}</h2>\n"
+"{{details}}\n"
"{{#hasTrace}}\n"
" <br /><h3>Context:</h3>\n"
" {{#trace}}<pre>{{line}}</pre>{{/trace}}<br />\n"
@@ -176,7 +177,7 @@ static const char * getErrorMsg(int httpError) {
}
}
-void Balau::HttpWorker::sendError(int error, const char * msg, bool closeConnection, std::vector<String> trace) {
+void Balau::HttpWorker::sendError(int error, const char * msg, const char * details, bool closeConnection, std::vector<String> trace) {
SimpleMustache * tpl = &m_errorTemplate;
const char * errorMsg = getErrorMsg(error);
Printer::elog(Balau::E_HTTPSERVER, "%s caused a %i error (%s)", m_name.to_charp(), error, errorMsg);
@@ -186,6 +187,8 @@ void Balau::HttpWorker::sendError(int error, const char * msg, bool closeConnect
ctx["title"] = title;
ctx["hasTrace"] = !trace.empty();
ctx["msg"] = msg;
+ if (details)
+ ctx["details"] = details;
if (m_socket->isClosed()) return;
for (std::vector<String>::iterator i = trace.begin(); i != trace.end(); i++)
ctx["trace"][(ssize_t) 0]["line"] = *i;
@@ -210,7 +213,7 @@ void Balau::HttpWorker::sendError(int error, const char * msg, bool closeConnect
"Content-Type: text/html; charset=UTF-8\r\n"
"Connection: keep-alive\r\n"
"Server: %s\r\n"
-"Content-Length: %i\r\n"
+"Content-Length: %lli\r\n"
"\r\n", error, errorMsg, m_serverName.to_charp(), length);
m_socket->forceWrite(headers);
if (m_socket->isClosed()) return;
@@ -402,17 +405,21 @@ bool Balau::HttpWorker::handleClient() {
if (multipart) {
// will handle this horror later...
- Assert(!"multipart/form-data not supported for now");
+ Failure("multipart/form-data not supported for now");
} else {
uint8_t * postData = (uint8_t *) malloc(length);
- try {
- m_strm->forceRead(postData, length);
- }
- catch (EAgain) {
- Assert(evtTimeout.gotSignal());
- Balau::Printer::elog(Balau::E_HTTPSERVER, "%s timed out getting request (reading POST values)", m_name.to_charp());
- return false;
+ while (true) {
+ try {
+ m_strm->forceRead(postData, length);
+ break;
+ }
+ catch (EAgain) {
+ if (!evtTimeout.gotSignal())
+ yield();
+ Balau::Printer::elog(Balau::E_HTTPSERVER, "%s timed out getting request (reading POST values)", m_name.to_charp());
+ return false;
+ }
}
readVariables(variables, (char *) postData);
@@ -473,20 +480,23 @@ bool Balau::HttpWorker::handleClient() {
if (!f.action->Do(m_server, req, f.matches, out))
persistent = false;
}
- catch (GeneralException e) {
+ catch (GeneralException & e) {
Printer::log(M_ERROR, "%s got an exception while processing its request: `%s'", m_name.to_charp(), e.getMsg());
+ const char * details = e.getDetails();
+ if (details)
+ Printer::log(M_ERROR, " %s", details);
std::vector<String> trace = e.getTrace();
for (std::vector<String>::iterator i = trace.begin(); i != trace.end(); i++)
Printer::log(M_DEBUG, "%s", i->to_charp());
if (!out->wrote())
- send500(e.getMsg(), trace);
+ send500(e.getMsg(), details, trace);
return false;
}
catch (...) {
- Printer::log(M_ERROR, "%s got an unknow exception while processing its request: `%s'", m_name.to_charp());
+ Printer::log(M_ERROR, "%s got an unknow exception while processing its request.", m_name.to_charp());
if (!out->wrote()) {
std::vector<String> d;
- send500("unknow exception", d);
+ send500("unknow exception", NULL, d);
}
return false;
}
@@ -512,13 +522,13 @@ const char * Balau::HttpWorker::getName() {
typedef Balau::Listener<Balau::HttpWorker> HttpListener;
void Balau::HttpServer::start() {
- Assert(!m_started);
+ AAssert(!m_started, "Don't start an HttpServer twice");
m_listenerPtr = createTask(new HttpListener(m_port, m_local.to_charp(), this));
m_started = true;
}
void Balau::HttpServer::stop() {
- Assert(m_started);
+ AAssert(m_started, "Don't stop an HttpServer that hasn't been started");
reinterpret_cast<HttpListener *>(m_listenerPtr)->stop();
m_started = false;
}
diff --git a/src/Input.cc b/src/Input.cc
index 73a2a0a..48b32ea 100644
--- a/src/Input.cc
+++ b/src/Input.cc
@@ -55,7 +55,7 @@ Balau::Input::Input(const char * fname) throw (GeneralException) : m_fd(-1), m_s
cbResults_t cbResults;
eio_req * r = eio_open(fname, O_RDONLY, 0, 0, eioDone, &cbResults);
- Assert(r != 0);
+ RAssert(r != NULL, "eio_open returned a NULL eio_req");
Task::yield(&cbResults.evt);
if (cbResults.result < 0) {
char str[4096];
@@ -70,7 +70,7 @@ Balau::Input::Input(const char * fname) throw (GeneralException) : m_fd(-1), m_s
cbStatsResults_t cbStatsResults;
r = eio_fstat(m_fd, 0, eioStatsDone, &cbStatsResults);
- Assert(r != 0);
+ RAssert(r != NULL, "eio_fstat returned a NULL eio_req");
Task::yield(&cbStatsResults.evt);
if (cbStatsResults.result == 0) {
m_size = cbStatsResults.statdata.st_size;
@@ -83,7 +83,7 @@ void Balau::Input::close() throw (GeneralException) {
return;
cbResults_t cbResults;
eio_req * r = eio_close(m_fd, 0, eioDone, &cbResults);
- Assert(r != 0);
+ RAssert(r != NULL, "eio_close returned a NULL eio_req");
m_fd = -1;
Task::yield(&cbResults.evt);
if (cbResults.result < 0) {
@@ -98,7 +98,7 @@ void Balau::Input::close() throw (GeneralException) {
ssize_t Balau::Input::read(void * buf, size_t count) throw (GeneralException) {
cbResults_t cbResults;
eio_req * r = eio_read(m_fd, buf, count, getROffset(), 0, eioDone, &cbResults);
- Assert(r != 0);
+ RAssert(r != NULL, "eio_read returned a NULL eio_req");
Task::yield(&cbResults.evt);
if (cbResults.result > 0) {
rseek(cbResults.result, SEEK_CUR);
diff --git a/src/Local.cc b/src/Local.cc
index 805ecdb..9729c35 100644
--- a/src/Local.cc
+++ b/src/Local.cc
@@ -24,7 +24,6 @@ int Balau::Local::s_size = 0;
void ** Balau::Local::m_globals = 0;
void Balau::Local::doStart() {
- Assert(Main::status() == Main::STARTING);
m_idx = s_size++;
m_globals = reinterpret_cast<void **>(realloc(m_globals, s_size * sizeof(void *)));
m_globals[m_idx] = 0;
@@ -46,7 +45,7 @@ void PThreadsTLSManager::doStart() {
int r;
r = pthread_key_create(&m_key, NULL);
- Assert(r == 0);
+ RAssert(r == 0, "Unable to create a pthtread_key: %i", r);
Balau::g_tlsManager = this;
}
diff --git a/src/Main.cc b/src/Main.cc
index eb5e589..d42a1a5 100644
--- a/src/Main.cc
+++ b/src/Main.cc
@@ -1,4 +1,7 @@
#include "Main.h"
+#include "TaskMan.h"
+#include "Printer.h"
+#include "AtStartExit.h"
Balau::AtStart * Balau::AtStart::s_head = 0;
Balau::AtExit * Balau::AtExit::s_head = 0;
@@ -6,6 +9,7 @@ Balau::AtExit * Balau::AtExit::s_head = 0;
Balau::AtStart::AtStart(int priority) : m_priority(priority) {
if (priority < 0)
return;
+ AAssert(!Main::hasMain(), "An AtStart can't be created dynamically");
AtStart ** ptr = &s_head;
@@ -20,6 +24,7 @@ Balau::AtStart::AtStart(int priority) : m_priority(priority) {
Balau::AtExit::AtExit(int priority) : m_priority(priority) {
if (priority < 0)
return;
+ AAssert(!Main::hasMain(), "An AtExit can't be created dynamically");
AtExit ** ptr = &s_head;
@@ -32,3 +37,83 @@ Balau::AtExit::AtExit(int priority) : m_priority(priority) {
}
Balau::Main * Balau::Main::s_application = NULL;
+
+Balau::MainTask::~MainTask() {
+ if (m_stopTaskManOnExit)
+ TaskMan::stop(0);
+}
+
+const char * Balau::MainTask::getName() {
+ return "Main Task";
+}
+
+int Balau::Main::bootstrap(int _argc, char ** _argv) {
+ int r = 0;
+ m_status = STARTING;
+
+ argc = _argc;
+ argv = _argv;
+ enve = NULL;
+
+ for (AtStart * ptr = AtStart::s_head; ptr; ptr = ptr->m_next)
+ ptr->doStart();
+
+ try {
+ m_status = RUNNING;
+ MainTask * mainTask = createTask(new MainTask());
+ r = TaskMan::getDefaultTaskMan()->mainLoop();
+ m_status = STOPPING;
+ }
+ catch (Exit e) {
+ m_status = STOPPING;
+ Printer::log(M_ERROR, "We shouldn't have gotten an Exit exception here... exitting anyway");
+ std::vector<String> trace = e.getTrace();
+ for (std::vector<String>::iterator i = trace.begin(); i != trace.end(); i++)
+ Printer::log(M_ERROR, "%s", i->to_charp());
+ r = e.getCode();
+ }
+ catch (RessourceException e) {
+ m_status = STOPPING;
+ Printer::log(M_ERROR | M_ALERT, "The application got a ressource problem: %s", e.getMsg());
+ const char * details = e.getDetails();
+ if (details)
+ Printer::log(M_ERROR, " %s", details);
+ std::vector<String> trace = e.getTrace();
+ for (std::vector<String>::iterator i = trace.begin(); i != trace.end(); i++)
+ Printer::log(M_DEBUG, "%s", i->to_charp());
+ r = -1;
+ }
+ catch (GeneralException e) {
+ m_status = STOPPING;
+ Printer::log(M_ERROR | M_ALERT, "The application caused an exception: %s", e.getMsg());
+ const char * details = e.getDetails();
+ if (details)
+ Printer::log(M_ERROR, " %s", details);
+ std::vector<String> trace = e.getTrace();
+ for (std::vector<String>::iterator i = trace.begin(); i != trace.end(); i++)
+ Printer::log(M_DEBUG, "%s", i->to_charp());
+ r = -1;
+ }
+ catch (...) {
+ m_status = STOPPING;
+ Printer::log(M_ERROR | M_ALERT, "The application caused an unknown exception");
+ r = -1;
+ }
+ m_status = STOPPING;
+
+ for (AtExit * ptr = AtExit::s_head; ptr; ptr = ptr->m_next)
+ ptr->doExit();
+
+ m_status = STOPPED;
+ return r;
+}
+
+extern "C" {
+
+int main(int argc, char ** argv) {
+ setlocale(LC_ALL, "");
+ Balau::Main mainClass;
+ return mainClass.bootstrap(argc, argv);
+}
+
+};
diff --git a/src/Output.cc b/src/Output.cc
index 3f66a7c..f147a78 100644
--- a/src/Output.cc
+++ b/src/Output.cc
@@ -55,7 +55,7 @@ Balau::Output::Output(const char * fname, bool truncate) throw (GeneralException
cbResults_t cbResults;
eio_req * r = eio_open(fname, O_WRONLY | O_CREAT | (truncate ? O_TRUNC : 0), 0755, 0, eioDone, &cbResults);
- Assert(r != 0);
+ RAssert(r != NULL, "eio_open returned a NULL eio_req");
Task::yield(&cbResults.evt);
if (cbResults.result < 0) {
char str[4096];
@@ -70,7 +70,7 @@ Balau::Output::Output(const char * fname, bool truncate) throw (GeneralException
cbStatsResults_t cbStatsResults;
r = eio_fstat(m_fd, 0, eioStatsDone, &cbStatsResults);
- Assert(r != 0);
+ RAssert(r != NULL, "eio_fstat returned a NULL eio_req");
Task::yield(&cbStatsResults.evt);
if (cbStatsResults.result == 0) {
m_size = cbStatsResults.statdata.st_size;
@@ -83,7 +83,7 @@ void Balau::Output::close() throw (GeneralException) {
return;
cbResults_t cbResults;
eio_req * r = eio_close(m_fd, 0, eioDone, &cbResults);
- Assert(r != 0);
+ RAssert(r != NULL, "eio_close returned a NULL eio_req");
m_fd = -1;
Task::yield(&cbResults.evt);
if (cbResults.result < 0) {
@@ -98,7 +98,7 @@ void Balau::Output::close() throw (GeneralException) {
ssize_t Balau::Output::write(const void * buf, size_t count) throw (GeneralException) {
cbResults_t cbResults;
eio_req * r = eio_write(m_fd, const_cast<void *>(buf), count, getWOffset(), 0, eioDone, &cbResults);
- Assert(r != 0);
+ RAssert(r != NULL, "eio_write returned a NULL eio_req");
Task::yield(&cbResults.evt);
if (cbResults.result > 0) {
wseek(cbResults.result, SEEK_CUR);
diff --git a/src/SimpleMustache.cc b/src/SimpleMustache.cc
index 97f8faa..92fefeb 100644
--- a/src/SimpleMustache.cc
+++ b/src/SimpleMustache.cc
@@ -58,7 +58,7 @@ index -x of a context == slot number size - x
*/
Balau::SimpleMustache::Context & Balau::SimpleMustache::Context::Proxy::operator[](const char * str) {
- Assert(m_parent->m_type == CONTEXTLIST);
+ IAssert(m_parent->m_type == CONTEXTLIST, "We got a [str] request on a ContextProxy which parent isn't a CONTEXTLIST... ?");
String key = str;
ContextList & ctxLst = m_parent->m_contextList;
if (m_idx <= 0)
@@ -186,7 +186,7 @@ void Balau::SimpleMustache::setTemplate(IO<Handle> _h) {
break;
case READING_INNER:
if (beginning) {
- Assert(p == buf);
+ IAssert(p == buf, "READING_INNER; beginning = true but p isn't at the beginning of the buffer...");
beginning = false;
tagType = NORMAL;
stupidMarker = false;
@@ -256,8 +256,8 @@ void Balau::SimpleMustache::setTemplate(IO<Handle> _h) {
if (++dist == endMarker.strlen()) {
bool pushIt = true;
String str = curFragment->str;
- Assert(str.strlen() != 0);
- Assert(tagType != PARTIAL); // not yet supported
+ AAssert(str.strlen() != 0, "Got an empty tag... ?");
+ AAssert(tagType != PARTIAL, "Partials aren't supported yet");
Regex::Captures c;
switch (tagType) {
case NORMAL:
@@ -279,30 +279,30 @@ void Balau::SimpleMustache::setTemplate(IO<Handle> _h) {
curFragment->type = Fragment::INVERTED;
break;
case PARTIAL:
- Assert(0);
+ Failure("Partials aren't supported yet");
break;
case CHANGING:
pushIt = false;
- Assert(str[0] == '=');
- Assert(str[-1] == '=');
+ IAssert(str[0] == '=', "A CHANGING tag that doesn't start with =... ?");
+ AAssert(str[-1] == '=', "A changing tag must end with =");
c = changing.match(str.to_charp());
- Assert(c.size() == 3);
+ IAssert(c.size() == 3, "The 'changing' regexp didn't match...");
srtMarker = c[1];
endMarker = c[2];
- Assert(srtMarker.strlen() != 0);
- Assert(endMarker.strlen() != 0);
- Assert(srtMarker[0] != endMarker[0]);
- Assert(srtMarker.strchr(' ') < 0);
- Assert(srtMarker.strchr('=') < 0);
- Assert(endMarker.strchr(' ') < 0);
- Assert(endMarker.strchr('=') < 0);
+ AAssert(srtMarker.strlen() != 0, "A new Mustache marker can't be empty.");
+ AAssert(endMarker.strlen() != 0, "A new Mustache marker can't be empty.");
+ AAssert(srtMarker[0] != endMarker[0], "The beginning and end markers can't start with the same character");
+ AAssert(srtMarker.strchr(' ') < 0, "A mustache marker can't contain spaces");
+ AAssert(srtMarker.strchr('=') < 0, "A mustache marker can't contain '='");
+ AAssert(endMarker.strchr(' ') < 0, "A mustache marker can't contain spaces");
+ AAssert(endMarker.strchr('=') < 0, "A mustache marker can't contain '='");
break;
case COMMENT:
pushIt = false;
break;
}
if (pushIt) {
- Assert(curFragment->type != Fragment::UNKNOWN);
+ IAssert(curFragment->type != Fragment::UNKNOWN, "We got an unknown fragment at that point...?");
m_fragments.push_back(curFragment);
curFragment = new Fragment();
}
@@ -315,7 +315,7 @@ void Balau::SimpleMustache::setTemplate(IO<Handle> _h) {
}
}
- Assert(state == PLAIN);
+ IAssert(state == PLAIN, "We shouldn't exit that parsing loop without being in the 'PLAIN' state");
if (p != buf) {
*p = 0;
@@ -335,10 +335,10 @@ Balau::SimpleMustache::Fragments::iterator Balau::SimpleMustache::checkTemplate_
for (cur = begin; cur != end; cur++) {
Fragment * fr = *cur;
if ((fr->type == Fragment::END_SECTION) && (endSection.strlen() != 0)) {
- Assert(fr->str == endSection);
+ AAssert(fr->str == endSection, "Beginning / End sections mismatch (%s != %s)", fr->str.to_charp(), endSection.to_charp());
return cur;
}
- Assert(fr->type != Fragment::END_SECTION);
+ AAssert(fr->type != Fragment::END_SECTION, "Reached an extra end section (%s)", fr->str.to_charp());
if ((fr->type == Fragment::SECTION) || (fr->type == Fragment::INVERTED))
cur = checkTemplate_r(++cur, fr->str);
}
@@ -356,7 +356,7 @@ Balau::SimpleMustache::Fragments::iterator Balau::SimpleMustache::render_r(IO<Ha
Fragment * fr = *cur;
if (fr->type == Fragment::END_SECTION) {
if (depth == 0) {
- Assert(fr->str == endSection);
+ IAssert(fr->str == endSection, "Beginning / End sections mismatch (%s != %s); shouldn't have checkTemplate caught that... ?", fr->str.to_charp(), endSection.to_charp());
end = cur;
break;
} else {
@@ -366,7 +366,7 @@ Balau::SimpleMustache::Fragments::iterator Balau::SimpleMustache::render_r(IO<Ha
if ((fr->type == Fragment::SECTION) || (fr->type == Fragment::INVERTED))
depth++;
}
- Assert(end != m_fragments.end());
+ IAssert(end != m_fragments.end(), "Reached end of template without finding an end section for %s; shouldn't have checkTemplate caught that... ?", endSection.to_charp());
}
if (!ctx) {
@@ -380,7 +380,7 @@ Balau::SimpleMustache::Fragments::iterator Balau::SimpleMustache::render_r(IO<Ha
return end;
}
- Assert(!noWrite);
+ IAssert(!noWrite, "noWrite == true but we have a context... ?");
Context::ContextList::iterator sCtx;
int idx = 0;
@@ -390,8 +390,8 @@ Balau::SimpleMustache::Fragments::iterator Balau::SimpleMustache::render_r(IO<Ha
Context::SubContext::iterator f;
for (cur = begin; cur != end; cur++) {
Fragment * fr = *cur;
- Assert(fr->type != Fragment::UNKNOWN);
- Assert(fr->type != Fragment::END_SECTION);
+ IAssert(fr->type != Fragment::UNKNOWN, "Processing an unknown fragment... ?");
+ IAssert(fr->type != Fragment::END_SECTION, "Processing an end section tag... ?");
switch (fr->type) {
case Fragment::STRING:
h->write(fr->str);
@@ -434,7 +434,7 @@ Balau::SimpleMustache::Fragments::iterator Balau::SimpleMustache::render_r(IO<Ha
cur = render_r(h, NULL, fr->str, ++cur, sCtx->find(fr->str) != sCtx->end(), -1);
break;
default:
- Assert(false);
+ FailureDetails("We shouldn't end up here", "fragment type = %i", fr->type);
break;
}
}
diff --git a/src/Socket.cc b/src/Socket.cc
index af397a6..2f9fa17 100644
--- a/src/Socket.cc
+++ b/src/Socket.cc
@@ -175,40 +175,40 @@ static const char * inet_ntop(int af, const void * src, char * dst, socklen_t si
#if 0
// TODO: use getaddrinfo_a, if available.
#else
-class ResolverThread : public Balau::Thread, public Balau::AtStart, public Balau::AtExit {
+class ResolverThread : public Balau::Thread, public Balau::AtStart {
public:
- ResolverThread() : AtStart(8) { }
+ ResolverThread() : Thread(true), AtStart(8), m_stopping(false) { }
void pushRequest(DNSRequest * req) { m_queue.push(req); }
private:
virtual void * proc();
virtual void doStart();
- virtual void doExit();
+ virtual void threadExit();
Balau::Queue<DNSRequest> m_queue;
+ volatile bool m_stopping;
};
void ResolverThread::doStart() {
threadStart();
}
-void ResolverThread::doExit() {
+void ResolverThread::threadExit() {
+ m_stopping = true;
DNSRequest req;
memset(&req, 0, sizeof(req));
pushRequest(&req);
- join();
}
void * ResolverThread::proc() {
DNSRequest * req;
- DNSRequest stop;
- memset(&stop, 0, sizeof(stop));
- while (true) {
+ while (!m_stopping) {
req = m_queue.pop();
- if (memcmp(&stop, req, sizeof(stop)) == 0)
+ if (m_stopping)
break;
Balau::Printer::elog(Balau::E_SOCKET, "Resolver thread got a request for `%s'", req->name);
req->error = getaddrinfo(req->name, req->service, req->hints, &req->res);
Balau::Printer::elog(Balau::E_SOCKET, "Resolver thread got an answer; sending signal");
- req->evt->trigger();
+ if (!m_stopping)
+ req->evt->trigger();
}
return NULL;
}
@@ -237,7 +237,7 @@ static DNSRequest resolveName(const char * name, const char * service = NULL, st
Balau::Socket::Socket() throw (GeneralException) : m_fd(socket(AF_INET6, SOCK_STREAM, 0)), m_connected(false), m_connecting(false), m_listening(false) {
m_name = "Socket(unconnected)";
- Assert(m_fd >= 0);
+ RAssert(m_fd >= 0, "socket() returned %i", m_fd);
m_evtR = new SocketEvent(m_fd, ev::READ);
m_evtW = new SocketEvent(m_fd, ev::WRITE);
#ifdef _WIN32
@@ -249,7 +249,7 @@ Balau::Socket::Socket() throw (GeneralException) : m_fd(socket(AF_INET6, SOCK_ST
int on = 0;
int r = setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &on, sizeof(on));
- Assert(r == 0);
+ RAssert(r == 0, "setsockopt returned %i", r);
memset(&m_localAddr, 0, sizeof(m_localAddr));
memset(&m_remoteAddr, 0, sizeof(m_remoteAddr));
@@ -272,8 +272,8 @@ Balau::Socket::Socket(int fd) : m_fd(fd), m_connected(true), m_connecting(false)
rLocal = inet_ntop(AF_INET6, &m_localAddr.sin6_addr, prtLocal, len);
rRemote = inet_ntop(AF_INET6, &m_remoteAddr.sin6_addr, prtRemote, len);
- Assert(rLocal);
- Assert(rRemote);
+ RAssert(rLocal, "inet_ntop returned NULL");
+ RAssert(rRemote, "inet_ntop returned NULL");
m_evtR = new SocketEvent(m_fd, ev::READ);
m_evtW = new SocketEvent(m_fd, ev::WRITE);
@@ -314,7 +314,7 @@ bool Balau::Socket::canWrite() { return true; }
const char * Balau::Socket::getName() { return m_name.to_charp(); }
bool Balau::Socket::setLocal(const char * hostname, int port) {
- Assert(m_localAddr.sin6_family == 0);
+ AAssert(m_localAddr.sin6_family == 0, "Can't call setLocal twice");
if (hostname && hostname[0]) {
struct addrinfo hints;
@@ -334,9 +334,9 @@ bool Balau::Socket::setLocal(const char * hostname, int port) {
freeaddrinfo(res);
return false;
}
- Assert(res->ai_family == AF_INET6);
- Assert(res->ai_protocol == IPPROTO_TCP);
- Assert(res->ai_addrlen == sizeof(sockaddr_in6));
+ RAssert(res->ai_family == AF_INET6, "getaddrinfo returned a familiy which isn't AF_INET6; %i", res->ai_family);
+ RAssert(res->ai_protocol == IPPROTO_TCP, "getaddrinfo returned a protocol which isn't IPPROTO_TCP; %i", res->ai_protocol);
+ RAssert(res->ai_addrlen == sizeof(sockaddr_in6), "getaddrinfo returned an addrlen which isn't that of sizeof(sockaddr_in6); %i", res->ai_addrlen);
memcpy(&m_localAddr.sin6_addr, &((sockaddr_in6 *) res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
freeaddrinfo(res);
} else {
@@ -359,14 +359,14 @@ bool Balau::Socket::setLocal(const char * hostname, int port) {
#endif
bool Balau::Socket::connect(const char * hostname, int port) {
- Assert(!m_listening);
- Assert(!m_connected);
- Assert(hostname);
- Assert(!isClosed());
+ AAssert(!m_listening, "You can't call Socket::connect() on a listening socket");
+ AAssert(!m_connected, "You can't call Socket::connect() on an already connected socket");
+ AAssert(hostname, "You can't call Socket::connect() without a hostname");
+ AAssert(m_fd >= 0, "You can't call Socket::connect() on a closed socket");
if (!m_connecting) {
Printer::elog(E_SOCKET, "Resolving %s", hostname);
- Assert(m_remoteAddr.sin6_family == 0);
+ IAssert(m_remoteAddr.sin6_family == 0, "That shouldn't happen...; family = %i", m_remoteAddr.sin6_family);
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
@@ -386,9 +386,9 @@ bool Balau::Socket::connect(const char * hostname, int port) {
return false;
}
Printer::elog(E_SOCKET, "Got a resolution answer");
- Assert(res->ai_family == AF_INET6);
- Assert(res->ai_protocol == IPPROTO_TCP);
- Assert(res->ai_addrlen == sizeof(sockaddr_in6));
+ RAssert(res->ai_family == AF_INET6, "getaddrinfo returned a familiy which isn't AF_INET6; %i", res->ai_family);
+ RAssert(res->ai_protocol == IPPROTO_TCP, "getaddrinfo returned a protocol which isn't IPPROTO_TCP; %i", res->ai_protocol);
+ RAssert(res->ai_addrlen == sizeof(sockaddr_in6), "getaddrinfo returned an addrlen which isn't that of sizeof(sockaddr_in6); %i", res->ai_addrlen);
memcpy(&m_remoteAddr.sin6_addr, &((sockaddr_in6 *) res->ai_addr)->sin6_addr, sizeof(struct in6_addr));
m_remoteAddr.sin6_port = htons(port);
@@ -399,7 +399,7 @@ bool Balau::Socket::connect(const char * hostname, int port) {
freeaddrinfo(res);
} else {
// if we end up there, it means our yield earlier thrown a EAgain exception.
- Assert(m_evtR->gotSignal());
+ AAssert(m_evtR->gotSignal(), "Please don't call connect after a EAgain without checking its signal first.");
}
int spins = 0;
@@ -418,7 +418,7 @@ bool Balau::Socket::connect(const char * hostname, int port) {
} else {
socklen_t sLen = sizeof(err);
int g = getsockopt(m_fd, SOL_SOCKET, SO_ERROR, (char *) &err, &sLen);
- Assert(g == 0);
+ RAssert(g == 0, "getsockopt failed; g = %i", g);
r = err != 0 ? -1 : 0;
}
if ((r == 0) || ((r < 0) && (err == EISCONN))) {
@@ -440,8 +440,8 @@ bool Balau::Socket::connect(const char * hostname, int port) {
rLocal = inet_ntop(AF_INET6, &m_localAddr.sin6_addr, prtLocal, len);
rRemote = inet_ntop(AF_INET6, &m_remoteAddr.sin6_addr, prtRemote, len);
- Assert(rLocal);
- Assert(rRemote);
+ RAssert(rLocal, "inet_ntop returned NULL");
+ RAssert(rRemote, "inet_ntop returned NULL");
m_name.set("Socket(Connected - [%s]:%i -> [%s]:%i)", rLocal, ntohs(m_localAddr.sin6_port), rRemote, ntohs(m_remoteAddr.sin6_port));
Printer::elog(E_SOCKET, "Connected; %s", m_name.to_charp());
@@ -458,12 +458,12 @@ bool Balau::Socket::connect(const char * hostname, int port) {
Printer::elog(E_SOCKET, "Connect() failed with the following error code: %i (%s)", err, strerror(err));
return false;
} else {
- Assert(spins == 0);
+ IAssert(spins == 0, "We shouldn't have spinned...");
}
Task::yield(m_evtW, true);
// if we're still here, it means the parent task doesn't want to be thrown an exception
- Assert(m_evtW->gotSignal());
+ IAssert(m_evtW->gotSignal(), "We shouldn't have been awoken without getting our event signalled");
} while (spins++ < 2);
@@ -471,10 +471,10 @@ bool Balau::Socket::connect(const char * hostname, int port) {
}
bool Balau::Socket::listen() {
- Assert(!m_listening);
- Assert(!m_connecting);
- Assert(!m_connected);
- Assert(!isClosed());
+ AAssert(!m_listening, "You can't call Socket::listen() on an already listening socket");
+ AAssert(!m_connecting, "You can't call Socket::listen() on a connecting socket");
+ AAssert(!m_connected, "You can't call Socket::listen() on a connected socket");
+ AAssert(m_fd >= 0, "You can't call Socket::listen() on a closed socket");
if (::listen(m_fd, 16) == 0) {
m_listening = true;
@@ -490,13 +490,13 @@ bool Balau::Socket::listen() {
len = sizeof(m_localAddr);
rLocal = inet_ntop(AF_INET6, &m_localAddr.sin6_addr, prtLocal, len);
- Assert(rLocal);
+ RAssert(rLocal, "inet_ntop() returned NULL");
m_name.set("Socket(Listener - [%s]:%i)", rLocal, ntohs(m_localAddr.sin6_port));
Printer::elog(E_SOCKET, "Socket %i started to listen: %s", m_fd, m_name.to_charp());
} else {
String msg = getErrorMessage();
- Printer::elog(E_SOCKET, "listen() failed with error #i (%s)", errno, msg.to_charp());
+ Printer::elog(E_SOCKET, "listen() failed with error %i (%s)", errno, msg.to_charp());
}
return m_listening;
@@ -509,8 +509,8 @@ bool Balau::Socket::listen() {
#endif
Balau::IO<Balau::Socket> Balau::Socket::accept() throw (GeneralException) {
- Assert(m_listening);
- Assert(m_fd >= 0);
+ AAssert(m_listening, "You can't call accept() on a non-listening socket");
+ AAssert(m_fd >= 0, "You can't call accept() on a closed socket");
while(true) {
sockaddr_in6 remoteAddr;
@@ -537,8 +537,8 @@ ssize_t Balau::Socket::read(void * buf, size_t count) throw (GeneralException) {
if (count == 0)
return 0;
- Assert(m_connected);
- Assert(m_fd >= 0);
+ AAssert(m_connected, "You can't call read() on a non-connected socket");
+ AAssert(m_fd >= 0, "You can't call read() on a closed socket");
int spins = 0;
@@ -566,15 +566,15 @@ ssize_t Balau::Socket::write(const void * buf, size_t count) throw (GeneralExcep
if (count == 0)
return 0;
- Assert(m_connected);
- Assert(m_fd >= 0);
+ AAssert(m_connected, "You can't call write() on a non-connected socket");
+ AAssert(m_fd >= 0, "You can't call write() on a closed socket");
int spins = 0;
do {
ssize_t r = ::send(m_fd, (const char *) buf, count, 0);
- Assert(r != 0);
+ RAssert(r != 0, "send() returned 0 (broken pipe ?)");
if (r > 0)
return r;
@@ -607,9 +607,9 @@ void Balau::ListenerBase::stop() {
void Balau::ListenerBase::Do() {
bool r = m_listener->setLocal(m_local.to_charp(), m_port);
- Assert(r);
+ RAssert(r, "Couldn't set the local IP/port to listen to");
r = m_listener->listen();
- Assert(r);
+ RAssert(r, "Couldn't listen on the given IP/port");
setName();
setOkayToEAgain(true);
waitFor(&m_evt);
diff --git a/src/Task.cc b/src/Task.cc
index 848ab37..cc6fa94 100644
--- a/src/Task.cc
+++ b/src/Task.cc
@@ -24,11 +24,11 @@ bool Balau::Task::needsStacks() {
void Balau::Task::setup(TaskMan * taskMan, void * stack) {
size_t size = stackSize();
#ifndef _WIN32
- Assert(stack);
+ IAssert(stack, "Can't setup a coroutine without a stack");
m_stack = stack;
coro_create(&m_ctx, coroutineTrampoline, this, m_stack, size);
#else
- Assert(!stack);
+ Assert(!stack, "We shouldn't allocate stacks with Fibers");
m_stack = NULL;
m_fiber = CreateFiber(size, coroutineTrampoline, this);
#endif
@@ -48,19 +48,39 @@ Balau::Task::~Task() {
void Balau::Task::coroutineTrampoline(void * arg) {
Task * task = reinterpret_cast<Task *>(arg);
- Assert(task);
+ IAssert(task, "We didn't get a task to trampoline from... ?");
task->coroutine();
}
void Balau::Task::coroutine() {
- Assert(m_status == STARTING);
+ IAssert(m_status == STARTING, "The Task at %p was badly initialized ? m_status = %i", this, m_status);
try {
m_status = RUNNING;
Do();
m_status = STOPPED;
}
+ catch (Exit & e) {
+ m_status = STOPPED;
+ TaskMan::stop(e.getCode());
+ }
+ catch (TestException & e) {
+ m_status = STOPPED;
+ Printer::log(M_ERROR, "Unit test failed: %s", e.getMsg());
+ TaskMan::stop(-1);
+ }
+ catch (RessourceException & e) {
+ m_status = STOPPED;
+ Printer::log(M_ERROR, "Got a ressource exhaustion problem: %s", e.getMsg());
+ const char * details = e.getDetails();
+ if (details)
+ Printer::log(M_ERROR, " %s", details);
+ TaskMan::stop(-1);
+ }
catch (GeneralException & e) {
Printer::log(M_WARNING, "Task %s at %p caused an exception: `%s' - stopping.", getName(), this, e.getMsg());
+ const char * details = e.getDetails();
+ if (details)
+ Printer::log(M_WARNING, " %s", details);
std::vector<String> trace = e.getTrace();
for (std::vector<String>::iterator i = trace.begin(); i != trace.end(); i++)
Printer::log(M_DEBUG, "%s", i->to_charp());
@@ -79,7 +99,7 @@ void Balau::Task::coroutine() {
void Balau::Task::switchTo() {
Printer::elog(E_TASK, "Switching to task %p - %s", this, getName());
- Assert(m_status == IDLE || m_status == STARTING);
+ IAssert(m_status == IDLE || m_status == STARTING, "The task at %p isn't either idle or starting... ? m_status = %i", this, m_status);
void * oldTLS = g_tlsManager->getTLS();
g_tlsManager->setTLS(m_tls);
#ifndef _WIN32
@@ -157,7 +177,7 @@ Balau::Events::TaskEvent::~TaskEvent() {
}
void Balau::Events::TaskEvent::ack() {
- Assert(!m_ack);
+ AAssert(!m_ack, "You can't ack() a task event twice.");
bool deleted = false;
Task * t = m_taskWaited;
Task::waitedByList_t::iterator i;
@@ -169,7 +189,7 @@ void Balau::Events::TaskEvent::ack() {
}
}
Printer::elog(E_TASK, "TaskEvent at %p being ack; removing from the 'waited by' list of %p (%s - %s); deleted = %s", this, t, t->getName(), ClassName(t).c_str(), deleted ? "true" : "false");
- Assert(deleted);
+ IAssert(deleted, "We didn't find task %p in the waitedBy lists... ?", this);
m_ack = true;
reset();
}
diff --git a/src/TaskMan.cc b/src/TaskMan.cc
index 28fb0e3..ba74c8f 100644
--- a/src/TaskMan.cc
+++ b/src/TaskMan.cc
@@ -4,12 +4,16 @@
#include "Local.h"
class Stopper : public Balau::Task {
+ public:
+ Stopper(int code) : m_code(code) { }
+ private:
virtual void Do();
virtual const char * getName();
+ int m_code;
};
void Stopper::Do() {
- getMyTaskMan()->stopMe();
+ getMyTaskMan()->stopMe(m_code);
}
const char * Stopper::getName() {
@@ -23,16 +27,16 @@ static const int TOO_MANY_STACKS = 1024;
namespace Balau {
-class TaskScheduler : public Thread, public AtStart, public AtExit {
+class TaskScheduler : public Thread, public AtStart {
public:
- TaskScheduler() : AtStart(100), m_stopping(false) { }
+ TaskScheduler() : Thread(true), AtStart(100), m_stopping(false) { }
void registerTask(Task * t);
virtual void * proc();
virtual void doStart();
- virtual void doExit();
+ virtual void threadExit();
void registerTaskMan(TaskMan * t);
void unregisterTaskMan(TaskMan * t);
- void stopAll();
+ void stopAll(int code);
private:
Queue<Task> m_queue;
std::queue<TaskMan *> m_taskManagers;
@@ -70,7 +74,7 @@ void Balau::TaskScheduler::unregisterTaskMan(TaskMan * t) {
m_lock.leave();
}
-void Balau::TaskScheduler::stopAll() {
+void Balau::TaskScheduler::stopAll(int code) {
m_stopping = true;
m_lock.enter();
std::queue<TaskMan *> altQueue;
@@ -79,7 +83,7 @@ void Balau::TaskScheduler::stopAll() {
tm = m_taskManagers.front();
m_taskManagers.pop();
altQueue.push(tm);
- tm->addToPending(new Stopper());
+ tm->addToPending(new Stopper(code));
tm->m_evt.send();
}
while (!altQueue.empty()) {
@@ -120,22 +124,21 @@ void Balau::TaskScheduler::doStart() {
threadStart();
}
-void Balau::TaskScheduler::doExit() {
+void Balau::TaskScheduler::threadExit() {
Task * s = NULL;
m_queue.push(s);
- join();
}
void asyncDummy(ev::async & w, int revents) {
Balau::Printer::elog(Balau::E_TASK, "TaskMan is getting woken up...");
}
-Balau::TaskMan::TaskMan() : m_stopped(false), m_allowedToSignal(false) {
+Balau::TaskMan::TaskMan() : m_stopped(false), m_allowedToSignal(false), m_stopCode(0) {
#ifndef _WIN32
coro_create(&m_returnContext, 0, 0, 0, 0);
#else
m_fiber = ConvertThreadToFiber(NULL);
- Assert(m_fiber);
+ RAssert(m_fiber, "ConvertThreadToFiber returned NULL");
#endif
TaskMan * global = localTaskMan.getGlobal();
if (!global) {
@@ -159,7 +162,7 @@ class WinSocketStartup : public Balau::AtStart {
virtual void doStart() {
WSADATA wsaData;
int r = WSAStartup(MAKEWORD(2, 0), &wsaData);
- Assert(r == 0);
+ RAssert(r == 0, "WSAStartup returned %i", r);
}
};
@@ -169,7 +172,7 @@ static WinSocketStartup wsa;
Balau::TaskMan * Balau::TaskMan::getDefaultTaskMan() { return localTaskMan.get(); }
Balau::TaskMan::~TaskMan() {
- Assert(localTaskMan.getGlobal() != this);
+ AAssert(localTaskMan.getGlobal() != this, "Don't create / delete a TaskMan directly");
while (m_stacks.size() != 0) {
free(m_stacks.front());
m_stacks.pop();
@@ -203,13 +206,13 @@ void Balau::TaskMan::freeStack(void * stack) {
}
}
-void Balau::TaskMan::mainLoop() {
+int Balau::TaskMan::mainLoop() {
do {
taskHash_t::iterator iH;
Task * t;
bool noWait = false;
- Printer::elog(E_TASK, "TaskMan::mainLoop() at %p with m_tasks.size = %i", this, m_tasks.size());
+ Printer::elog(E_TASK, "TaskMan::mainLoop() at %p with m_tasks.size = %li", this, m_tasks.size());
// checking "STARTING" tasks, and running them once; also try to build the status of the noWait boolean.
for (iH = m_tasks.begin(); iH != m_tasks.end(); iH++) {
@@ -248,7 +251,7 @@ void Balau::TaskMan::mainLoop() {
for (iH = m_signaledTasks.begin(); iH != m_signaledTasks.end(); iH++) {
t = *iH;
Printer::elog(E_TASK, "TaskMan at %p Switching to task %p (%s - %s) that got signaled somehow.", this, t, t->getName(), ClassName(t).c_str());
- Assert(t->getStatus() == Task::IDLE);
+ IAssert(t->getStatus() == Task::IDLE, "We're switching to a non-idle task... ? status = %i", t->getStatus());
t->switchTo();
}
m_signaledTasks.clear();
@@ -258,7 +261,7 @@ void Balau::TaskMan::mainLoop() {
Printer::elog(E_TASK, "TaskMan at %p trying to pop a task...", this);
t = m_pendingAdd.pop();
Printer::elog(E_TASK, "TaskMan at %p popped task %p...", this, t);
- Assert(m_tasks.find(t) == m_tasks.end());
+ IAssert(m_tasks.find(t) == m_tasks.end(), "TaskMan got task %p twice... ?", t);
ev_now_update(m_loop);
t->setup(this, getStack());
m_tasks.insert(t);
@@ -283,6 +286,7 @@ void Balau::TaskMan::mainLoop() {
} while (!m_stopped);
Printer::elog(E_TASK, "TaskManager at %p stopping.", this);
+ return m_stopCode;
}
void Balau::TaskMan::registerTask(Balau::Task * t, Balau::Task * stick) {
@@ -300,13 +304,13 @@ void Balau::TaskMan::addToPending(Balau::Task * t) {
}
void Balau::TaskMan::signalTask(Task * t) {
- Assert(m_tasks.find(t) != m_tasks.end());
- Assert(m_allowedToSignal);
+ AAssert(m_tasks.find(t) != m_tasks.end(), "Can't signal task %p that I don't own (me = %p)", t, this);
+ AAssert(m_allowedToSignal, "I'm not allowed to signal (me = %p)", this);
m_signaledTasks.insert(t);
}
-void Balau::TaskMan::stop() {
- s_scheduler.stopAll();
+void Balau::TaskMan::stop(int code) {
+ s_scheduler.stopAll(code);
}
class ThreadedTaskMan : public Balau::Thread {
diff --git a/src/Threads.cc b/src/Threads.cc
index f6578ed..df19da2 100644
--- a/src/Threads.cc
+++ b/src/Threads.cc
@@ -17,11 +17,11 @@ Balau::Lock::Lock() {
pthread_mutexattr_t attr;
r = pthread_mutexattr_init(&attr);
- Assert(r == 0);
+ RAssert(r == 0, "Couldn't initialize mutex attribute; r = %i", r);
r = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
- Assert(r == 0);
+ RAssert(r == 0, "Couldn't set mutex attribute; r = %i", r);
r = pthread_mutex_init(&m_lock, &attr);
- Assert(r == 0);
+ RAssert(r == 0, "Couldn't initialize mutex; r = %i", r);
}
void * Balau::ThreadHelper::threadProc(void * arg) {
@@ -39,8 +39,10 @@ Balau::Thread::~Thread() {
void * Balau::Thread::join() {
void * r = NULL;
- if (Atomic::CmpXChgBool(&m_joined, true, false))
+ if (Atomic::CmpXChgBool(&m_joined, true, false)) {
+ threadExit();
pthread_join(m_thread, &r);
+ }
return r;
}
@@ -49,9 +51,11 @@ void Balau::Thread::threadStart() {
int r;
r = pthread_attr_init(&attr);
- Assert(r == 0);
+ RAssert(r == 0, "Couldn't initialize pthread attribute; r = %i", r);
r = pthread_create(&m_thread, &attr, Balau::ThreadHelper::threadProc, this);
- Assert(r == 0);
+ RAssert(r == 0, "Couldn't create pthread; r = %i", r);
r = pthread_attr_destroy(&attr);
- Assert(r == 0);
+ RAssert(r == 0, "Couldn't destroy pthread attribute; r = %i", r);
}
+
+void Balau::Thread::threadExit() { }