From 8324b947487f72fd8cfc439ea5ae5bd1187fff1b Mon Sep 17 00:00:00 2001 From: Matthias Schiffer Date: Wed, 6 May 2009 17:39:30 +0200 Subject: Exception und ThreadHandler nach Net verschoben --- src/Net/ClientConnection.cpp | 8 +- src/Net/ClientConnection.h | 4 +- src/Net/Exception.cpp | 63 +++++++++++++ src/Net/Exception.h | 61 ++++++++++++ src/Net/IPAddress.cpp | 10 +- src/Net/IPAddress.h | 6 +- src/Net/Listener.cpp | 10 +- src/Net/Listener.h | 3 +- src/Net/Makefile.am | 6 +- src/Net/Makefile.in | 15 ++- src/Net/ServerConnection.h | 1 - src/Net/ThreadManager.cpp | 215 +++++++++++++++++++++++++++++++++++++++++++ src/Net/ThreadManager.h | 113 +++++++++++++++++++++++ 13 files changed, 487 insertions(+), 28 deletions(-) create mode 100644 src/Net/Exception.cpp create mode 100644 src/Net/Exception.h create mode 100644 src/Net/ThreadManager.cpp create mode 100644 src/Net/ThreadManager.h (limited to 'src/Net') 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 +#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 + * + * 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 . + */ + +#include "Exception.h" + +#include +#include + +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 + * + * 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 . + */ + +#ifndef MAD_NET_EXCEPTION_H_ +#define MAD_NET_EXCEPTION_H_ + +#include + +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 +#include "Exception.h" #include #include @@ -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 #include #include @@ -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 #include 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 + * + * 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 . + */ + +#include "ThreadManager.h" +#include "FdManager.h" + +#include +#include +#include + +#include + +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 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 &newWork) { + gl_lock_lock(workLock); + + work.push(newWork); + + gl_cond_signal(workCond); + gl_lock_unlock(workLock); +} + +void ThreadManager::pushIO(const sigc::slot &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 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 + * + * 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 . + */ + +#ifndef MAD_COMMON_THREADMANAGER_H_ +#define MAD_COMMON_THREADMANAGER_H_ + +#include + +#include +#include + +#include +#include +#include + +#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 threads; + + gl_lock_t threadLock; + + gl_lock_t runLock; + bool running; + + gl_lock_t workLock; + gl_cond_t workCond; + std::queue > work; + + gl_lock_t ioLock; + bool hasIO; + int ioNotifyPipe[2]; + std::queue > 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 &newWork); + void pushIO(const sigc::slot &newIO); + + void runIO(); + + static ThreadManager* get() { + return &threadManager; + } +}; + +} +} + +#endif /* MAD_COMMON_THREADMANAGER_H_ */ -- cgit v1.2.3