summaryrefslogtreecommitdiffstats
path: root/src/Net
diff options
context:
space:
mode:
authorMatthias Schiffer <matthias@gamezock.de>2009-05-06 17:39:30 +0200
committerMatthias Schiffer <matthias@gamezock.de>2009-05-06 17:39:30 +0200
commit8324b947487f72fd8cfc439ea5ae5bd1187fff1b (patch)
treee7fb69f3207654b5e3d4ba260d3f51082b1d399a /src/Net
parent5bf3e2229015d93808bb0c2f4729c2c4f4da414e (diff)
downloadmad-8324b947487f72fd8cfc439ea5ae5bd1187fff1b.tar
mad-8324b947487f72fd8cfc439ea5ae5bd1187fff1b.zip
Exception und ThreadHandler nach Net verschoben
Diffstat (limited to 'src/Net')
-rw-r--r--src/Net/ClientConnection.cpp8
-rw-r--r--src/Net/ClientConnection.h4
-rw-r--r--src/Net/Exception.cpp63
-rw-r--r--src/Net/Exception.h61
-rw-r--r--src/Net/IPAddress.cpp10
-rw-r--r--src/Net/IPAddress.h6
-rw-r--r--src/Net/Listener.cpp10
-rw-r--r--src/Net/Listener.h3
-rw-r--r--src/Net/Makefile.am6
-rw-r--r--src/Net/Makefile.in15
-rw-r--r--src/Net/ServerConnection.h1
-rw-r--r--src/Net/ThreadManager.cpp215
-rw-r--r--src/Net/ThreadManager.h113
13 files changed, 487 insertions, 28 deletions
diff --git a/src/Net/ClientConnection.cpp b/src/Net/ClientConnection.cpp
index 31c1a08..0162a86 100644
--- a/src/Net/ClientConnection.cpp
+++ b/src/Net/ClientConnection.cpp
@@ -54,7 +54,7 @@ void ClientConnection::connectionHeader() {
rawReceive(sizeof(ConnectionHeader), sigc::mem_fun(this, &ClientConnection::connectionHeaderReceiveHandler));
}
-void ClientConnection::connect(const IPAddress &address, bool daemon0) throw(Common::Exception) {
+void ClientConnection::connect(const IPAddress &address, bool daemon0) throw(Exception) {
daemon = daemon0;
if(isConnected())
@@ -63,7 +63,7 @@ void ClientConnection::connect(const IPAddress &address, bool daemon0) throw(Com
sock = socket(PF_INET, SOCK_STREAM, 0);
if(sock < 0)
- throw Common::Exception("socket()", Common::Exception::INTERNAL_ERRNO, errno);
+ throw Exception("socket()", Exception::INTERNAL_ERRNO, errno);
if(peer)
delete peer;
@@ -73,7 +73,7 @@ void ClientConnection::connect(const IPAddress &address, bool daemon0) throw(Com
close(sock);
delete peer;
peer = 0;
- throw Common::Exception("connect()", Common::Exception::INTERNAL_ERRNO, errno);
+ throw Exception("connect()", Exception::INTERNAL_ERRNO, errno);
}
// Set non-blocking flag
@@ -82,7 +82,7 @@ void ClientConnection::connect(const IPAddress &address, bool daemon0) throw(Com
if(flags < 0) {
close(sock);
- throw Common::Exception("fcntl()", Common::Exception::INTERNAL_ERRNO, errno);
+ throw Exception("fcntl()", Exception::INTERNAL_ERRNO, errno);
}
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
diff --git a/src/Net/ClientConnection.h b/src/Net/ClientConnection.h
index 88bdf09..bdd7872 100644
--- a/src/Net/ClientConnection.h
+++ b/src/Net/ClientConnection.h
@@ -21,7 +21,7 @@
#define MAD_NET_CLIENTCONNECTION_H_
#include "Connection.h"
-#include <Common/Exception.h>
+#include "Exception.h"
namespace Mad {
namespace Net {
@@ -40,7 +40,7 @@ class ClientConnection : public Connection {
public:
ClientConnection() : daemon(0) {}
- void connect(const IPAddress &address, bool daemon0 = false) throw(Common::Exception);
+ void connect(const IPAddress &address, bool daemon0 = false) throw(Exception);
};
}
diff --git a/src/Net/Exception.cpp b/src/Net/Exception.cpp
new file mode 100644
index 0000000..34b8033
--- /dev/null
+++ b/src/Net/Exception.cpp
@@ -0,0 +1,63 @@
+/*
+ * 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>
+#include <gnutls/gnutls.h>
+
+namespace Mad {
+namespace Net {
+
+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 INTERNAL_GNUTLS:
+ return ret + "GnuTLS error: " + gnutls_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/Net/Exception.h b/src/Net/Exception.h
new file mode 100644
index 0000000..48e86d1
--- /dev/null
+++ b/src/Net/Exception.h
@@ -0,0 +1,61 @@
+/*
+ * 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_NET_EXCEPTION_H_
+#define MAD_NET_EXCEPTION_H_
+
+#include <string>
+
+namespace Mad {
+namespace Net {
+
+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, INTERNAL_GNUTLS = 0x0011,
+ 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, long subCode0 = 0, long subSubCode0 = 0)
+ : where(where0), errorCode(errorCode0), subCode(subCode0), subSubCode(subSubCode0) {}
+ Exception(ErrorCode errorCode0, 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;
+};
+
+}
+}
+
+#endif /* MAD_NET_EXCEPTION_H_ */
diff --git a/src/Net/IPAddress.cpp b/src/Net/IPAddress.cpp
index 6bf79a3..eb9d3be 100644
--- a/src/Net/IPAddress.cpp
+++ b/src/Net/IPAddress.cpp
@@ -36,7 +36,7 @@ IPAddress::IPAddress(uint32_t address, uint16_t port0) : addr(address), port(por
sa.sin_addr.s_addr = htonl(addr);
}
-IPAddress::IPAddress(const std::string &address) throw(Common::Exception) {
+IPAddress::IPAddress(const std::string &address) throw(Exception) {
std::string ip;
size_t pos = address.find_first_of(':');
@@ -51,7 +51,7 @@ IPAddress::IPAddress(const std::string &address) throw(Common::Exception) {
char *endptr;
port = std::strtol(address.substr(pos+1).c_str(), &endptr, 10);
if(*endptr != 0 || port == 0)
- throw Common::Exception(Common::Exception::INVALID_ADDRESS);
+ throw Exception(Exception::INVALID_ADDRESS);
}
sa.sin_family = AF_INET;
@@ -60,17 +60,17 @@ IPAddress::IPAddress(const std::string &address) throw(Common::Exception) {
if(ip == "*")
sa.sin_addr.s_addr = INADDR_ANY;
else if(!inet_pton(AF_INET, ip.c_str(), &sa.sin_addr))
- throw Common::Exception(Common::Exception::INVALID_ADDRESS);
+ throw Exception(Exception::INVALID_ADDRESS);
addr = ntohl(sa.sin_addr.s_addr);
}
-IPAddress::IPAddress(const std::string &address, uint16_t port0) throw(Common::Exception) : port(port0) {
+IPAddress::IPAddress(const std::string &address, uint16_t port0) throw(Exception) : port(port0) {
sa.sin_family = AF_INET;
sa.sin_port = htons(port);
if(!inet_pton(AF_INET, address.c_str(), &sa.sin_addr))
- throw Common::Exception(Common::Exception::INVALID_ADDRESS);
+ throw Exception(Exception::INVALID_ADDRESS);
addr = ntohl(sa.sin_addr.s_addr);
}
diff --git a/src/Net/IPAddress.h b/src/Net/IPAddress.h
index d67ec3e..3541891 100644
--- a/src/Net/IPAddress.h
+++ b/src/Net/IPAddress.h
@@ -20,7 +20,7 @@
#ifndef MAD_NET_IPADDRESS_H_
#define MAD_NET_IPADDRESS_H_
-#include <Common/Exception.h>
+#include "Exception.h"
#include <string>
#include <arpa/inet.h>
@@ -39,8 +39,8 @@ class IPAddress {
// TODO Default port
IPAddress(uint16_t port0 = 6666);
IPAddress(uint32_t address, uint16_t port0);
- IPAddress(const std::string &address) throw(Common::Exception);
- IPAddress(const std::string &address, uint16_t port0) throw(Common::Exception);
+ IPAddress(const std::string &address) throw(Exception);
+ IPAddress(const std::string &address, uint16_t port0) throw(Exception);
IPAddress(const struct sockaddr_in &address);
uint32_t getAddress() const {return addr;}
diff --git a/src/Net/Listener.cpp b/src/Net/Listener.cpp
index c4c5194..95147fa 100644
--- a/src/Net/Listener.cpp
+++ b/src/Net/Listener.cpp
@@ -41,7 +41,7 @@ void Listener::acceptHandler(int) {
}
}
-Listener::Listener(const std::string &x905CertFile0, const std::string &x905KeyFile0, const IPAddress &address0) throw(Common::Exception)
+Listener::Listener(const std::string &x905CertFile0, const std::string &x905KeyFile0, const IPAddress &address0) throw(Exception)
: x905CertFile(x905CertFile0), x905KeyFile(x905KeyFile0), address(address0) {
gnutls_dh_params_init(&dh_params);
gnutls_dh_params_generate2(dh_params, 768);
@@ -49,7 +49,7 @@ Listener::Listener(const std::string &x905CertFile0, const std::string &x905KeyF
sock = socket(PF_INET, SOCK_STREAM, 0);
if(sock < 0)
- throw Common::Exception("socket()", Common::Exception::INTERNAL_ERRNO, errno);
+ throw Exception("socket()", Exception::INTERNAL_ERRNO, errno);
// Set non-blocking flag
int flags = fcntl(sock, F_GETFL, 0);
@@ -57,7 +57,7 @@ Listener::Listener(const std::string &x905CertFile0, const std::string &x905KeyF
if(flags < 0) {
close(sock);
- throw Common::Exception("fcntl()", Common::Exception::INTERNAL_ERRNO, errno);
+ throw Exception("fcntl()", Exception::INTERNAL_ERRNO, errno);
}
fcntl(sock, F_SETFL, flags | O_NONBLOCK);
@@ -69,13 +69,13 @@ Listener::Listener(const std::string &x905CertFile0, const std::string &x905KeyF
if(bind(sock, address.getSockAddr(), address.getSockAddrLength()) < 0) {
close(sock);
- throw Common::Exception("bind()", Common::Exception::INTERNAL_ERRNO, errno);
+ throw Exception("bind()", Exception::INTERNAL_ERRNO, errno);
}
if(listen(sock, 64) < 0) {
close(sock);
- throw Common::Exception("listen()", Common::Exception::INTERNAL_ERRNO, errno);
+ throw Exception("listen()", Exception::INTERNAL_ERRNO, errno);
}
FdManager::get()->registerFd(sock, sigc::mem_fun(this, &Listener::acceptHandler), POLLIN);
diff --git a/src/Net/Listener.h b/src/Net/Listener.h
index a095439..ca19947 100644
--- a/src/Net/Listener.h
+++ b/src/Net/Listener.h
@@ -21,7 +21,6 @@
#define MAD_NET_LISTENER_H_
#include "IPAddress.h"
-#include <Common/Exception.h>
#include <gnutls/gnutls.h>
#include <list>
@@ -51,7 +50,7 @@ class Listener {
Listener& operator=(const Listener &o);
public:
- Listener(const std::string &x905CertFile0, const std::string &x905KeyFile0, const IPAddress &address0 = IPAddress()) throw(Common::Exception);
+ Listener(const std::string &x905CertFile0, const std::string &x905KeyFile0, const IPAddress &address0 = IPAddress()) throw(Exception);
virtual ~Listener();
ServerConnection* getConnection();
diff --git a/src/Net/Makefile.am b/src/Net/Makefile.am
index e8265fa..65fc504 100644
--- a/src/Net/Makefile.am
+++ b/src/Net/Makefile.am
@@ -1,4 +1,6 @@
noinst_LTLIBRARIES = libnet.la
-libnet_la_SOURCES = ClientConnection.cpp ServerConnection.cpp Connection.cpp FdManager.cpp IPAddress.cpp Listener.cpp Packet.cpp
+libnet_la_SOURCES = ClientConnection.cpp Exception.cpp ServerConnection.cpp Connection.cpp FdManager.cpp IPAddress.cpp \
+ Listener.cpp Packet.cpp ThreadManager.cpp
-noinst_HEADERS = ClientConnection.h ServerConnection.h Connection.h FdManager.h IPAddress.h Listener.h Packet.h
+noinst_HEADERS = ClientConnection.h Exception.h ServerConnection.h Connection.h FdManager.h IPAddress.h Listener.h \
+ Packet.h ThreadManager.h
diff --git a/src/Net/Makefile.in b/src/Net/Makefile.in
index 0d65c6d..5d421fb 100644
--- a/src/Net/Makefile.in
+++ b/src/Net/Makefile.in
@@ -60,8 +60,9 @@ CONFIG_HEADER = $(top_builddir)/config.h
CONFIG_CLEAN_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
libnet_la_LIBADD =
-am_libnet_la_OBJECTS = ClientConnection.lo ServerConnection.lo \
- Connection.lo FdManager.lo IPAddress.lo Listener.lo Packet.lo
+am_libnet_la_OBJECTS = ClientConnection.lo Exception.lo \
+ ServerConnection.lo Connection.lo FdManager.lo IPAddress.lo \
+ Listener.lo Packet.lo ThreadManager.lo
libnet_la_OBJECTS = $(am_libnet_la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/config/depcomp
@@ -265,8 +266,12 @@ top_build_prefix = @top_build_prefix@
top_builddir = @top_builddir@
top_srcdir = @top_srcdir@
noinst_LTLIBRARIES = libnet.la
-libnet_la_SOURCES = ClientConnection.cpp ServerConnection.cpp Connection.cpp FdManager.cpp IPAddress.cpp Listener.cpp Packet.cpp
-noinst_HEADERS = ClientConnection.h ServerConnection.h Connection.h FdManager.h IPAddress.h Listener.h Packet.h
+libnet_la_SOURCES = ClientConnection.cpp Exception.cpp ServerConnection.cpp Connection.cpp FdManager.cpp IPAddress.cpp \
+ Listener.cpp Packet.cpp ThreadManager.cpp
+
+noinst_HEADERS = ClientConnection.h Exception.h ServerConnection.h Connection.h FdManager.h IPAddress.h Listener.h \
+ Packet.h ThreadManager.h
+
all: all-am
.SUFFIXES:
@@ -320,11 +325,13 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ClientConnection.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Connection.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Exception.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/FdManager.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/IPAddress.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Listener.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Packet.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ServerConnection.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ThreadManager.Plo@am__quote@
.cpp.o:
@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
diff --git a/src/Net/ServerConnection.h b/src/Net/ServerConnection.h
index 9a67c13..0870143 100644
--- a/src/Net/ServerConnection.h
+++ b/src/Net/ServerConnection.h
@@ -21,7 +21,6 @@
#define MAD_NET_SERVERCONNECTION_H_
#include "Connection.h"
-#include <Common/Exception.h>
#include <string>
namespace Mad {
diff --git a/src/Net/ThreadManager.cpp b/src/Net/ThreadManager.cpp
new file mode 100644
index 0000000..9eb965d
--- /dev/null
+++ b/src/Net/ThreadManager.cpp
@@ -0,0 +1,215 @@
+/*
+ * 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 "FdManager.h"
+
+#include <fcntl.h>
+#include <sigc++/bind.h>
+#include <sigc++/hide.h>
+
+#include <ignore-value.h>
+
+namespace Mad {
+namespace Net {
+
+ThreadManager ThreadManager::threadManager;
+
+
+void ThreadManager::workerFunc() {
+ while(true) {
+ gl_lock_lock(runLock);
+
+ if(!running || !isThisWorkerThread()) {
+ gl_lock_unlock(runLock);
+ return;
+ }
+
+ gl_lock_unlock(runLock);
+
+ gl_lock_lock(workLock);
+ while(work.empty()) {
+ gl_cond_wait(workCond, workLock);
+
+ if(!running) {
+ gl_lock_unlock(workLock);
+ return;
+ }
+ }
+
+ sigc::slot<void> nextWork = work.front();
+ work.pop();
+
+ gl_lock_unlock(workLock);
+
+ nextWork();
+ }
+
+ // And let the new worker thread join us...
+ pushWork(sigc::bind(sigc::mem_fun(this, &ThreadManager::threadFinished), (gl_thread_t)gl_thread_self()));
+}
+
+void ThreadManager::detach() {
+ if(!isThisMainThread()) {
+ Common::Logger::log(Common::Logger::CRITICAL, "Tried to detach main thread! This is just WRONG!");
+ return;
+ }
+
+ gl_lock_lock(runLock);
+ bool isRunning = running;
+ gl_lock_unlock(runLock);
+ if(!isRunning) // There's no point in creating a new worker thread when we aren't running anymore
+ return;
+
+ gl_lock_lock(threadLock);
+
+ if(workerThread == (gl_thread_t)gl_thread_self()) {// Already detached?
+ threads.insert(workerThread);
+ workerThread = gl_thread_create(&ThreadManager::workerStart, 0);
+ }
+
+ gl_lock_unlock(threadLock);
+}
+
+void ThreadManager::pushWork(const sigc::slot<void> &newWork) {
+ gl_lock_lock(workLock);
+
+ work.push(newWork);
+
+ gl_cond_signal(workCond);
+ gl_lock_unlock(workLock);
+}
+
+void ThreadManager::pushIO(const sigc::slot<void> &newIO) {
+ gl_lock_lock(ioLock);
+
+ ioQueue.push(newIO);
+
+ if(!hasIO) {
+ hasIO = true;
+ ignore_value(write(ioNotifyPipe[1], "", 1));
+ }
+
+ gl_lock_unlock(ioLock);
+}
+
+void ThreadManager::runIO() {
+ gl_lock_lock(ioLock);
+
+ // Empty the pipe
+ char buf;
+ ignore_value(read(ioNotifyPipe[0], &buf, 1));
+ hasIO = false;
+
+ while(!ioQueue.empty()) {
+ sigc::slot<void> handler = ioQueue.front();
+ ioQueue.pop();
+ gl_lock_unlock(ioLock);
+
+ handler();
+
+ gl_lock_lock(ioLock);
+ }
+
+ gl_lock_unlock(ioLock);
+}
+
+
+void ThreadManager::doInit() {
+ gl_lock_init(threadLock);
+ gl_lock_init(runLock);
+
+ gl_lock_init(workLock);
+ gl_cond_init(workCond);
+
+ gl_lock_init(ioLock);
+ hasIO = false;
+
+ // TODO Error handling
+ pipe(ioNotifyPipe);
+
+ fcntl(ioNotifyPipe[0], F_SETFL, fcntl(ioNotifyPipe[0], F_GETFL) | O_NONBLOCK);
+ fcntl(ioNotifyPipe[1], F_SETFL, fcntl(ioNotifyPipe[1], F_GETFL) | O_NONBLOCK);
+
+ Net::FdManager::get()->registerFd(ioNotifyPipe[0], sigc::hide(sigc::mem_fun(this, &ThreadManager::runIO)), POLLIN);
+
+ running = true;
+
+ gl_lock_lock(threadLock);
+
+ mainThread = (gl_thread_t)gl_thread_self();
+ workerThread = gl_thread_create(&ThreadManager::workerStart, 0);
+ loggerThread = gl_thread_create(&ThreadManager::loggerStart, 0);
+
+ gl_lock_unlock(threadLock);
+}
+
+void ThreadManager::doDeinit() {
+ if(!isThisMainThread()) {
+ // TODO Critical error!!!
+ return;
+ }
+
+ // First set running = false so the worker threads quit
+ gl_lock_lock(runLock);
+ gl_lock_lock(workLock);
+
+ running = false;
+ gl_cond_signal(workCond);
+
+ gl_lock_unlock(workLock);
+ gl_lock_unlock(runLock);
+
+ // We don't have to lock threadLock as detach() won't change workerThread when running is false
+ gl_thread_join(workerThread, 0);
+
+ // Now wait for all detached threads
+ gl_lock_lock(threadLock);
+ while(!threads.empty()) {
+ gl_thread_t thread = *threads.begin();
+ gl_lock_unlock(threadLock);
+
+ gl_thread_join(thread, 0);
+
+ gl_lock_lock(threadLock);
+ threads.erase(thread);
+ }
+ gl_lock_unlock(threadLock);
+
+ // Finally, the logger thread has to die
+ Common::LogManager::get()->stopLoggerThread();
+ gl_thread_join(loggerThread, 0);
+
+ // And then we clean everything up
+ Net::FdManager::get()->unregisterFd(ioNotifyPipe[0]);
+
+ close(ioNotifyPipe[0]);
+ close(ioNotifyPipe[1]);
+
+ gl_lock_destroy(ioLock);
+
+ gl_cond_destroy(workCond);
+ gl_lock_destroy(workLock);
+
+ gl_lock_destroy(runLock);
+ gl_lock_destroy(threadLock);
+}
+
+}
+}
diff --git a/src/Net/ThreadManager.h b/src/Net/ThreadManager.h
new file mode 100644
index 0000000..9e2b3d3
--- /dev/null
+++ b/src/Net/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_COMMON_THREADMANAGER_H_
+#define MAD_COMMON_THREADMANAGER_H_
+
+#include <config.h>
+
+#include <Common/Initializable.h>
+#include <Common/LogManager.h>
+
+#include <queue>
+#include <set>
+#include <sigc++/slot.h>
+
+#include "glthread/thread.h"
+#include "glthread/lock.h"
+#include "glthread/cond.h"
+
+namespace Mad {
+namespace Net {
+
+class ThreadManager : public Common::Initializable {
+ private:
+ gl_thread_t mainThread, workerThread, loggerThread;
+ std::set<gl_thread_t> threads;
+
+ gl_lock_t threadLock;
+
+ gl_lock_t runLock;
+ bool running;
+
+ gl_lock_t workLock;
+ gl_cond_t workCond;
+ std::queue<sigc::slot<void> > work;
+
+ gl_lock_t ioLock;
+ bool hasIO;
+ int ioNotifyPipe[2];
+ std::queue<sigc::slot<void> > ioQueue;
+
+ static ThreadManager threadManager;
+
+ ThreadManager() {}
+
+ static void* workerStart(void*) {
+ threadManager.workerFunc();
+ return 0;
+ }
+
+ static void* loggerStart(void*) {
+ Common::LogManager::get()->loggerThread();
+ return 0;
+ }
+
+ void workerFunc();
+
+ void threadFinished(gl_thread_t thread) {
+ gl_lock_lock(threadLock);
+ threads.erase(thread);
+ gl_lock_unlock(threadLock);
+
+ gl_thread_join(thread, 0);
+ }
+
+ protected:
+ virtual void doInit();
+ virtual void doDeinit();
+
+ public:
+ bool isThisMainThread() {
+ return (mainThread == (gl_thread_t)gl_thread_self());
+ }
+
+ bool isThisWorkerThread() {
+ gl_lock_lock(threadLock);
+ bool ret = (workerThread == (gl_thread_t)gl_thread_self());
+ gl_lock_unlock(threadLock);
+ return ret;
+ }
+
+ void detach();
+
+ void pushWork(const sigc::slot<void> &newWork);
+ void pushIO(const sigc::slot<void> &newIO);
+
+ void runIO();
+
+ static ThreadManager* get() {
+ return &threadManager;
+ }
+};
+
+}
+}
+
+#endif /* MAD_COMMON_THREADMANAGER_H_ */