summaryrefslogtreecommitdiffstats
path: root/src/tsthread/tsthread.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/tsthread/tsthread.h')
-rw-r--r--src/tsthread/tsthread.h387
1 files changed, 387 insertions, 0 deletions
diff --git a/src/tsthread/tsthread.h b/src/tsthread/tsthread.h
new file mode 100644
index 0000000..5b98890
--- /dev/null
+++ b/src/tsthread/tsthread.h
@@ -0,0 +1,387 @@
+/****************************************************************************
+
+ Copyright (C) 2004 Lubos Lunak <[email protected]>
+
+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.
+
+****************************************************************************/
+
+#ifndef TSTHREAD_H
+#define TSTHREAD_H
+
+#include <qobject.h>
+#include <qthread.h>
+#include <qwaitcondition.h>
+#include <qdeepcopy.h>
+#include <qmutex.h>
+#include <private/qucomextra_p.h>
+
+#ifdef TS_QTHREADSTORAGE
+#include <qthreadstorage.h>
+#else
+#include <pthread.h>
+#endif
+
+#include "tswaitcondition.h"
+
+// how difficult ...
+template< typename T >
+T TSDeepCopy( const T& t )
+{
+ return QDeepCopy< T >( t );
+}
+
+class TSCurrentThread;
+
+/**
+ Thread class, internally based on QThread, which intentionally doesn't have
+ dangerous crap like QThread::terminate() and intentionally has useful features
+ like emitting signals to the main thread, currentThread() or support
+ for cancelling.
+ */
+class TSThread
+ : public QObject
+ {
+ Q_OBJECT
+ public:
+ TSThread();
+ virtual ~TSThread();
+ /**
+ * Starts the thread.
+ * @see QThread::start()
+ */
+ void start();
+ /**
+ * Waits for the thread to finish.
+ * @see QThread::wait()
+ */
+ void wait( unsigned long time = ULONG_MAX );
+ /**
+ * Returns true if the thread has finished.
+ * @see QThread::finished()
+ */
+ bool finished() const;
+ /**
+ * Returns true if the thread is running.
+ * @see QThread::running()
+ */
+ bool running() const;
+ /**
+ * Sends the thread a request to terminate.
+ * The thread must check for cancellation using testCancel()
+ * and finish execution (return from run()).
+ * @see testCancel()
+ */
+ void cancel();
+ // TODO suspend + resume?
+ /**
+ * Returns true if a request to terminate is pending.
+ * @see cancel()
+ */
+ bool testCancel() const;
+ /**
+ * Returns pointer to the current thread, i.e. thread from which
+ * this function is called.
+ */
+ static TSThread* currentThread();
+ /**
+ * Returns a pointer to the main thread. Mostly useful for currentThread().
+ */
+ static TSThread* mainThread();
+ /**
+ * Emits the specified signal in the main thread. This function returns
+ * only after all slots connected to the signal have been executed (i.e.
+ * it works like normal signal). The signal can have one pointer argument,
+ * which can be used for communication in either direction. QObject::sender()
+ * in slots is valid.
+ * Example:
+ * \code
+ * emitSignal( this, SIGNAL( result( int* )), &result_data );
+ * \endcode
+ * @see postSignal
+ * @see emitCancellableSignal
+ */
+ void emitSignal( QObject* obj, const char* signal );
+ template< typename T1 >
+ void emitSignal( QObject* obj, const char* signal, const T1& p1 );
+ template< typename T1, typename T2 >
+ void emitSignal( QObject* obj, const char* signal, const T1& p1, const T2& p2 );
+ /**
+ * This function works like emitSignal(), but additionally acts as a cancellation
+ * point, i.e. calling cancel() on the thread causes premature return.
+ * @see emitSignal
+ * @see postSignal
+ */
+ void emitCancellableSignal( QObject* obj, const char* signal );
+ template< typename T1 >
+ void emitCancellableSignal( QObject* obj, const char* signal, const T1& p1 );
+ template< typename T1, typename T2 >
+ void emitCancellableSignal( QObject* obj, const char* signal, const T1& p1, const T2& p2 );
+ /**
+ * Posts (i.e. it is not executed immediatelly like normal signals)
+ * a signal to be emitted in the main thread. The signal cannot
+ * have any parameters, use your TSThread derived class instance
+ * data members instead. QObject::sender() in slots is valid, unless
+ * the thread instance is destroyed before the signal is processed.
+ * @see emitSignal
+ */
+ void postSignal( QObject* obj, const char* signal ); // is emitted _always_ in main thread
+ protected:
+ /**
+ * The code to be executed in the started thread.
+ * @see QThread::run()
+ */
+ virtual void run() = 0;
+ signals:
+ /**
+ * Emitted after the thread is terminated.
+ */
+ void terminated(); // is emitted _always_ in main thread
+ protected:
+ /**
+ * @internal
+ */
+ void customEvent( QCustomEvent* e );
+ private:
+ class SignalEvent
+ : public QCustomEvent
+ {
+ public:
+ SignalEvent( const char* sig, QObject* obj, QUObject* o )
+ : QCustomEvent( QEvent::User ), signal( sig ), object( obj ), args( o )
+ {
+ }
+ const QCString signal;
+ QObject* object;
+ QUObject* args;
+ };
+ class Helper
+ : public QThread
+ {
+ public:
+ Helper( TSThread* parent );
+ protected:
+ virtual void run();
+ private:
+ TSThread* thread;
+ };
+ void executeThread();
+ static void initCurrentThread();
+ bool setCancelData( QMutex*m, QWaitCondition* c );
+ void setSignalData( QUObject* o, int i );
+ void setSignalData( QUObject* o, const QImage& i );
+ void setSignalData( QUObject* o, const QString& s );
+ void setSignalData( QUObject* o, bool b );
+ void setSignalData( QUObject* o, const QColor& c );
+ void setSignalData( QUObject* o, const char* s );
+ void setSignalData( QUObject* o, const QSize& );
+ void emitSignalInternal( QObject* obj, const char* signal, QUObject* o );
+ void emitCancellableSignalInternal( QObject* obj, const char* signal, QUObject* o );
+ friend class Helper;
+ friend class TSWaitCondition;
+ Helper thread;
+ bool cancelling;
+ bool emit_pending;
+ mutable QMutex mutex;
+ QMutex signal_mutex;
+ TSWaitCondition signal_cond;
+ QMutex* cancel_mutex;
+ QWaitCondition* cancel_cond;
+ bool* deleted_flag;
+#ifdef TS_QTHREADSTORAGE
+ static QThreadStorage< TSThread** >* current_thread;
+#else
+ static TSCurrentThread* current_thread;
+#endif
+ static TSThread* main_thread;
+ private:
+ TSThread( const TSThread& );
+ TSThread& operator=( const TSThread& );
+ };
+
+#ifndef TS_QTHREADSTORAGE
+/**
+ * @internal
+ */
+class TSCurrentThread
+ {
+ public:
+ TSCurrentThread();
+ ~TSCurrentThread();
+ TSThread* localData() const;
+ void setLocalData( TSThread* t );
+ private:
+ pthread_key_t key;
+ };
+
+
+inline TSCurrentThread::TSCurrentThread()
+ {
+ pthread_key_create( &key, NULL );
+ }
+
+inline TSCurrentThread::~TSCurrentThread()
+ {
+ pthread_key_delete( key );
+ }
+
+inline void TSCurrentThread::setLocalData( TSThread* t )
+ {
+ pthread_setspecific( key, t );
+ }
+
+inline TSThread* TSCurrentThread::localData() const
+ {
+ return static_cast< TSThread* >( pthread_getspecific( key ));
+ }
+#endif
+
+inline
+bool TSThread::testCancel() const
+ {
+ QMutexLocker lock( &mutex );
+ return cancelling;
+ }
+
+#include <kdebug.h>
+inline
+bool TSThread::setCancelData( QMutex* m, QWaitCondition* c )
+ {
+ QMutexLocker lock( &mutex );
+ if( cancelling && m != NULL )
+ return false;
+ cancel_mutex = m;
+ cancel_cond = c;
+ return true;
+ }
+
+inline
+TSThread* TSThread::currentThread()
+ {
+ if( current_thread == NULL )
+ initCurrentThread();
+#ifdef TS_QTHREADSTORAGE
+ return *current_thread->localData();
+#else
+ return current_thread->localData();
+#endif
+ }
+
+inline
+TSThread* TSThread::mainThread()
+ {
+ return main_thread;
+ }
+
+inline
+void TSThread::setSignalData( QUObject* o, int i )
+ {
+ static_QUType_int.set( o, i );
+ }
+
+inline
+void TSThread::setSignalData( QUObject* o, const QImage& i )
+ {
+ static_QUType_varptr.set( o, &i );
+ }
+
+inline
+void TSThread::setSignalData( QUObject* o, const QString& s )
+ {
+ static_QUType_QString.set( o, s );
+ }
+
+inline
+void TSThread::setSignalData( QUObject* o, bool b )
+ {
+ static_QUType_bool.set( o, b );
+ }
+
+inline
+void TSThread::setSignalData( QUObject* o, const QColor& c )
+ {
+ static_QUType_varptr.set( o, &c );
+ }
+
+inline
+void TSThread::setSignalData( QUObject* o, const char* s )
+ {
+ static_QUType_charstar.set( o, s );
+ }
+
+inline
+void TSThread::setSignalData( QUObject* o, const QSize& s )
+ {
+ static_QUType_varptr.set( o, &s );
+ }
+
+inline
+void TSThread::emitSignal( QObject* obj, const char* signal )
+ {
+ QUObject o[ 1 ];
+ emitSignalInternal( obj, signal, o );
+ }
+
+template< typename T1 >
+inline
+void TSThread::emitSignal( QObject* obj, const char* signal, const T1& p1 )
+ {
+ QUObject o[ 2 ];
+ setSignalData( o + 1, p1 );
+ emitSignalInternal( obj, signal, o );
+ }
+
+template< typename T1, typename T2 >
+inline
+void TSThread::emitSignal( QObject* obj, const char* signal, const T1& p1, const T2& p2 )
+ {
+ QUObject o[ 3 ];
+ setSignalData( o + 1, p1 );
+ setSignalData( o + 2, p2 );
+ emitSignalInternal( obj, signal, o );
+ }
+
+inline
+void TSThread::emitCancellableSignal( QObject* obj, const char* signal )
+ {
+ QUObject o[ 1 ];
+ emitCancellableSignalInternal( obj, signal, o );
+ }
+
+template< typename T1 >
+inline
+void TSThread::emitCancellableSignal( QObject* obj, const char* signal, const T1& p1 )
+ {
+ QUObject o[ 2 ];
+ setSignalData( o + 1, p1 );
+ emitCancellableSignalInternal( obj, signal, o );
+ }
+
+template< typename T1, typename T2 >
+inline
+void TSThread::emitCancellableSignal( QObject* obj, const char* signal, const T1& p1, const T2& p2 )
+ {
+ QUObject o[ 3 ];
+ setSignalData( o + 1, p1 );
+ setSignalData( o + 2, p2 );
+ emitCancellableSignalInternal( obj, signal, o );
+ }
+
+
+#endif