From d440c3f50a918a932293ad98bcec96eaa4683222 Mon Sep 17 00:00:00 2001 From: Pixel Date: Sun, 4 Dec 2011 01:19:09 -0800 Subject: Reworked some things in the architecture, mainly exceptions and asserts. -) Removed Assert() -) Added AAssert(), IAssert(), RAssert(), TAssert() and Failure() -) Reworked all asserts in the code, and added meaningful messages to them. -) Changed the way the startup code is generated; BALAU_STARTUP is no longer necessary. --- src/BLua.cc | 2 +- src/BStream.cc | 14 ++++---- src/Exceptions.cc | 21 ++++++++++-- src/Handle.cc | 12 +++---- src/HttpServer.cc | 52 ++++++++++++++++------------ src/Input.cc | 8 ++--- src/Local.cc | 3 +- src/Main.cc | 85 ++++++++++++++++++++++++++++++++++++++++++++++ src/Output.cc | 8 ++--- src/SimpleMustache.cc | 50 +++++++++++++-------------- src/Socket.cc | 94 +++++++++++++++++++++++++-------------------------- src/Task.cc | 34 +++++++++++++++---- src/TaskMan.cc | 46 +++++++++++++------------ src/Threads.cc | 18 ++++++---- 14 files changed, 293 insertions(+), 154 deletions(-) (limited to 'src') 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 & 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()) || (m_h.isA())) 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 h) : m_h(h), m_wrote(false) { Assert(m_h->canWrite()); m_name.set("OutputCheck(%s)", m_h->getName()); } + OutputCheck(Balau::IO 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 trace); - void send400() { std::vector d2; sendError(400, "The HTTP request you've sent is invalid", true, d2); } - void send404() { std::vector 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 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 trace); + void send400() { std::vector d2; sendError(400, "The HTTP request you've sent is invalid", NULL, true, d2); } + void send404() { std::vector 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 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( " \n" "

{{title}}

\n" "

{{msg}}

\n" +"{{details}}\n" "{{#hasTrace}}\n" "

Context:

\n" " {{#trace}}
{{line}}
{{/trace}}
\n" @@ -176,7 +177,7 @@ static const char * getErrorMsg(int httpError) { } } -void Balau::HttpWorker::sendError(int error, const char * msg, bool closeConnection, std::vector trace) { +void Balau::HttpWorker::sendError(int error, const char * msg, const char * details, bool closeConnection, std::vector 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::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 trace = e.getTrace(); for (std::vector::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 d; - send500("unknow exception", d); + send500("unknow exception", NULL, d); } return false; } @@ -512,13 +522,13 @@ const char * Balau::HttpWorker::getName() { typedef Balau::Listener 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(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(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 trace = e.getTrace(); + for (std::vector::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 trace = e.getTrace(); + for (std::vector::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 trace = e.getTrace(); + for (std::vector::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(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 _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 _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 _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 _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(IOtype == 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(IOtype == 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(IOtype != 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(IOstr, ++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 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::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(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 trace = e.getTrace(); for (std::vector::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 m_queue; std::queue 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 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() { } -- cgit v1.2.3