summaryrefslogtreecommitdiffstats
path: root/src/Net/ThreadManager.cpp
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/ThreadManager.cpp
parent5bf3e2229015d93808bb0c2f4729c2c4f4da414e (diff)
downloadmad-8324b947487f72fd8cfc439ea5ae5bd1187fff1b.tar
mad-8324b947487f72fd8cfc439ea5ae5bd1187fff1b.zip
Exception und ThreadHandler nach Net verschoben
Diffstat (limited to 'src/Net/ThreadManager.cpp')
-rw-r--r--src/Net/ThreadManager.cpp215
1 files changed, 215 insertions, 0 deletions
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);
+}
+
+}
+}