summaryrefslogtreecommitdiffstats
path: root/src/Core
diff options
context:
space:
mode:
Diffstat (limited to 'src/Core')
-rw-r--r--src/Core/CMakeLists.txt25
-rw-r--r--src/Core/ConfigEntry.cpp64
-rw-r--r--src/Core/ConfigEntry.h96
-rw-r--r--src/Core/ConfigManager.cpp141
-rw-r--r--src/Core/ConfigManager.h69
-rw-r--r--src/Core/Configurable.h47
-rw-r--r--src/Core/Exception.cpp60
-rw-r--r--src/Core/Exception.h65
-rw-r--r--src/Core/Initializable.cpp69
-rw-r--r--src/Core/Initializable.h54
-rw-r--r--src/Core/LogManager.cpp146
-rw-r--r--src/Core/LogManager.h146
-rw-r--r--src/Core/Logger.cpp89
-rw-r--r--src/Core/Logger.h68
-rw-r--r--src/Core/LoggerBase.h79
-rw-r--r--src/Core/RemoteLogger.h42
-rw-r--r--src/Core/Signals.h27
-rw-r--r--src/Core/Signals/Connection.h53
-rw-r--r--src/Core/Signals/GenericSignal.h61
-rw-r--r--src/Core/Signals/Signal0.h46
-rw-r--r--src/Core/Signals/Signal1.h47
-rw-r--r--src/Core/Signals/Signal2.h47
-rw-r--r--src/Core/Signals/SignalBase.h53
-rw-r--r--src/Core/ThreadManager.cpp143
-rw-r--r--src/Core/ThreadManager.h113
-rw-r--r--src/Core/Tokenizer.cpp131
-rw-r--r--src/Core/Tokenizer.h44
27 files changed, 2025 insertions, 0 deletions
diff --git a/src/Core/CMakeLists.txt b/src/Core/CMakeLists.txt
new file mode 100644
index 0000000..30947e3
--- /dev/null
+++ b/src/Core/CMakeLists.txt
@@ -0,0 +1,25 @@
+include_directories(${INCLUDES})
+link_directories(${Boost_LIBRARY_DIRS})
+
+add_library(Core
+ Signals/Connection.h
+ Signals/GenericSignal.h
+ Signals/Signal0.h
+ Signals/Signal1.h
+ Signals/Signal2.h
+ Signals/SignalBase.h
+
+ ConfigEntry.cpp ConfigEntry.h
+ ConfigManager.cpp ConfigManager.h
+ Configurable.h
+ Exception.cpp Exception.h
+ Initializable.cpp Initializable.h
+ Logger.cpp Logger.h
+ LoggerBase.h
+ LogManager.cpp LogManager.h
+ RemoteLogger.h
+ Signals.h
+ ThreadManager.cpp ThreadManager.h
+ Tokenizer.cpp Tokenizer.h
+)
+target_link_libraries(Core ${Boost_LIBRARIES})
diff --git a/src/Core/ConfigEntry.cpp b/src/Core/ConfigEntry.cpp
new file mode 100644
index 0000000..d85235a
--- /dev/null
+++ b/src/Core/ConfigEntry.cpp
@@ -0,0 +1,64 @@
+/*
+ * ConfigEntry.cpp
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ConfigEntry.h"
+
+namespace Mad {
+namespace Core {
+
+ConfigEntry::String& ConfigEntry::Entry::operator[] (size_t i) {
+ try {
+ return value.at(i);
+ }
+ catch(std::out_of_range &e) {
+ zero = String();
+ return zero;
+ }
+}
+
+const ConfigEntry::String& ConfigEntry::Entry::operator[] (size_t i) const {
+ try {
+ return value.at(i);
+ }
+ catch(std::out_of_range &e) {
+ return constZero;
+ }
+}
+
+ConfigEntry::Entry& ConfigEntry::operator[] (size_t i) {
+ try {
+ return entries.at(i);
+ }
+ catch(std::out_of_range &e) {
+ zero = Entry();
+ return zero;
+ }
+}
+
+const ConfigEntry::Entry& ConfigEntry::operator[] (size_t i) const {
+ try {
+ return entries.at(i);
+ }
+ catch(std::out_of_range &e) {
+ return constZero;
+ }
+}
+
+}
+}
diff --git a/src/Core/ConfigEntry.h b/src/Core/ConfigEntry.h
new file mode 100644
index 0000000..42f8f91
--- /dev/null
+++ b/src/Core/ConfigEntry.h
@@ -0,0 +1,96 @@
+/*
+ * ConfigEntry.h
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_CONFIGENTRY_H_
+#define MAD_CORE_CONFIGENTRY_H_
+
+#include <stdexcept>
+#include <string>
+#include <string.h>
+#include <vector>
+
+namespace Mad {
+namespace Core {
+
+class ConfigEntry {
+ public:
+ class String : public std::string {
+ public:
+ String() {}
+ String(const std::string &str) : std::string(str) {}
+
+ bool matches(const std::string &str) const {
+ return (strcasecmp(c_str(), str.c_str()) == 0);
+ }
+ };
+
+ class Entry {
+ private:
+ String key;
+ std::vector<String> value;
+
+ String zero, constZero;
+
+ public:
+ Entry() {}
+ Entry(const std::vector<std::string> &args) {
+ if(args.empty())
+ return;
+
+ key = args.front();
+
+ value.assign(args.begin()+1, args.end());
+ }
+
+ bool empty() const {
+ return key.empty();
+ }
+
+ String &getKey() {return key;}
+ const String &getKey() const {return key;}
+
+ size_t getSize() const {return value.size();}
+
+ String& operator[] (size_t i);
+ const String& operator[] (size_t i) const;
+ };
+
+ private:
+ std::vector<Entry> entries;
+ Entry zero, constZero;
+
+ public:
+ size_t getSize() const {return entries.size();}
+
+ Entry& operator[] (size_t i);
+ const Entry& operator[] (size_t i) const;
+
+ void push(const Entry &entry) {
+ entries.push_back(entry);
+ }
+
+ void pop() {
+ entries.pop_back();
+ }
+};
+
+}
+}
+
+#endif /* MAD_CORE_CONFIGENTRY_H_ */
diff --git a/src/Core/ConfigManager.cpp b/src/Core/ConfigManager.cpp
new file mode 100644
index 0000000..8b1ebd4
--- /dev/null
+++ b/src/Core/ConfigManager.cpp
@@ -0,0 +1,141 @@
+/*
+ * ConfigManager.cpp
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ConfigManager.h"
+#include "ConfigEntry.h"
+#include "Configurable.h"
+#include "Logger.h"
+#include "LogManager.h"
+#include "Tokenizer.h"
+
+#include <fstream>
+#include <stdexcept>
+
+namespace Mad {
+namespace Core {
+
+ConfigManager ConfigManager::configManager;
+
+
+bool ConfigManager::Compare::operator() (const Configurable *c1, const Configurable *c2) {
+ if(c1->getPriority() != c2->getPriority())
+ return c1->getPriority() > c2->getPriority();
+ else
+ return c1 < c2;
+}
+
+
+void ConfigManager::handleConfigEntry(const ConfigEntry &entry) {
+ bool handled = false;
+
+ for(std::set<Configurable*>::iterator c = configurables.begin(); c != configurables.end(); ++c) {
+ if((*c)->handleConfigEntry(entry, handled))
+ handled = true;
+ }
+
+ if(!handled)
+ Logger::logf(Logger::WARNING, "Invalid config option '%s'.", entry[entry.getSize()-1].getKey().c_str());
+}
+
+bool ConfigManager::loadFile(const std::string &filename) {
+ if(finished)
+ return false;
+
+ std::ifstream file(filename.c_str());
+ ConfigEntry entry;
+ std::string line, input;
+ char delim;
+ std::vector<std::string> splitLine, lastConfigLine;
+
+ if(!file.good())
+ return false;
+
+ while(!(file.eof() && line.empty() && input.empty())) {
+ while(input.empty() && !file.eof())
+ std::getline(file, input);
+
+ if(input.empty())
+ break;
+
+ size_t pos = input.find_first_of("#{}");
+ if(pos == std::string::npos) {
+ line += input;
+ delim = '\n';
+ input.clear();
+ }
+ else {
+ line += input.substr(0, pos);
+ delim = input[pos];
+ input = input.substr(pos+1);
+ }
+
+ if(!Tokenizer::tokenize(line, splitLine)) {
+ line += delim;
+ continue;
+ }
+
+ if(!splitLine.empty()) {
+ pos = line.find_first_of(" \t");
+
+ entry.push(splitLine);
+ handleConfigEntry(entry);
+ entry.pop();
+
+ lastConfigLine = splitLine;
+ }
+
+ switch(delim) {
+ case '#':
+ input.clear();
+ break;
+ case '{':
+ entry.push(lastConfigLine);
+ break;
+ case '}':
+ entry.pop();
+ }
+
+ line.clear();
+ }
+
+ // TODO Depth check
+
+ return true;
+}
+
+void ConfigManager::finish() {
+ if(finished)
+ return;
+
+ for(std::set<Configurable*>::iterator c = configurables.begin(); c != configurables.end(); ++c)
+ (*c)->configFinished();
+
+ finished = true;
+}
+
+ConfigManager::ConfigManager() : finished(false) {
+ registerConfigurable(LogManager::get());
+}
+
+ConfigManager::~ConfigManager() {
+ unregisterConfigurable(LogManager::get());
+}
+
+}
+}
diff --git a/src/Core/ConfigManager.h b/src/Core/ConfigManager.h
new file mode 100644
index 0000000..2d49a97
--- /dev/null
+++ b/src/Core/ConfigManager.h
@@ -0,0 +1,69 @@
+/*
+ * ConfigManager.h
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_CONFIGMANAGER_H_
+#define MAD_CORE_CONFIGMANAGER_H_
+
+#include <memory>
+#include <set>
+#include <string>
+
+namespace Mad {
+namespace Core {
+
+class ConfigEntry;
+class Configurable;
+
+class ConfigManager {
+ private:
+ struct Compare {
+ bool operator() (const Configurable *c1, const Configurable *c2);
+ };
+
+ static ConfigManager configManager;
+
+ std::set<Configurable*, Compare> configurables;
+ bool finished;
+
+ ConfigManager();
+ ~ConfigManager();
+
+ void handleConfigEntry(const ConfigEntry &entry);
+
+ public:
+ bool loadFile(const std::string &filename);
+ void finish();
+
+ void registerConfigurable(Configurable *c) {
+ configurables.insert(c);
+ }
+
+ void unregisterConfigurable(Configurable *c) {
+ configurables.erase(c);
+ }
+
+ static ConfigManager *get() {
+ return &configManager;
+ }
+};
+
+}
+}
+
+#endif /* MAD_CORE_CONFIGMANAGER_H_ */
diff --git a/src/Core/Configurable.h b/src/Core/Configurable.h
new file mode 100644
index 0000000..db2e4a0
--- /dev/null
+++ b/src/Core/Configurable.h
@@ -0,0 +1,47 @@
+/*
+ * Configurable.h
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_CONFIGURABLE_H_
+#define MAD_CORE_CONFIGURABLE_H_
+
+namespace Mad {
+namespace Core {
+
+class ConfigEntry;
+class ConfigManager;
+
+class Configurable {
+ public:
+ virtual ~Configurable() {}
+
+ virtual int getPriority() const {return 0;}
+
+ protected:
+ friend class ConfigManager;
+
+ Configurable() {}
+
+ virtual bool handleConfigEntry(const ConfigEntry&, bool) {return false;}
+ virtual void configFinished() {}
+};
+
+}
+}
+
+#endif /* MAD_CORE_CONFIGURABLE_H_ */
diff --git a/src/Core/Exception.cpp b/src/Core/Exception.cpp
new file mode 100644
index 0000000..fbae6aa
--- /dev/null
+++ b/src/Core/Exception.cpp
@@ -0,0 +1,60 @@
+/*
+ * Exception.cpp
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Exception.h"
+
+#include <cstring>
+
+namespace Mad {
+namespace Core {
+
+std::string Exception::strerror() const {
+ std::string ret;
+
+ if(!where.empty())
+ ret = where + ": ";
+
+ switch(errorCode) {
+ case SUCCESS:
+ return ret + "Success";
+ case UNEXPECTED_PACKET:
+ return ret + "An unexpected packet was received";
+ case INVALID_ACTION:
+ return ret + "The action is invalid";
+ case NOT_AVAILABLE:
+ return ret + "Not available";
+ case NOT_FINISHED:
+ return ret + "Not finished";
+ case NOT_IMPLEMENTED:
+ return ret + "Not implemented";
+ case INTERNAL_ERRNO:
+ return ret + std::strerror(subCode);
+ case INVALID_ADDRESS:
+ return ret + "Invalid address";
+ case ALREADY_IDENTIFIED:
+ return ret + "The host is already identified";
+ case UNKNOWN_DAEMON:
+ return ret + "The daemon is unknown";
+ default:
+ return ret + "Unknown error";
+ }
+}
+
+}
+}
diff --git a/src/Core/Exception.h b/src/Core/Exception.h
new file mode 100644
index 0000000..6c89549
--- /dev/null
+++ b/src/Core/Exception.h
@@ -0,0 +1,65 @@
+/*
+ * Exception.h
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_EXCEPTION_H_
+#define MAD_CORE_EXCEPTION_H_
+
+#include <string>
+
+namespace Mad {
+namespace Core {
+
+class Exception {
+ public:
+ enum ErrorCode {
+ SUCCESS = 0x0000, UNEXPECTED_PACKET = 0x0001, INVALID_ACTION = 0x0002, NOT_AVAILABLE = 0x0003, NOT_FINISHED = 0x0004, NOT_IMPLEMENTED = 0x0005,
+ INTERNAL_ERRNO = 0x0010,
+ INVALID_ADDRESS = 0x0020,
+ ALREADY_IDENTIFIED = 0x0030, UNKNOWN_DAEMON = 0x0031
+ };
+
+ private:
+ std::string where;
+
+ ErrorCode errorCode;
+ long subCode;
+ long subSubCode;
+
+ public:
+ Exception(const std::string &where0, ErrorCode errorCode0 = SUCCESS, long subCode0 = 0, long subSubCode0 = 0)
+ : where(where0), errorCode(errorCode0), subCode(subCode0), subSubCode(subSubCode0) {}
+ Exception(ErrorCode errorCode0 = SUCCESS, long subCode0 = 0, long subSubCode0 = 0) : errorCode(errorCode0), subCode(subCode0), subSubCode(subSubCode0) {}
+ virtual ~Exception() {}
+
+ const std::string& getWhere() const {return where;}
+ ErrorCode getErrorCode() const {return errorCode;}
+ long getSubCode() const {return subCode;}
+ long getSubSubCode() const {return subSubCode;}
+
+ std::string strerror() const;
+
+ operator bool() const {
+ return (errorCode != SUCCESS);
+ }
+};
+
+}
+}
+
+#endif /* MAD_CORE_EXCEPTION_H_ */
diff --git a/src/Core/Initializable.cpp b/src/Core/Initializable.cpp
new file mode 100644
index 0000000..95d527f
--- /dev/null
+++ b/src/Core/Initializable.cpp
@@ -0,0 +1,69 @@
+/*
+ * Initializable.cpp
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Initializable.h"
+
+#include "ConfigManager.h"
+#include "Configurable.h"
+#include "Logger.h"
+
+namespace Mad {
+namespace Core {
+
+std::stack<Initializable*> Initializable::initializedObjects;
+
+void Initializable::init() {
+ if(initialized)
+ return;
+
+ if(initializing) {
+ Logger::log(Logger::CRITICAL, "Fatal initialization error: cyclic dependencies.");
+ std::terminate();
+ }
+
+ initializing = true;
+
+ doInit();
+
+ Configurable *c = dynamic_cast<Configurable*>(this);
+ if(c)
+ ConfigManager::get()->registerConfigurable(c);
+
+ initializing = false;
+ initialized = true;
+ initializedObjects.push(this);
+}
+
+void Initializable::deinit() {
+ while(!initializedObjects.empty()) {
+ Initializable *in = initializedObjects.top();
+
+ Configurable *c = dynamic_cast<Configurable*>(in);
+ if(c)
+ ConfigManager::get()->unregisterConfigurable(c);
+
+ in->doDeinit();
+ in->initialized = false;
+
+ initializedObjects.pop();
+ }
+}
+
+}
+}
diff --git a/src/Core/Initializable.h b/src/Core/Initializable.h
new file mode 100644
index 0000000..e7d329d
--- /dev/null
+++ b/src/Core/Initializable.h
@@ -0,0 +1,54 @@
+/*
+ * Initializable.h
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_INITIALIZABLE_H_
+#define MAD_CORE_INITIALIZABLE_H_
+
+#include <stack>
+
+namespace Mad {
+namespace Core {
+
+class Initializable {
+ private:
+ static std::stack<Initializable*> initializedObjects;
+
+ bool initializing;
+ bool initialized;
+
+ protected:
+ Initializable() : initializing(false), initialized(false) {}
+ virtual void doInit() {}
+ virtual void doDeinit() {}
+
+ public:
+ virtual ~Initializable() {}
+
+ void init();
+
+ bool isInitialized() const {return initialized;}
+ bool isInitializing() const {return initializing;}
+
+ static void deinit();
+};
+
+}
+}
+
+#endif /* MAD_CORE_INITIALIZABLE_H_ */
diff --git a/src/Core/LogManager.cpp b/src/Core/LogManager.cpp
new file mode 100644
index 0000000..bf9767b
--- /dev/null
+++ b/src/Core/LogManager.cpp
@@ -0,0 +1,146 @@
+/*
+ * LogManager.cpp
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "LogManager.h"
+#include "ConfigEntry.h"
+
+#include <iostream>
+
+namespace Mad {
+namespace Core {
+
+LogManager LogManager::logManager;
+
+
+void LogManager::ConsoleLogger::logMessage(MessageCategory category _UNUSED_PARAMETER_, MessageLevel level, time_t timestamp _UNUSED_PARAMETER_, const std::string &message) {
+ if(level != CRITICAL) {// Critical messages are printed to cerr directly, so don't print them a second time
+ cerrLock.lock();
+ std::cerr << message << std::endl;
+ cerrLock.unlock();
+ }
+}
+
+void LogManager::ConsoleLogger::logMessage(MessageCategory category _UNUSED_PARAMETER_, MessageLevel, time_t timestamp _UNUSED_PARAMETER_, const std::string &message, const std::string &messageSource) {
+ cerrLock.lock();
+ std::cerr << message << " from " << messageSource << std::endl;
+ cerrLock.unlock();
+}
+
+void LogManager::ConsoleLogger::logMessageDirect(MessageCategory category _UNUSED_PARAMETER_, MessageLevel level _UNUSED_PARAMETER_, time_t timestamp _UNUSED_PARAMETER_, const std::string &message) {
+ cerrLock.lock();
+ std::cerr << message << std::endl;
+ cerrLock.unlock();
+}
+
+
+bool LogManager::handleConfigEntry(const ConfigEntry &entry, bool handled) {
+ if(handled)
+ return false;
+
+ if(entry[0].getKey().matches("Logger")) {
+ if(entry[0][0].matches("Console")) {
+ if(entry[1].empty()) {
+ registerLogger(static_cast<Logger*>(&consoleLogger));
+ return true;
+ }
+ }
+ else if(entry[1].empty()) {
+ Logger::logf(Logger::WARNING, "Unknown logger '%s'.", entry[0][0].c_str());
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void LogManager::configFinished() {
+ if(loggers.empty())
+ registerLogger(static_cast<Logger*>(&consoleLogger));
+
+ // TODO Debug
+ consoleLogger.Logger::setLevel(LoggerBase::DEBUG);
+
+ queueLock.lock();
+ configured = true;
+ queueLock.unlock();
+ queueCond.notify_one();
+}
+
+void LogManager::log(MessageCategory category, MessageLevel level, time_t timestamp, const std::string &message) {
+ if(level == LoggerBase::CRITICAL)
+ consoleLogger.logMessageDirect(category, level, timestamp, message);
+
+ queueLock.lock();
+ Message m = {category, level, timestamp, message};
+ messageQueue.push(m);
+ queueLock.unlock();
+ queueCond.notify_one();
+}
+
+void LogManager::log(MessageCategory category, MessageLevel level, time_t timestamp, const std::string &message, const std::string &source) {
+ queueLock.lock();
+ RemoteMessage m = {category, level, timestamp, message, source};
+ remoteMessageQueue.push(m);
+ queueLock.unlock();
+ queueCond.notify_one();
+}
+
+void LogManager::loggerThread() {
+ boost::unique_lock<boost::mutex> lock(queueLock);
+
+ running = true;
+
+ while(running) {
+ while(running && ((messageQueue.empty() && messageQueue.empty()) || !configured))
+ queueCond.wait(lock);
+
+ while(!messageQueue.empty()) {
+ Message message = messageQueue.front();
+ messageQueue.pop();
+ lock.unlock();
+
+ loggerLock.lock();
+ for(std::set<Logger*>::iterator logger = loggers.begin(); logger != loggers.end(); ++logger) {
+ if((*logger)->getLevel() >= message.level && (*logger)->isCategorySet(message.category))
+ (*logger)->logMessage(message.category, message.level, message.timestamp, message.message);
+ }
+ loggerLock.unlock();
+
+ lock.lock();
+ }
+
+ while(!remoteMessageQueue.empty()) {
+ RemoteMessage message = remoteMessageQueue.front();
+ remoteMessageQueue.pop();
+ lock.unlock();
+
+ remoteLoggerLock.lock();
+ for(std::set<RemoteLogger*>::iterator logger = remoteLoggers.begin(); logger != remoteLoggers.end(); ++logger) {
+ if((*logger)->getLevel() >= message.level && (*logger)->isCategorySet(message.category))
+ (*logger)->logMessage(message.category, message.level, message.timestamp, message.message, message.source);
+ }
+ remoteLoggerLock.unlock();
+
+ lock.lock();
+ }
+ }
+}
+
+}
+}
diff --git a/src/Core/LogManager.h b/src/Core/LogManager.h
new file mode 100644
index 0000000..6d75b82
--- /dev/null
+++ b/src/Core/LogManager.h
@@ -0,0 +1,146 @@
+/*
+ * LogManager.h
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_LOGMANAGER_H_
+#define MAD_CORE_LOGMANAGER_H_
+
+#include <config.h>
+
+#include "Configurable.h"
+#include "Logger.h"
+#include "RemoteLogger.h"
+
+#include <queue>
+#include <set>
+
+#include <boost/thread/condition_variable.hpp>
+#include <boost/thread/mutex.hpp>
+
+namespace Mad {
+namespace Core {
+
+class ThreadManager;
+
+class LogManager : public Configurable {
+ private:
+ friend class ThreadManager;
+
+ typedef LoggerBase::MessageCategory MessageCategory;
+ typedef LoggerBase::MessageLevel MessageLevel;
+
+ struct Message {
+ MessageCategory category;
+ MessageLevel level;
+ time_t timestamp;
+ std::string message;
+ };
+
+ struct RemoteMessage {
+ MessageCategory category;
+ MessageLevel level;
+ time_t timestamp;
+ std::string message;
+ std::string source;
+ };
+
+ class ConsoleLogger : public Logger, public RemoteLogger {
+ private:
+ // For long messages, writing to cerr is not atomic
+ // -> lock cerr to prevent mixing messages up
+ boost::mutex cerrLock;
+
+ protected:
+ virtual void logMessage(MessageCategory category _UNUSED_PARAMETER_, MessageLevel level, time_t timestamp _UNUSED_PARAMETER_, const std::string &message);
+ virtual void logMessage(MessageCategory category _UNUSED_PARAMETER_, MessageLevel, time_t timestamp _UNUSED_PARAMETER_, const std::string &message, const std::string &messageSource);
+
+ public:
+ ConsoleLogger() {}
+
+ void logMessageDirect(MessageCategory category _UNUSED_PARAMETER_, MessageLevel level _UNUSED_PARAMETER_, time_t timestamp _UNUSED_PARAMETER_, const std::string &message);
+ };
+
+
+ static LogManager logManager;
+
+ ConsoleLogger consoleLogger;
+
+ std::set<Logger*> loggers;
+ std::set<RemoteLogger*> remoteLoggers;
+ bool configured, running;
+
+ boost::mutex queueLock;
+ boost::condition_variable queueCond;
+
+ boost::mutex loggerLock;
+ boost::mutex remoteLoggerLock;
+
+ std::queue<Message> messageQueue;
+ std::queue<RemoteMessage> remoteMessageQueue;
+
+ void loggerThread();
+ void stopLoggerThread() {
+ queueLock.lock();
+ running = false;
+ queueLock.unlock();
+ queueCond.notify_one();
+ }
+
+ LogManager() : configured(false), running(false) {}
+
+ protected:
+ virtual bool handleConfigEntry(const ConfigEntry &entry, bool handled);
+ virtual void configFinished();
+
+ public:
+ void log(MessageCategory category, MessageLevel level, time_t timestamp, const std::string &message);
+ void log(MessageCategory category, MessageLevel level, time_t timestamp, const std::string &message, const std::string &source);
+
+ void registerLogger(Logger *logger) {
+ loggerLock.lock();
+ loggers.insert(logger);
+ loggerLock.unlock();
+ }
+
+ void unregisterLogger(Logger *logger) {
+ loggerLock.lock();
+ loggers.erase(logger);
+ loggerLock.unlock();
+ }
+
+ void registerLogger(RemoteLogger *logger) {
+ remoteLoggerLock.lock();
+ remoteLoggers.insert(logger);
+ remoteLoggerLock.unlock();
+ }
+
+ void unregisterLogger(RemoteLogger *logger) {
+ remoteLoggerLock.lock();
+ remoteLoggers.erase(logger);
+ remoteLoggerLock.unlock();
+ }
+
+ static LogManager *get() {
+ return &logManager;
+ }
+};
+
+}
+}
+
+#endif /* MAD_CORE_LOGMANAGER_H_ */
diff --git a/src/Core/Logger.cpp b/src/Core/Logger.cpp
new file mode 100644
index 0000000..e4e0341
--- /dev/null
+++ b/src/Core/Logger.cpp
@@ -0,0 +1,89 @@
+/*
+ * Logger.cpp
+ *
+ * Copyright (C) 2008 Johannes Thorn <dante@g4t3.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Logger.h"
+#include "LogManager.h"
+
+#include <cstdlib>
+
+namespace Mad {
+namespace Core {
+
+void Logger::logfv(MessageCategory category, MessageLevel level, const char *format, va_list ap) {
+ int size = 100;
+ char *buf = (char*)std::malloc(size);
+
+ // If buffer is too small, try again with bigger buffer
+ while(true) {
+ va_list ap2;
+
+ va_copy(ap2, ap);
+ int n = std::vsnprintf(buf, size, format, ap2);
+ va_end(ap2);
+
+ if(n > -1 && n < size) {
+ log(category, level, buf);
+ std::free(buf);
+ return;
+ }
+
+ if(n > -1)
+ size = n+1;
+ else
+ size *= 2;
+
+ buf = (char*)std::realloc(buf, size);
+ }
+
+}
+
+void Logger::log(MessageCategory category, MessageLevel level, const std::string &message) {
+ LogManager::get()->log(category, level, std::time(0), message);
+}
+
+void Logger::logf(MessageCategory category, MessageLevel level, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ logfv(category, level, format, ap);
+ va_end(ap);
+}
+
+void Logger::logf(MessageCategory category, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ logfv(category, DEFAULT, format, ap);
+ va_end(ap);
+}
+
+void Logger::logf(MessageLevel level, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ logfv(GENERAL, level, format, ap);
+ va_end(ap);
+}
+
+void Logger::logf(const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ logfv(GENERAL, DEFAULT, format, ap);
+ va_end(ap);
+}
+
+}
+}
diff --git a/src/Core/Logger.h b/src/Core/Logger.h
new file mode 100644
index 0000000..3de22d2
--- /dev/null
+++ b/src/Core/Logger.h
@@ -0,0 +1,68 @@
+/*
+ * Logger.h
+ *
+ * Copyright (C) 2008 Johannes Thorn <dante@g4t3.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_LOGGER_H_
+#define MAD_CORE_LOGGER_H_
+
+#include "LoggerBase.h"
+
+#include <cstdarg>
+#include <ctime>
+#include <string>
+
+namespace Mad {
+namespace Core {
+
+class LogManager;
+
+class Logger : public LoggerBase {
+ private:
+ friend class LogManager;
+
+ static void logfv(MessageCategory category, MessageLevel level, const char *format, va_list ap);
+
+ protected:
+ virtual void logMessage(MessageCategory category, MessageLevel level, time_t timestamp, const std::string &message) = 0;
+
+ public:
+ static void log(MessageCategory category, MessageLevel level, const std::string &message);
+
+ static void log(MessageCategory category, const std::string &message) {
+ log(category, DEFAULT, message);
+ }
+
+ static void log(MessageLevel level, const std::string &message) {
+ log(GENERAL, level, message);
+ }
+
+ static void log(const std::string &message) {
+ log(GENERAL, DEFAULT, message);
+ }
+
+
+ static void logf(MessageCategory category, MessageLevel level, const char *format, ...);
+ static void logf(MessageCategory category, const char *format, ...);
+ static void logf(MessageLevel level, const char *format, ...);
+ static void logf(const char *format, ...);
+};
+
+}
+}
+
+#endif /* MAD_CORE_LOGGER_H_ */
diff --git a/src/Core/LoggerBase.h b/src/Core/LoggerBase.h
new file mode 100644
index 0000000..49be833
--- /dev/null
+++ b/src/Core/LoggerBase.h
@@ -0,0 +1,79 @@
+/*
+ * LoggerBase.h
+ *
+ * Copyright (C) 2008 Johannes Thorn <dante@g4t3.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_LOGGERBASE_H_
+#define MAD_CORE_LOGGERBASE_H_
+
+#include <bitset>
+#include <list>
+
+namespace Mad {
+namespace Core {
+
+class LoggerBase {
+ public:
+ enum MessageLevel {
+ CRITICAL, ERROR, WARNING, DEFAULT, VERBOSE, DEBUG
+ };
+
+ enum MessageCategory {
+ SYSTEM, NETWORK, DAEMON, USER, DISK, PROGRAM, GENERAL
+ };
+
+ protected:
+ std::bitset<16> categories;
+ MessageLevel level;
+
+ LoggerBase() : level(DEFAULT) {setAllCategories();}
+ virtual ~LoggerBase() {}
+
+ public:
+ void setCategory(MessageCategory newCategory) {
+ categories.set(newCategory);
+ }
+
+ void unsetCategory(MessageCategory oldCategory) {
+ categories.reset(oldCategory);
+ }
+
+ void setAllCategories() {
+ categories.set();
+ }
+
+ void unsetAllCategories() {
+ categories.reset();
+ }
+
+ bool isCategorySet(MessageCategory category) const {
+ return categories.test(category);
+ }
+
+ MessageLevel getLevel() const {
+ return level;
+ }
+
+ void setLevel(MessageLevel newLevel) {
+ level = newLevel;
+ }
+};
+
+}
+}
+
+#endif /* MAD_CORE_LOGGERBASE_H_ */
diff --git a/src/Core/RemoteLogger.h b/src/Core/RemoteLogger.h
new file mode 100644
index 0000000..f5c8a6b
--- /dev/null
+++ b/src/Core/RemoteLogger.h
@@ -0,0 +1,42 @@
+/*
+ * LogRequestLogger.h
+ *
+ * Copyright (C) 2008 Johannes Thorn <dante@g4t3.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_REMOTELOGGER_H_
+#define MAD_CORE_REMOTELOGGER_H_
+
+#include "LoggerBase.h"
+
+#include <string>
+
+namespace Mad {
+namespace Core {
+
+class LogManager;
+
+class RemoteLogger : public LoggerBase {
+ protected:
+ friend class LogManager;
+
+ virtual void logMessage(MessageCategory category, MessageLevel level, time_t messageTimestamp, const std::string &message, const std::string &messageSource) = 0;
+};
+
+}
+}
+
+#endif /* MAD_CORE_REMOTELOGGER_H_ */
diff --git a/src/Core/Signals.h b/src/Core/Signals.h
new file mode 100644
index 0000000..3c129af
--- /dev/null
+++ b/src/Core/Signals.h
@@ -0,0 +1,27 @@
+/*
+ * Signals.h
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_SIGNALS_SIGNALS_H_
+#define MAD_CORE_SIGNALS_SIGNALS_H_
+
+#include "Signals/Signal0.h"
+#include "Signals/Signal1.h"
+#include "Signals/Signal2.h"
+
+#endif /* MAD_CORE_SIGNALS_SIGNALS_H_ */
diff --git a/src/Core/Signals/Connection.h b/src/Core/Signals/Connection.h
new file mode 100644
index 0000000..5ce7b4a
--- /dev/null
+++ b/src/Core/Signals/Connection.h
@@ -0,0 +1,53 @@
+/*
+ * Connection.h
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_SIGNALS_CONNECTION_H_
+#define MAD_CORE_SIGNALS_CONNECTION_H_
+
+namespace Mad {
+namespace Core {
+namespace Signals {
+
+class SignalBase;
+
+class Connection {
+ private:
+ friend class SignalBase;
+
+ SignalBase *signal;
+ unsigned long id;
+
+ Connection(SignalBase *signal0, unsigned long id0)
+ : signal(signal0), id(id0) {}
+
+ public:
+ bool operator==(const Connection &o) const {
+ return (signal == o.signal && id == o.id);
+ }
+
+ bool operator<(const Connection &o) const {
+ return (signal != o.signal) ? (signal < o.signal) : (id < o.id);
+ }
+};
+
+}
+}
+}
+
+#endif /* MAD_CORE_SIGNALS_CONNECTION_H_ */
diff --git a/src/Core/Signals/GenericSignal.h b/src/Core/Signals/GenericSignal.h
new file mode 100644
index 0000000..641f575
--- /dev/null
+++ b/src/Core/Signals/GenericSignal.h
@@ -0,0 +1,61 @@
+/*
+ * GenericSignal.h
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_SIGNALS_GENERICSIGNAL_H_
+#define MAD_CORE_SIGNALS_GENERICSIGNAL_H_
+
+#include "SignalBase.h"
+
+#include <map>
+#include <boost/thread/locks.hpp>
+
+namespace Mad {
+namespace Core {
+namespace Signals {
+
+template <typename FunctionType>
+class GenericSignal : protected SignalBase {
+ public:
+ typedef FunctionType slot_type;
+
+ protected:
+ std::map<Connection, slot_type> handlers;
+
+ public:
+ Connection connect(const slot_type &slot) {
+ boost::lock_guard<boost::mutex> lock(mutex);
+
+ Connection con = getNewConnection();
+ handlers.insert(std::make_pair(con, slot));
+
+ return con;
+ }
+
+ bool disconnect(const Connection &connection) {
+ boost::lock_guard<boost::mutex> lock(mutex);
+
+ return handlers.erase(connection);
+ }
+};
+
+}
+}
+}
+
+#endif /* MAD_CORE_SIGNALS_GENERICSIGNAL_H_ */
diff --git a/src/Core/Signals/Signal0.h b/src/Core/Signals/Signal0.h
new file mode 100644
index 0000000..ccfb548
--- /dev/null
+++ b/src/Core/Signals/Signal0.h
@@ -0,0 +1,46 @@
+/*
+ * Signal0.h
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_SIGNALS_SIGNAL0_H_
+#define MAD_CORE_SIGNALS_SIGNAL0_H_
+
+#include "GenericSignal.h"
+#include "../ThreadManager.h"
+
+#include <boost/function.hpp>
+
+namespace Mad {
+namespace Core {
+namespace Signals {
+
+class Signal0 : public GenericSignal<boost::function0<void> > {
+ public:
+ void emit() {
+ boost::lock_guard<boost::mutex> lock(mutex);
+
+ for(std::map<Connection, slot_type>::iterator handler = handlers.begin(); handler != handlers.end(); ++handler)
+ ThreadManager::get()->pushWork(handler->second);
+ }
+};
+
+}
+}
+}
+
+#endif /* MAD_CORE_SIGNALS_SIGNAL0_H_ */
diff --git a/src/Core/Signals/Signal1.h b/src/Core/Signals/Signal1.h
new file mode 100644
index 0000000..e4a946c
--- /dev/null
+++ b/src/Core/Signals/Signal1.h
@@ -0,0 +1,47 @@
+/*
+ * Signal1.h
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_SIGNALS_SIGNAL1_H_
+#define MAD_CORE_SIGNALS_SIGNAL1_H_
+
+#include "GenericSignal.h"
+#include "../ThreadManager.h"
+
+#include <boost/function.hpp>
+
+namespace Mad {
+namespace Core {
+namespace Signals {
+
+template <typename T1>
+class Signal1 : public GenericSignal<boost::function1<void, T1> > {
+ public:
+ void emit(T1 arg1) {
+ boost::lock_guard<boost::mutex> lock(this->mutex);
+
+ for(typename std::map<Connection, typename GenericSignal<boost::function1<void, T1> >::slot_type>::iterator handler = this->handlers.begin(); handler != this->handlers.end(); ++handler)
+ ThreadManager::get()->pushWork(boost::bind(handler->second, arg1));
+ }
+};
+
+}
+}
+}
+
+#endif /* MAD_CORE_SIGNALS_SIGNAL1_H_ */
diff --git a/src/Core/Signals/Signal2.h b/src/Core/Signals/Signal2.h
new file mode 100644
index 0000000..41045d7
--- /dev/null
+++ b/src/Core/Signals/Signal2.h
@@ -0,0 +1,47 @@
+/*
+ * Signal2.h
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_SIGNALS_SIGNAL2_H_
+#define MAD_CORE_SIGNALS_SIGNAL2_H_
+
+#include "GenericSignal.h"
+#include "../ThreadManager.h"
+
+#include <boost/function.hpp>
+
+namespace Mad {
+namespace Core {
+namespace Signals {
+
+template <typename T1, typename T2>
+class Signal2 : public GenericSignal<boost::function2<void, T1, T2> > {
+ public:
+ void emit(T1 arg1, T2 arg2) {
+ boost::lock_guard<boost::mutex> lock(this->mutex);
+
+ for(typename std::map<Connection, typename GenericSignal<boost::function2<void, T1, T2> >::slot_type>::iterator handler = this->handlers.begin(); handler != this->handlers.end(); ++handler)
+ ThreadManager::get()->pushWork(boost::bind(handler->second, arg1, arg2));
+ }
+};
+
+}
+}
+}
+
+#endif /* MAD_CORE_SIGNALS_SIGNAL2_H_ */
diff --git a/src/Core/Signals/SignalBase.h b/src/Core/Signals/SignalBase.h
new file mode 100644
index 0000000..1a5d5a3
--- /dev/null
+++ b/src/Core/Signals/SignalBase.h
@@ -0,0 +1,53 @@
+/*
+ * SignalBase.h
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_SIGNALS_SIGNALBASE_H_
+#define MAD_CORE_SIGNALS_SIGNALBASE_H_
+
+#include "Connection.h"
+
+#include <set>
+#include <boost/thread/mutex.hpp>
+
+namespace Mad {
+namespace Core {
+namespace Signals {
+
+class SignalBase : private boost::noncopyable {
+ private:
+ friend class Connection;
+
+ unsigned long connectionId;
+
+ protected:
+ boost::mutex mutex;
+
+ Connection getNewConnection() {
+ return Connection(this, connectionId++);
+ }
+
+ SignalBase() : connectionId(0) {}
+ virtual ~SignalBase() {}
+};
+
+}
+}
+}
+
+#endif /* MAD_CORE_SIGNALS_SIGNALBASE_H_ */
diff --git a/src/Core/ThreadManager.cpp b/src/Core/ThreadManager.cpp
new file mode 100644
index 0000000..abc0bc6
--- /dev/null
+++ b/src/Core/ThreadManager.cpp
@@ -0,0 +1,143 @@
+/*
+ * ThreadManager.cpp
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "ThreadManager.h"
+
+#include "Logger.h"
+#include "LogManager.h"
+
+#include <boost/bind.hpp>
+
+namespace Mad {
+namespace Core {
+
+ThreadManager ThreadManager::threadManager;
+
+
+void ThreadManager::workerFunc() {
+ while(true) {
+ boost::unique_lock<boost::mutex> lock(runLock);
+
+ if(!running || !isThisWorkerThread())
+ break;
+
+ lock.unlock();
+
+ boost::unique_lock<boost::mutex> lock2(workLock);
+ while(work.empty()) {
+ workCond.wait(lock2);
+
+ if(!running)
+ return;
+ }
+
+ boost::function0<void> nextWork = work.front();
+ work.pop();
+
+ lock2.unlock();
+
+ nextWork();
+ }
+
+ // And let the new worker thread join us...
+ pushWork(boost::bind(&ThreadManager::threadFinished, this, boost::this_thread::get_id()));
+}
+
+void ThreadManager::detach() {
+ if(isThisMainThread()) {
+ Logger::log(Logger::CRITICAL, "Tried to detach main thread! This is just WRONG!");
+ return;
+ }
+
+ {
+ boost::lock_guard<boost::mutex> lock(runLock);
+ if(!running)
+ return; // There's no point in creating a new worker thread when we aren't running anymore
+ }
+
+ threadLock.lock();
+
+ if(workerThread->get_id() == boost::this_thread::get_id()) {// Already detached?
+ threads.insert(std::make_pair(boost::this_thread::get_id(), workerThread));
+
+ workerThread.reset(new boost::thread(std::mem_fun(&ThreadManager::workerFunc), this));
+ }
+
+ threadLock.unlock();
+}
+
+void ThreadManager::pushWork(const boost::function0<void> &newWork) {
+ workLock.lock();
+ work.push(newWork);
+ workLock.unlock();
+
+ workCond.notify_one();
+}
+
+
+void ThreadManager::doInit() {
+ running = true;
+
+ threadLock.lock();
+
+ ioWorker.reset(new boost::asio::io_service::work(ioService));
+
+ mainThreadId = boost::this_thread::get_id();
+ workerThread.reset(new boost::thread(&ThreadManager::workerFunc, this));
+ loggerThread.reset(new boost::thread(&LogManager::loggerThread, LogManager::get()));
+ ioThread.reset(new boost::thread((std::size_t(boost::asio::io_service::*)())&boost::asio::io_service::run, &ioService));
+
+ threadLock.unlock();
+}
+
+void ThreadManager::doDeinit() {
+ if(!isThisMainThread()) {
+ // TODO Critical error!!!
+ return;
+ }
+
+ // First set running = false so the worker threads quit
+ boost::lock(runLock, workLock);
+ running = false;
+
+ workLock.unlock();
+ runLock.unlock();
+
+ workCond.notify_one();
+
+ // We don't have to lock threadLock as detach() won't change workerThread when running is false
+ workerThread->join();
+
+ // Now wait for all detached threads
+ while(!threads.empty()) {
+ threadFinished(threads.begin()->first);
+ }
+
+ // IO thread is next
+ ioWorker.reset();
+ ioService.stop();
+ ioThread->join();
+
+ // Finally, the logger thread has to die
+ LogManager::get()->stopLoggerThread();
+ loggerThread->join();
+}
+
+}
+}
diff --git a/src/Core/ThreadManager.h b/src/Core/ThreadManager.h
new file mode 100644
index 0000000..b512ad4
--- /dev/null
+++ b/src/Core/ThreadManager.h
@@ -0,0 +1,113 @@
+/*
+ * ThreadManager.h
+ *
+ * Copyright (C) 2009 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_THREADMANAGER_H_
+#define MAD_CORE_THREADMANAGER_H_
+
+#include <config.h>
+
+#include "Initializable.h"
+
+#include <queue>
+#include <map>
+
+#include <boost/asio.hpp>
+
+#include <boost/thread/thread.hpp>
+#include <boost/thread/condition_variable.hpp>
+#include <boost/thread/locks.hpp>
+
+namespace Mad {
+namespace Core {
+
+class ThreadManager : public Initializable {
+ private:
+ boost::thread::id mainThreadId;
+ boost::shared_ptr<boost::thread> workerThread, loggerThread, ioThread;
+ std::map<boost::thread::id, boost::shared_ptr<boost::thread> > threads;
+
+ boost::mutex threadLock;
+
+ boost::mutex runLock;
+ bool running;
+
+ boost::mutex workLock;
+ boost::condition_variable workCond;
+ std::queue<boost::function0<void> > work;
+
+ boost::scoped_ptr<boost::asio::io_service::work> ioWorker;
+
+ boost::asio::io_service ioService;
+
+ static ThreadManager threadManager;
+
+ ThreadManager() {}
+
+ void workerFunc();
+ void ioFunc();
+
+ void threadFinished(boost::thread::id threadId) {
+ boost::shared_ptr<boost::thread> thread;
+
+ {
+ boost::lock_guard<boost::mutex> lock(threadLock);
+
+ std::map<boost::thread::id, boost::shared_ptr<boost::thread> >::iterator it = threads.find(threadId);
+
+ if(it == threads.end())
+ return;
+
+ thread = it->second;
+ threads.erase(it);
+ }
+
+ thread->join();
+ }
+
+ protected:
+ virtual void doInit();
+ virtual void doDeinit();
+
+ public:
+ bool isThisMainThread() {
+ return (mainThreadId == boost::this_thread::get_id());
+ }
+
+ bool isThisWorkerThread() {
+ boost::lock_guard<boost::mutex> lock(threadLock);
+ return (workerThread->get_id() == boost::this_thread::get_id());
+ }
+
+ boost::asio::io_service& getIOService() {
+ return ioService;
+ }
+
+ void detach();
+
+ void pushWork(const boost::function0<void> &newWork);
+
+ static ThreadManager* get() {
+ return &threadManager;
+ }
+};
+
+}
+}
+
+#endif /* MAD_CORE_THREADMANAGER_H_ */
diff --git a/src/Core/Tokenizer.cpp b/src/Core/Tokenizer.cpp
new file mode 100644
index 0000000..a812ed1
--- /dev/null
+++ b/src/Core/Tokenizer.cpp
@@ -0,0 +1,131 @@
+/*
+ * Tokenizer.cpp
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Tokenizer.h"
+
+namespace Mad {
+namespace Core {
+
+const std::string Tokenizer::delimiters = " \t\n\"'\\";
+
+
+std::vector<std::string> Tokenizer::split(const std::string &str) {
+ std::vector<std::string> ret;
+
+ for(size_t s = 0; s < str.length();) {
+ size_t index = str.find_first_of(delimiters, s);
+ size_t length = (index == std::string::npos) ? std::string::npos : index-s;
+
+ ret.push_back(str.substr(s, length));
+
+ if(index != std::string::npos) {
+ size_t index2 = str.find_first_not_of(delimiters, index);
+
+ length = (index2 == std::string::npos) ? std::string::npos : index2-index;
+
+ ret.push_back(str.substr(index, length));
+
+ if(index2 != std::string::npos)
+ s = index2;
+ else
+ break;
+ }
+ else
+ break;
+ }
+
+ return ret;
+}
+
+bool Tokenizer::tokenize(const std::string &str, std::vector<std::string> &out) {
+ std::vector<std::string> splitString = split(str);
+
+ bool singleQuotes = false, doubleQuotes = false, escape = false;
+ std::string token;
+ bool forceToken = false;
+
+ out.clear();
+
+ for(std::vector<std::string>::iterator s = splitString.begin(); s != splitString.end(); ++s) {
+ token += *s;
+ escape = false;
+
+ if(++s == splitString.end())
+ break;
+
+ for(std::string::iterator c = s->begin(); c != s->end(); ++c) {
+ if(*c == '\n' && escape) {
+ escape = false;
+
+ if(doubleQuotes)
+ continue;
+ }
+
+ if(escape || (singleQuotes && *c != '\'')) {
+ token += *c;
+
+ escape = false;
+ continue;
+ }
+
+ switch(*c) {
+ case ' ':
+ case '\t':
+ case '\n':
+ if(doubleQuotes) {
+ token += *c;
+ }
+ else {
+ if(!token.empty() || forceToken) {
+ out.push_back(token);
+ token.clear();
+ forceToken = false;
+ }
+ }
+ break;
+
+ case '"':
+ doubleQuotes = !doubleQuotes;
+ forceToken = true;
+ break;
+
+ case '\'':
+ if(doubleQuotes) {
+ token += *c;
+ }
+ else {
+ singleQuotes = !singleQuotes;
+ forceToken = true;
+ }
+ break;
+
+ case '\\':
+ escape = true;
+ }
+ }
+ }
+
+ if(!token.empty() || forceToken)
+ out.push_back(token);
+
+ return !(singleQuotes || doubleQuotes || escape);
+}
+
+}
+}
diff --git a/src/Core/Tokenizer.h b/src/Core/Tokenizer.h
new file mode 100644
index 0000000..7b29fed
--- /dev/null
+++ b/src/Core/Tokenizer.h
@@ -0,0 +1,44 @@
+/*
+ * Tokenizer.h
+ *
+ * Copyright (C) 2008 Matthias Schiffer <matthias@gamezock.de>
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef MAD_CORE_TOKENIZER_H_
+#define MAD_CORE_TOKENIZER_H_
+
+#include <string>
+#include <vector>
+
+namespace Mad {
+namespace Core {
+
+class Tokenizer {
+ private:
+ static const std::string delimiters;
+
+ Tokenizer();
+
+ static std::vector<std::string> split(const std::string &str);
+
+ public:
+ static bool tokenize(const std::string &str, std::vector<std::string> &out);
+};
+
+}
+}
+
+#endif /* MAD_CORE_TOKENIZER_H_ */