summaryrefslogtreecommitdiff
path: root/includes
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 /includes
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.
Diffstat (limited to 'includes')
-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
12 files changed, 163 insertions, 133 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;
};