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. --- includes/AtStartExit.h | 27 +++++++++++++ includes/BString.h | 6 +-- includes/Exceptions.h | 90 ++++++++++++++++++++++++++++++++++++------- includes/Handle.h | 13 +++++-- includes/HttpServer.h | 6 +-- includes/Main.h | 98 ++++------------------------------------------- includes/Printer.h | 10 ++--- includes/SimpleMustache.h | 8 ++-- includes/Socket.h | 2 + includes/Task.h | 17 ++++++-- includes/TaskMan.h | 10 +++-- includes/Threads.h | 9 +++-- 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 +++++---- tests/test-Handles.cc | 56 +++++++++++++-------------- tests/test-Http.cc | 11 +++--- tests/test-Lua.cc | 12 +++--- tests/test-Regex.cc | 12 +++--- tests/test-Sanity.cc | 8 ++-- tests/test-Sockets.cc | 16 ++++---- tests/test-String.cc | 52 ++++++++++++------------- tests/test-Tasks.cc | 14 +++---- tests/test-Threads.cc | 3 -- 35 files changed, 540 insertions(+), 387 deletions(-) create mode 100644 includes/AtStartExit.h diff --git a/includes/AtStartExit.h b/includes/AtStartExit.h new file mode 100644 index 0000000..9b55d93 --- /dev/null +++ b/includes/AtStartExit.h @@ -0,0 +1,27 @@ +#pragma once + +namespace Balau { + +class AtStart { + protected: + AtStart(int priority = 0); + virtual void doStart() = 0; + private: + const int m_priority; + AtStart * m_next; + static AtStart * s_head; + friend class Main; +}; + +class AtExit { + protected: + AtExit(int priority = 0); + virtual void doExit() = 0; + private: + const int m_priority; + AtExit * m_next; + static AtExit * s_head; + friend class Main; +}; + +}; diff --git a/includes/BString.h b/includes/BString.h index d8487d0..29f3d22 100644 --- a/includes/BString.h +++ b/includes/BString.h @@ -26,12 +26,12 @@ class String : private std::string { String(const String & s) : std::string(s) { } String(const std::string & s) : std::string(s) { } - String & set(const char * fmt, va_list); - String & set(const char * fmt, ...) { va_list ap; va_start(ap, fmt); set(fmt, ap); va_end(ap); return *this; } + String & set(const char * fmt, va_list) __attribute__((format(printf, 2, 0))); + String & set(const char * fmt, ...) __attribute__((format(printf, 2, 3))) { va_list ap; va_start(ap, fmt); set(fmt, ap); va_end(ap); return *this; } String & set(const String & fmt, ...) { va_list ap; va_start(ap, fmt); set(fmt.to_charp(), ap); va_end(ap); return *this; } int scanf(const char * fmt, va_list ap) const { return ::vsscanf(c_str(), fmt, ap); } - int scanf(const char * fmt, ...) const { va_list ap; va_start(ap, fmt); int r = scanf(fmt, ap); va_end(ap); return r; } + int scanf(const char * fmt, ...) const __attribute__((format(scanf, 2, 3))) { va_list ap; va_start(ap, fmt); int r = scanf(fmt, ap); va_end(ap); return r; } int scanf(const String & fmt, ...) const { va_list ap; va_start(ap, fmt); int r = scanf(fmt.to_charp(), ap); va_end(ap); return r; } const char * to_charp(size_t begin = 0) const { return c_str() + begin; } diff --git a/includes/Exceptions.h b/includes/Exceptions.h index c397265..1f65b12 100644 --- a/includes/Exceptions.h +++ b/includes/Exceptions.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -9,11 +10,12 @@ namespace Balau { class GeneralException { public: - GeneralException(const char * msg) : m_msg(::strdup(msg)) { genTrace(); } - GeneralException(const String & msg) : m_msg(msg.strdup()) { genTrace(); } - GeneralException(const GeneralException & e) : m_msg(strdup(e.m_msg)), m_trace(e.m_trace) { } + GeneralException(const char * msg, const char * details = NULL) : m_msg(::strdup(msg)) { setDetails(details); genTrace(); } + GeneralException(const String & msg, const char * details = NULL) : m_msg(msg.strdup()) { setDetails(details); genTrace(); } + GeneralException(const GeneralException & e) : m_msg(strdup(e.m_msg)), m_trace(e.m_trace) { setDetails(e.m_details); } ~GeneralException() { if (m_msg) free(m_msg); } const char * getMsg() const { return m_msg; } + const char * getDetails() const { return m_details; } const std::vector getTrace() const { return m_trace; } protected: @@ -23,37 +25,78 @@ class GeneralException { private: char * m_msg; + char * m_details; std::vector m_trace; + + void setDetails(const char * details) { + if (details) + m_details = ::strdup(details); + else + m_details = NULL; + } +}; + +class RessourceException : public GeneralException { + public: + RessourceException(const String & msg, const char * details) : GeneralException(msg, details) { } }; -static inline void * malloc(size_t size) throw (GeneralException) { +void ExitHelper(const String & msg, const char * fmt = NULL, ...) __attribute__((format(printf, 2, 3))); + +static inline void * malloc(size_t size) { void * r = ::malloc(size); if (!r && size) - throw GeneralException("Failed to allocate memory."); + ExitHelper("Failed to allocate memory", "%li bytes", size); return r; } -static inline void * calloc(size_t count, size_t size) throw (GeneralException) { +static inline void * calloc(size_t count, size_t size) { void * r = ::calloc(count, size); if (!r && ((count * size) != 0)) - throw GeneralException("Failed to allocate memory."); + ExitHelper("Failed to allocate memory", "%li * %li = %li bytes", count, size, count * size); return r; } -static inline void * realloc(void * previous, size_t size) throw (GeneralException) { +static inline void * realloc(void * previous, size_t size) { void * r = ::realloc(previous, size); if (!r && size) - throw GeneralException("Failed to allocate memory."); + ExitHelper("Failed to re-allocate memory", "%li bytes", size); return r; } -static inline void AssertHelper(const String & msg) throw(GeneralException) { throw GeneralException(msg); } +static inline void AssertHelperInner(const String & msg, const char * details = NULL) throw (GeneralException) { + throw GeneralException(msg, details); +} + +static inline void AssertHelper(const String & msg, const char * fmt = NULL, ...) __attribute__((format(printf, 2, 3))); + +static inline void AssertHelper(const String & msg, const char * fmt, ...) { + if (fmt) { + String details; + va_list ap; + va_start(ap, fmt); + details.set(fmt, ap); + va_end(ap); + AssertHelperInner(msg, details.to_charp()); + } else { + AssertHelperInner(msg); + } +} + +class TestException : public GeneralException { + public: + TestException(const String & msg) : GeneralException(msg) { } +}; + +static inline void TestHelper(const String & msg) throw (TestException) { + throw TestException(msg); +} class ClassName { public: @@ -72,8 +115,29 @@ ClassName::ClassName(T * ptr) { }; -#define Assert(c) if (!(c)) { \ +#define Failure(msg) Balau::AssertHelper(msg); +#define FailureDetails(msg, ...) Balau::AssertHelper(msg, __VA_ARGS__); + +#define IAssert(c, ...) if (!__builtin_expect(!!(c), 0)) { \ + Balau::String msg; \ + msg.set("Internal Assertion " #c " failed at %s:%i", __FILE__, __LINE__); \ + Balau::AssertHelper(msg, __VA_ARGS__); \ +} + +#define AAssert(c, ...) if (!__builtin_expect(!!(c), 0)) { \ + Balau::String msg; \ + msg.set("API Assertion " #c " failed at %s:%i", __FILE__, __LINE__); \ + Balau::AssertHelper(msg, __VA_ARGS__); \ +} + +#define RAssert(c, ...) if (!__builtin_expect(!!(c), 0)) { \ + Balau::String msg; \ + msg.set("Ressource Assertion " #c " failed at %s:%i", __FILE__, __LINE__); \ + Balau::ExitHelper(msg, __VA_ARGS__); \ +} + +#define TAssert(c) if (!__builtin_expect(!!(c), 0)) { \ Balau::String msg; \ - msg.set("Assertion " #c " failed at %s:%i", __FILE__, __LINE__); \ - Balau::AssertHelper(msg); \ + msg.set("UnitTest Assert " #c " failed at %s:%i", __FILE__, __LINE__); \ + Balau::TestHelper(msg); \ } diff --git a/includes/Handle.h b/includes/Handle.h index cc66a22..e3ff356 100644 --- a/includes/Handle.h +++ b/includes/Handle.h @@ -29,7 +29,7 @@ class BaseEvent; class Handle { public: - virtual ~Handle() { Assert(m_refCount == 0); } + virtual ~Handle() { AAssert(m_refCount == 0, "Do not use handles directly; warp them in IO<>"); } virtual void close() throw (GeneralException) = 0; virtual bool isClosed() = 0; virtual bool isEOF() = 0; @@ -107,7 +107,12 @@ class IO : public IOBase { template bool isA() { return !!dynamic_cast(m_h); } IO & operator=(const IO & io) { if (m_h) m_h->delRef(); setHandle(io.m_h); return *this; } - T * operator->() { Assert(m_h); T * r = dynamic_cast(m_h); Assert(r); return r; } + T * operator->() { + AAssert(m_h, "Can't use %s->() with a null Handle", ClassName(this).c_str()); + T * r = dynamic_cast(m_h); + AAssert(r, "%s->() used with an incompatible Handle type", ClassName(this).c_str()); + return r; + } bool isNull() { return dynamic_cast(m_h); } }; @@ -129,7 +134,7 @@ class SeekableHandle : public Handle { class ReadOnly : public Handle { public: - ReadOnly(IO & io) : m_io(io) { Assert(m_io->canRead()); } + ReadOnly(IO & io) : m_io(io) { AAssert(m_io->canRead(), "You need to use ReadOnly with a Handle that can at least read"); } virtual void close() throw (GeneralException) { m_io->close(); } virtual bool isClosed() { return m_io->isClosed(); } virtual bool isEOF() { return m_io->isEOF(); } @@ -151,7 +156,7 @@ class ReadOnly : public Handle { class WriteOnly : public Handle { public: - WriteOnly(IO & io) : m_io(io) { Assert(m_io->canWrite()); } + WriteOnly(IO & io) : m_io(io) { AAssert(m_io->canWrite(), "You need to use WriteOnly with a Handle that can at least write"); } virtual void close() throw (GeneralException) { m_io->close(); } virtual bool isClosed() { return m_io->isClosed(); } virtual bool isEOF() { return m_io->isEOF(); } diff --git a/includes/HttpServer.h b/includes/HttpServer.h index 6c97799..9885d50 100644 --- a/includes/HttpServer.h +++ b/includes/HttpServer.h @@ -21,7 +21,7 @@ class HttpServer { class Action { public: Action(const Regex & regex, const Regex & host = Regexes::any) : m_regex(regex), m_host(host), m_refCount(0) { } - ~Action() { Assert(m_refCount == 0); } + ~Action() { AAssert(m_refCount == 0, "Don't delete an Action directl"); } struct ActionMatch { Regex::Captures uri, host; }; @@ -39,8 +39,8 @@ class HttpServer { ~HttpServer() { if (!m_started) stop(); } void start(); void stop(); - void setPort(int port) { Assert(!m_started); m_port = port; } - void setLocal(const char * local) { Assert(!m_started); m_local = local; } + void setPort(int port) { AAssert(!m_started, "You can't set the HTTP port once the server has started"); m_port = port; } + void setLocal(const char * local) { AAssert(!m_started, "You can't set the HTTP IP once the server has started"); m_local = local; } void registerAction(Action * action); void flushAllActions(); struct ActionFound { diff --git a/includes/Main.h b/includes/Main.h index 1c902ec..a890525 100644 --- a/includes/Main.h +++ b/includes/Main.h @@ -1,31 +1,10 @@ #pragma once #include +#include namespace Balau { -class AtStart { - protected: - AtStart(int priority = 0); - virtual void doStart() = 0; - private: - const int m_priority; - AtStart * m_next; - static AtStart * s_head; - friend class Main; -}; - -class AtExit { - protected: - AtExit(int priority = 0); - virtual void doExit() = 0; - private: - const int m_priority; - AtExit * m_next; - static AtExit * s_head; - friend class Main; -}; - class Exit : public GeneralException { public: Exit(int code = -1) : GeneralException(), m_code(code) { String s; s.set("Application exitting with code = %i", code); setMsg(s.strdup()); } @@ -34,19 +13,11 @@ class Exit : public GeneralException { int m_code; }; -}; - -#include -#include -#include - -namespace Balau { - class MainTask : public Task { public: MainTask() : m_stopTaskManOnExit(true) { } - virtual ~MainTask() { if (m_stopTaskManOnExit) TaskMan::stop(); } - virtual const char * getName() { return "Main Task"; } + virtual ~MainTask(); + virtual const char * getName(); virtual void Do(); void stopTaskManOnExit(bool v) { m_stopTaskManOnExit = v; } private: @@ -62,50 +33,10 @@ class Main { STOPPING, STOPPED, }; - Main() : m_status(UNKNOWN) { Assert(s_application == 0); s_application = this; } - static Status status() { return s_application->m_status; } - int 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()); - TaskMan::getDefaultTaskMan()->mainLoop(); - m_status = STOPPING; - } - catch (Exit e) { - m_status = STOPPING; - r = e.getCode(); - } - catch (GeneralException e) { - m_status = STOPPING; - Printer::log(M_ERROR | M_ALERT, "The application caused an exception: %s", e.getMsg()); - 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; - } + Main() : m_status(UNKNOWN) { IAssert(s_application == NULL, "There can't be two main apps"); s_application = this; } + static Status getStatus() { return s_application->m_status; } + int bootstrap(int _argc, char ** _argv); + static bool hasMain() { return s_application; } protected: int argc; char ** argv; @@ -115,19 +46,4 @@ class Main { static Main * s_application; }; -#define BALAU_STARTUP \ -\ -class Application : public Balau::Main { \ - public: \ - virtual int startup() throw (Balau::GeneralException); \ -}; \ -\ -extern "C" { \ - int main(int argc, char ** argv) { \ - setlocale(LC_ALL, ""); \ - Balau::Main mainClass; \ - return mainClass.bootstrap(argc, argv); \ - } \ -} - }; diff --git a/includes/Printer.h b/includes/Printer.h index e321557..b4001f1 100644 --- a/includes/Printer.h +++ b/includes/Printer.h @@ -56,14 +56,14 @@ class Printer { static Printer * getPrinter(); static void log(uint32_t level, const String & fmt, ...) { va_list ap; va_start(ap, fmt); vlog(level, fmt.to_charp(), ap); va_end(ap); } - static void log(uint32_t level, const char * fmt, ...) { va_list ap; va_start(ap, fmt); vlog(level, fmt, ap); va_end(ap); } - static void vlog(uint32_t level, const char * fmt, va_list ap) { getPrinter()->_log(level, fmt, ap); } + static void log(uint32_t level, const char * fmt, ...) __attribute__((format(printf, 2, 3))) { va_list ap; va_start(ap, fmt); vlog(level, fmt, ap); va_end(ap); } + static void vlog(uint32_t level, const char * fmt, va_list ap) __attribute__((format(printf, 2, 0))) { getPrinter()->_log(level, fmt, ap); } static void print(const String & fmt, ...) { va_list ap; va_start(ap, fmt); vprint(fmt.to_charp(), ap); va_end(ap); } - static void print(const char * fmt, ...) { va_list ap; va_start(ap, fmt); vprint(fmt, ap); va_end(ap); } - static void vprint(const char * fmt, va_list ap) { getPrinter()->_print(fmt, ap); } + static void print(const char * fmt, ...) __attribute__((format(printf, 1, 2))) { va_list ap; va_start(ap, fmt); vprint(fmt, ap); va_end(ap); } + static void vprint(const char * fmt, va_list ap) __attribute__((format(printf, 1, 0))) { getPrinter()->_print(fmt, ap); } #ifdef DEBUG - static void elog(uint32_t engine, const char * fmt, ...) { va_list ap; va_start(ap, fmt); getPrinter()->_log(M_ENGINE_DEBUG, fmt, ap); } + static void elog(uint32_t engine, const char * fmt, ...) __attribute__((format(printf, 2, 3))) { va_list ap; va_start(ap, fmt); getPrinter()->_log(M_ENGINE_DEBUG, fmt, ap); } #else static void elog(uint32_t engine, const char * fmt, ...) { } #endif diff --git a/includes/SimpleMustache.h b/includes/SimpleMustache.h index b16f683..2bb0cb1 100644 --- a/includes/SimpleMustache.h +++ b/includes/SimpleMustache.h @@ -57,8 +57,8 @@ class SimpleMustache { LAMBDA, } m_type; Context(ContextType type) : m_type(type), m_root(false) { } - Context(Context & c) { Assert(false); } - Context & operator=(Context & c) { Assert(false); return *this; } + Context(Context & c) { Failure("You can't copy a Context; use references"); } + Context & operator=(Context & c) { Failure("You can't assign a Context; use references"); return *this; } String m_str; bool m_bool; typedef std::map SubContext; @@ -82,9 +82,9 @@ class SimpleMustache { } void setTemplate(const char * str, ssize_t s = -1) { setTemplate((const uint8_t *) str, s); } void setTemplate(const String & str) { setTemplate((const uint8_t *) str.to_charp(), str.strlen()); } - void render(IO h, Context * ctx) { Assert(ctx); render_r(h, ctx, "", m_fragments.begin(), false, -1); } + void render(IO h, Context * ctx) { AAssert(ctx, "Please pass on a context to render"); render_r(h, ctx, "", m_fragments.begin(), false, -1); } void empty() { while (!m_fragments.empty()) { delete m_fragments.front(); m_fragments.pop_front(); } } - void checkTemplate() { Fragments::iterator end = checkTemplate_r(m_fragments.begin()); Assert(end == m_fragments.end()); } + void checkTemplate() { Fragments::iterator end = checkTemplate_r(m_fragments.begin()); AAssert(end == m_fragments.end(), "The template wasn't fully checked; possibly mismatched sections"); } ~SimpleMustache() { empty(); } private: struct Fragment { diff --git a/includes/Socket.h b/includes/Socket.h index a19b1e2..77e1165 100644 --- a/includes/Socket.h +++ b/includes/Socket.h @@ -29,6 +29,8 @@ class Socket : public Handle { bool setLocal(const char * hostname = NULL, int port = 0); bool connect(const char * hostname, int port); + bool gotR() { return m_evtR->gotSignal(); } + bool gotW() { return m_evtW->gotSignal(); } IO accept() throw (GeneralException); bool listen(); private: diff --git a/includes/Task.h b/includes/Task.h index 2e52747..03233f8 100644 --- a/includes/Task.h +++ b/includes/Task.h @@ -38,9 +38,20 @@ class BaseEvent { virtual ~BaseEvent() { if (m_cb) delete m_cb; } bool gotSignal() { return m_signal; } void doSignal(); - void reset() { Assert(m_task != NULL); m_signal = false; gotOwner(m_task); } - Task * taskWaiting() { Assert(m_task); return m_task; } - void registerOwner(Task * task) { if (m_task == task) return; Assert(m_task == NULL); m_task = task; gotOwner(task); } + void reset() { + // could be potentially changed into a simple return + AAssert(m_task != NULL, "Can't reset an event that doesn't have a task"); + m_signal = false; + gotOwner(m_task); + } + Task * taskWaiting() { AAssert(m_task, "No task is waiting for that event"); return m_task; } + void registerOwner(Task * task) { + if (m_task == task) + return; + AAssert(m_task == NULL, "Can't register an event for another task"); + m_task = task; + gotOwner(task); + } protected: virtual void gotOwner(Task * task) { } private: diff --git a/includes/TaskMan.h b/includes/TaskMan.h index 1e7a2f1..6a50491 100644 --- a/includes/TaskMan.h +++ b/includes/TaskMan.h @@ -27,13 +27,14 @@ class TaskMan { public: TaskMan(); ~TaskMan(); - void mainLoop(); + int mainLoop(); static TaskMan * getDefaultTaskMan(); struct ev_loop * getLoop() { return m_loop; } void signalTask(Task * t); - static void stop(); - void stopMe() { m_stopped = true; } + static void stop(int code); + void stopMe(int code) { m_stopped = true; m_stopCode = code; } static Thread * createThreadedTaskMan(); + bool stopped() { return m_stopped; } private: static void registerTask(Task * t, Task * stick); void * getStack(); @@ -58,9 +59,10 @@ class TaskMan { ev::async m_evt; std::queue m_stacks; int m_nStacks; + int m_stopCode; }; template -T * createTask(T * t, Task * stick) { TaskMan::registerTask(t, stick); Assert(dynamic_cast(t)); return t; } +T * createTask(T * t, Task * stick) { TaskMan::registerTask(t, stick); return t; } }; diff --git a/includes/Threads.h b/includes/Threads.h index ca60627..bc2670d 100644 --- a/includes/Threads.h +++ b/includes/Threads.h @@ -1,5 +1,6 @@ #pragma once +#include #include namespace Balau { @@ -21,17 +22,19 @@ class Lock { class ThreadHelper; -class Thread { +class Thread : public AtExit { public: virtual ~Thread(); void threadStart(); void * join(); protected: - Thread() : m_joined(false) { } + Thread(bool registerAtExit = false) : AtExit(registerAtExit ? 1 : -1), m_joined(false) { } virtual void * proc() = 0; + virtual void threadExit(); private: pthread_t m_thread; - bool m_joined; + volatile bool m_joined; + virtual void doExit() { join(); } friend class ThreadHelper; }; 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() { } diff --git a/tests/test-Handles.cc b/tests/test-Handles.cc index f185b60..c872e9f 100644 --- a/tests/test-Handles.cc +++ b/tests/test-Handles.cc @@ -14,8 +14,6 @@ void ctime_r(const time_t * t, char * str) { } #endif -BALAU_STARTUP; - using namespace Balau; void MainTask::Do() { @@ -28,7 +26,7 @@ void MainTask::Do() { catch (ENoEnt e) { failed = true; } - Assert(failed); + TAssert(failed); IO i(new Input("tests/rtest.txt")); Printer::log(M_STATUS, "Opened file %s:", i->getName()); Printer::log(M_STATUS, " - size = %lli", i->getSize()); @@ -39,71 +37,71 @@ void MainTask::Do() { char * nl = strrchr(mtimestr, '\n'); if (nl) *nl = 0; - Printer::log(M_STATUS, " - mtime = %i (%s)", mtime, mtimestr); + Printer::log(M_STATUS, " - mtime = %li (%s)", mtime, mtimestr); off_t s = i->rtell(); - Assert(s == 0); + TAssert(s == 0); i->rseek(0, SEEK_END); s = i->rtell(); - Assert(s == i->getSize()); + TAssert(s == i->getSize()); i->rseek(0, SEEK_SET); char * buf1 = (char *) malloc(i->getSize()); ssize_t r = i->read(buf1, s + 15); - Printer::log(M_STATUS, "Read %i bytes (instead of %i)", r, s + 15); - Assert(i->isEOF()) + Printer::log(M_STATUS, "Read %li bytes (instead of %lli)", r, s + 15); + TAssert(i->isEOF()) char * buf2 = (char *) malloc(i->getSize()); i->rseek(0, SEEK_SET); - Assert(!i->isEOF()); - Assert(i->rtell() == 0); + TAssert(!i->isEOF()); + TAssert(i->rtell() == 0); r = i->read(buf2, 5); - Assert(r == 5); - Assert(i->rtell() == 5); + TAssert(r == 5); + TAssert(i->rtell() == 5); r = i->read(buf2 + 5, s - 5); - Assert(r == (s - 5)); - Assert(memcmp(buf1, buf2, s) == 0); + TAssert(r == (s - 5)); + TAssert(memcmp(buf1, buf2, s) == 0); IO o(new Output("tests/out.txt")); s = o->wtell(); - Assert(s == 0); + TAssert(s == 0); s = o->getSize(); - Assert(s == 0); + TAssert(s == 0); o->writeString("foo\n"); IO b(new Buffer()); s = b->rtell(); - Assert(s == 0); + TAssert(s == 0); s = b->wtell(); - Assert(s == 0); + TAssert(s == 0); b->writeString("foo\n"); s = b->rtell(); - Assert(s == 0); + TAssert(s == 0); s = b->wtell(); - Assert(s == 4); + TAssert(s == 4); b->writeString("bar\r\n"); s = b->rtell(); - Assert(s == 0); + TAssert(s == 0); s = b->wtell(); - Assert(s == 9); + TAssert(s == 9); b->writeString("eof"); s = b->rtell(); - Assert(s == 0); + TAssert(s == 0); s = b->wtell(); - Assert(s == 12); + TAssert(s == 12); IO strm(new BStream(b)); String str; str = strm->readString(); - Assert(str == "foo"); + TAssert(str == "foo"); str = strm->readString(); - Assert(str == "bar"); + TAssert(str == "bar"); str = strm->readString(); - Assert(str == "eof"); + TAssert(str == "eof"); s = b->rtell(); - Assert(s == 12); - Assert(b->isEOF()); + TAssert(s == 12); + TAssert(b->isEOF()); Printer::log(M_STATUS, "Test::Handles passed."); } diff --git a/tests/test-Http.cc b/tests/test-Http.cc index 15ef7de..e6ba38d 100644 --- a/tests/test-Http.cc +++ b/tests/test-Http.cc @@ -1,7 +1,6 @@ #include #include - -BALAU_STARTUP; +#include #define DAEMON_NAME "Balau/1.0" @@ -48,13 +47,15 @@ bool TestFailure::Do(HttpServer * server, Http::Request & req, HttpServer::Actio throw GeneralException("Test..."); } +#define NTHREADS 4 + void MainTask::Do() { Printer::enable(M_DEBUG); Printer::log(M_STATUS, "Test::Http running."); - Thread * tms[4]; + Thread * tms[NTHREADS]; - for (int i = 0; i < 4; i++) + for (int i = 0; i < NTHREADS; i++) tms[i] = TaskMan::createThreadedTaskMan(); HttpServer * s = new HttpServer(); @@ -70,7 +71,7 @@ void MainTask::Do() { s->stop(); - for (int i = 0; i < 4; i++) + for (int i = 0; i < NTHREADS; i++) tms[i]->join(); Printer::log(M_STATUS, "Test::Http passed."); diff --git a/tests/test-Lua.cc b/tests/test-Lua.cc index 86baffb..8ba3785 100644 --- a/tests/test-Lua.cc +++ b/tests/test-Lua.cc @@ -1,8 +1,6 @@ #include #include -BALAU_STARTUP; - using namespace Balau; void MainTask::Do() { @@ -11,7 +9,7 @@ void MainTask::Do() { Lua L; // yeah, they really should be the same thing. - Assert(sizeof(L) == sizeof(lua_State *)); + TAssert(sizeof(L) == sizeof(lua_State *)); L.open_base(); L.open_table(); @@ -21,13 +19,13 @@ void MainTask::Do() { L.open_bit(); L.open_jit(); - Assert(L.gettop() == 0); + TAssert(L.gettop() == 0); L.load("return 42"); - Assert(L.gettop() == 1); + TAssert(L.gettop() == 1); int r = L.tonumber(); - Assert(r == 42); + TAssert(r == 42); L.pop(); - Assert(L.gettop() == 0); + TAssert(L.gettop() == 0); Printer::log(M_STATUS, "Test::Lua passed."); } diff --git a/tests/test-Regex.cc b/tests/test-Regex.cc index b656445..082afd2 100644 --- a/tests/test-Regex.cc +++ b/tests/test-Regex.cc @@ -1,8 +1,6 @@ #include #include -BALAU_STARTUP; - using namespace Balau; void MainTask::Do() { @@ -11,11 +9,11 @@ void MainTask::Do() { Regex reg("http://([^/ ]+)/([^? ]+)(\\?([^ ]+))?"); Regex::Captures c = reg.match("some url: http://www.test.com/uri?var1=val1 that should match"); - Assert(c[0] == "http://www.test.com/uri?var1=val1"); - Assert(c[1] == "www.test.com"); - Assert(c[2] == "uri"); - Assert(c[3] == "?var1=val1"); - Assert(c[4] == "var1=val1"); + TAssert(c[0] == "http://www.test.com/uri?var1=val1"); + TAssert(c[1] == "www.test.com"); + TAssert(c[2] == "uri"); + TAssert(c[3] == "?var1=val1"); + TAssert(c[4] == "var1=val1"); Printer::log(M_STATUS, "Test::Regex passed"); } diff --git a/tests/test-Sanity.cc b/tests/test-Sanity.cc index 9ed9b4e..22120ab 100644 --- a/tests/test-Sanity.cc +++ b/tests/test-Sanity.cc @@ -1,15 +1,13 @@ #include -BALAU_STARTUP; - using namespace Balau; void MainTask::Do() { Printer::log(M_STATUS, "Test::Sanity running."); - Assert(sizeof(off_t) == 8); - Assert(sizeof(size_t) == 4); - Assert(sizeof(time_t) == 4); + TAssert(sizeof(off_t) == 8); + TAssert(sizeof(size_t) == 4); + TAssert(sizeof(time_t) == 4); Printer::log(M_STATUS, "Test::Sanity passed."); } diff --git a/tests/test-Sockets.cc b/tests/test-Sockets.cc index 87d557b..073548a 100644 --- a/tests/test-Sockets.cc +++ b/tests/test-Sockets.cc @@ -1,8 +1,6 @@ #include #include -BALAU_STARTUP; - using namespace Balau; class Worker : public Task { @@ -28,11 +26,11 @@ void Worker::Do() { int r; r = m_io->read(&x, 1); - Assert(x == 'x'); - Assert(r == 1); + TAssert(x == 'x'); + TAssert(r == 1); y = 'y'; r = m_io->write(&y, 1); - Assert(r == 1); + TAssert(r == 1); } Listener * listener; @@ -48,14 +46,14 @@ class Client : public Task { char x, y; IO s(new Socket()); bool c = s->connect("localhost", 1234); - Assert(c); + TAssert(c); x = 'x'; int r; r = s->write(&x, 1); - Assert(r == 1); + TAssert(r == 1); r = s->read(&y, 1); - Assert(y == 'y'); - Assert(r == 1); + TAssert(y == 'y'); + TAssert(r == 1); listener->stop(); } }; diff --git a/tests/test-String.cc b/tests/test-String.cc index 1f7efc0..9637911 100644 --- a/tests/test-String.cc +++ b/tests/test-String.cc @@ -1,54 +1,52 @@ #include #include -BALAU_STARTUP; - using namespace Balau; void MainTask::Do() { Printer::log(M_STATUS, "Test::String running."); String x = "foobar"; - Assert(x == "foobar"); - Assert(x != "barfoo"); + TAssert(x == "foobar"); + TAssert(x != "barfoo"); String y = "xyz"; - x = "abcdef"; Assert(x < y); Assert(x + y == "abcdefxyz"); - x.set("x:%i", 42); Assert(x == "x:42"); + x = "abcdef"; TAssert(x < y); TAssert(x + y == "abcdefxyz"); + x.set("x:%i", 42); TAssert(x == "x:42"); - x = "foobar"; Assert(x == "foobar"); + x = "foobar"; TAssert(x == "foobar"); - y = x.extract(3); Assert(y == "bar"); - y = x.extract(1, 3); Assert(y == "oob"); + y = x.extract(3); TAssert(y == "bar"); + y = x.extract(1, 3); TAssert(y == "oob"); y = " foo bar "; - x = y; x.do_ltrim(); Assert(x == "foo bar "); - x = y; x.do_rtrim(); Assert(x == " foo bar"); - x = y; x.do_trim(); Assert(x == "foo bar"); + x = y; x.do_ltrim(); TAssert(x == "foo bar "); + x = y; x.do_rtrim(); TAssert(x == " foo bar"); + x = y; x.do_trim(); TAssert(x == "foo bar"); y = " "; - x = y; x.do_ltrim(); Assert(x == ""); - x = y; x.do_rtrim(); Assert(x == ""); - x = y; x.do_trim(); Assert(x == ""); + x = y; x.do_ltrim(); TAssert(x == ""); + x = y; x.do_rtrim(); TAssert(x == ""); + x = y; x.do_trim(); TAssert(x == ""); - x = "42"; Assert(x.to_int() == 42); - x = "0x42"; Assert(x.to_int() == 0x42); - x = "42"; Assert(x.to_int(16) == 0x42); - x = "4.2"; Assert(x.to_double() == 4.2); + x = "42"; TAssert(x.to_int() == 42); + x = "0x42"; TAssert(x.to_int() == 0x42); + x = "42"; TAssert(x.to_int(16) == 0x42); + x = "4.2"; TAssert(x.to_double() == 4.2); x = "foobar"; - Assert(x[0] == 'f'); - Assert(x[5] == 'r'); - Assert(x.strlen() == 6); - Assert(x.strchr('o') == 1); - Assert(x.strrchr('o') == 2); - Assert(x.strchrcnt('o') == 2); - Assert(x.strstr("bar") == 3); + TAssert(x[0] == 'f'); + TAssert(x[5] == 'r'); + TAssert(x.strlen() == 6); + TAssert(x.strchr('o') == 1); + TAssert(x.strrchr('o') == 2); + TAssert(x.strchrcnt('o') == 2); + TAssert(x.strstr("bar") == 3); x = "\xc3\xa9"; y = x.iconv("UTF-8", "Latin1"); - Assert(((unsigned char) y[0]) == 0xe9); + TAssert(((unsigned char) y[0]) == 0xe9); Printer::log(M_STATUS, "Test::String passed."); } diff --git a/tests/test-Tasks.cc b/tests/test-Tasks.cc index 8677fb7..4b26406 100644 --- a/tests/test-Tasks.cc +++ b/tests/test-Tasks.cc @@ -2,8 +2,6 @@ #include #include -BALAU_STARTUP; - using namespace Balau; class CustomPrinter : public Printer { @@ -25,7 +23,7 @@ class TestTask : public Task { static void yieldingFunction() { Events::Timeout timeout(0.2); Task::yield(&timeout); - Assert(timeout.gotSignal()); + TAssert(timeout.gotSignal()); } void MainTask::Do() { @@ -35,22 +33,22 @@ void MainTask::Do() { Task * testTask = Balau::createTask(new TestTask()); Events::TaskEvent taskEvt(testTask); waitFor(&taskEvt); - Assert(!taskEvt.gotSignal()); + TAssert(!taskEvt.gotSignal()); yield(); - Assert(taskEvt.gotSignal()); + TAssert(taskEvt.gotSignal()); taskEvt.ack(); Events::Timeout timeout(0.1); waitFor(&timeout); - Assert(!timeout.gotSignal()); + TAssert(!timeout.gotSignal()); yield(); - Assert(timeout.gotSignal()); + TAssert(timeout.gotSignal()); timeout.set(0.1); timeout.reset(); waitFor(&timeout); yieldingFunction(); - Assert(timeout.gotSignal()); + TAssert(timeout.gotSignal()); Printer::log(M_STATUS, "Test::Tasks passed."); Printer::log(M_DEBUG, "You shouldn't see that message."); diff --git a/tests/test-Threads.cc b/tests/test-Threads.cc index 1005906..50cc741 100644 --- a/tests/test-Threads.cc +++ b/tests/test-Threads.cc @@ -1,12 +1,9 @@ #include #include -BALAU_STARTUP; - using namespace Balau; class TestThread : public Thread { - private: virtual void * proc(); }; -- cgit v1.2.3