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