summaryrefslogtreecommitdiffstats
path: root/src/tsthread/tsthread.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/tsthread/tsthread.cpp')
-rw-r--r--src/tsthread/tsthread.cpp194
1 files changed, 194 insertions, 0 deletions
diff --git a/src/tsthread/tsthread.cpp b/src/tsthread/tsthread.cpp
new file mode 100644
index 0000000..16b4538
--- /dev/null
+++ b/src/tsthread/tsthread.cpp
@@ -0,0 +1,194 @@
+/****************************************************************************
+
+ Copyright (C) 2004 Lubos Lunak <l.lunak@kde.org>
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+****************************************************************************/
+
+#include "tsthread.h"
+
+#include <qapplication.h>
+#include <qmetaobject.h>
+#include <kdebug.h>
+#include <qguardedptr.h>
+
+#include <assert.h>
+
+#ifdef TS_QTHREADSTORAGE
+QThreadStorage< TSThread** >* TSThread::current_thread;
+#else
+TSCurrentThread* TSThread::current_thread;
+#endif
+TSThread* TSThread::main_thread = NULL;
+
+class TSMainThread
+ : public TSThread
+ {
+ protected:
+ virtual void run() { assert( false ); }
+ };
+
+TSThread::Helper::Helper( TSThread* parent )
+ : thread( parent )
+ {
+ assert( parent );
+ }
+
+void TSThread::Helper::run()
+ {
+ thread->executeThread();
+ }
+
+
+TSThread::TSThread()
+ : thread( this )
+ , cancelling( false )
+ , emit_pending( false )
+ , cancel_mutex( NULL )
+ , cancel_cond( NULL )
+ , deleted_flag( NULL )
+ {
+ }
+
+TSThread::~TSThread()
+ {
+ if( deleted_flag != NULL )
+ *deleted_flag = true;
+ }
+
+void TSThread::start()
+ {
+ if( current_thread == NULL )
+ initCurrentThread();
+ thread.start();
+ }
+
+void TSThread::cancel()
+ {
+ QMutexLocker lock( &mutex );
+ cancelling = true;
+ if( cancel_mutex != NULL )
+ {
+ QMutexLocker lock( cancel_mutex );
+ cancel_cond->wakeAll();
+ }
+ }
+
+void TSThread::wait( unsigned long time )
+ {
+ thread.wait( time );
+ }
+
+bool TSThread::finished() const
+ {
+ return thread.finished();
+ }
+
+bool TSThread::running() const
+ {
+ return thread.running();
+ }
+
+void TSThread::initCurrentThread()
+ {
+#ifdef TS_QTHREADSTORAGE
+ current_thread = new QThreadStorage< TSThread** >();
+ typedef TSThread* TSThreadPtr;
+ // set pointer for main thread (this must be main thread)
+ current_thread->setLocalData( new TSThreadPtr( NULL )); // TODO NULL ?
+#else
+ current_thread = new TSCurrentThread();
+ main_thread = new TSMainThread;
+ // set pointer for main thread (this must be main thread)
+ current_thread->setLocalData( main_thread );
+#endif
+ }
+
+void TSThread::executeThread()
+ {
+#ifdef TS_QTHREADSTORAGE
+ // store dynamically allocated pointer, so that
+ // QThreadStorage deletes the pointer and not TSThread
+ typedef TSThread* TSThreadPtr;
+ current_thread->setLocalData( new TSThreadPtr( this ));
+#else
+ current_thread->setLocalData( this );
+#endif
+ run();
+ postSignal( this, NULL ); // = terminated()
+ }
+
+void TSThread::postSignal( QObject* obj, const char* signal )
+ {
+ assert( currentThread() == this );
+ qApp->postEvent( this, new SignalEvent( signal, obj, NULL ));
+ }
+
+void TSThread::emitSignalInternal( QObject* obj, const char* signal, QUObject* o )
+ {
+ assert( currentThread() == this );
+ QMutexLocker locker( &signal_mutex );
+ emit_pending = true;
+ qApp->postEvent( this, new SignalEvent( signal, obj, o ));
+ while( emit_pending )
+ signal_cond.wait( &signal_mutex );
+ }
+
+void TSThread::emitCancellableSignalInternal( QObject* obj, const char* signal, QUObject* o )
+ {
+ assert( currentThread() == this );
+ // can't use this->mutex, because its locking will be triggered by TSWaitCondition
+ QMutexLocker locker( &signal_mutex );
+ emit_pending = true;
+ qApp->postEvent( this, new SignalEvent( signal, obj, o ));
+ while( emit_pending && !testCancel())
+ signal_cond.cancellableWait( &signal_mutex );
+ emit_pending = false; // in case of cancel
+ }
+
+void TSThread::customEvent( QCustomEvent* ev )
+ {
+ SignalEvent* e = static_cast< SignalEvent* >( ev );
+ if( e->signal.isEmpty()) // = terminated()
+ { // threadExecute() finishes before the actual thread terminates
+ if( !finished())
+ wait();
+ emit terminated();
+ return;
+ }
+ bool deleted = false;
+ deleted_flag = &deleted; // this is like QGuardedPtr for self, but faster
+ int signal_id = e->object->metaObject()->findSignal( normalizeSignalSlot( e->signal ).data() + 1, true );
+ if( signal_id >= 0 )
+ e->object->qt_emit( signal_id, e->args );
+ else
+ kdWarning() << "Cannot emit signal \"" << e->signal << "\"." << endl;
+ if( deleted ) // some slot deleted 'this'
+ return;
+ deleted_flag = NULL;
+ QMutexLocker locker( &signal_mutex );
+ if( emit_pending )
+ {
+ emit_pending = false;
+ signal_cond.wakeOne();
+ }
+ }
+
+#include "tsthread.moc"