summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Common/ThreadManager.cpp52
-rw-r--r--src/Common/ThreadManager.h21
2 files changed, 66 insertions, 7 deletions
diff --git a/src/Common/ThreadManager.cpp b/src/Common/ThreadManager.cpp
index 6b2606c..c0f4d74 100644
--- a/src/Common/ThreadManager.cpp
+++ b/src/Common/ThreadManager.cpp
@@ -19,6 +19,8 @@
#include "ThreadManager.h"
+#include <sigc++/bind.h>
+
namespace Mad {
namespace Common {
@@ -53,6 +55,31 @@ void ThreadManager::workerFunc() {
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()) {
+ Logger::log(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) {
@@ -66,18 +93,20 @@ void ThreadManager::pushWork(const sigc::slot<void> &newWork) {
void ThreadManager::doInit() {
+ gl_lock_init(threadLock);
gl_lock_init(runLock);
gl_lock_init(workLock);
gl_cond_init(workCond);
- gl_lock_lock(runLock);
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(runLock);
+ gl_lock_unlock(threadLock);
}
void ThreadManager::doDeinit() {
@@ -95,14 +124,29 @@ void ThreadManager::doDeinit() {
gl_lock_unlock(workLock);
gl_lock_unlock(runLock);
- LogManager::get()->stopLoggerThread();
-
+ // 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);
+
+ LogManager::get()->stopLoggerThread();
gl_thread_join(loggerThread, 0);
gl_cond_destroy(workCond);
gl_lock_destroy(workLock);
gl_lock_destroy(runLock);
+ gl_lock_destroy(threadLock);
}
}
diff --git a/src/Common/ThreadManager.h b/src/Common/ThreadManager.h
index 07ab196..6e8616f 100644
--- a/src/Common/ThreadManager.h
+++ b/src/Common/ThreadManager.h
@@ -41,6 +41,8 @@ class ThreadManager : public Initializable {
gl_thread_t mainThread, workerThread, loggerThread;
std::set<gl_thread_t> threads;
+ gl_lock_t threadLock;
+
gl_lock_t runLock;
bool running;
@@ -64,19 +66,32 @@ class ThreadManager : public Initializable {
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() const {
+ bool isThisMainThread() {
return (mainThread == (gl_thread_t)gl_thread_self());
}
- bool isThisWorkerThread() const {
- return (workerThread == (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);
static ThreadManager* get() {