You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
389 lines
11 KiB
389 lines
11 KiB
/****************************************************************************
|
|
|
|
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.
|
|
|
|
****************************************************************************/
|
|
|
|
#ifndef TSTHREAD_H
|
|
#define TSTHREAD_H
|
|
|
|
#include <tqobject.h>
|
|
#include <tqthread.h>
|
|
#include <tqwaitcondition.h>
|
|
#include <tqdeepcopy.h>
|
|
#include <tqmutex.h>
|
|
#include <tqucomextra_p.h>
|
|
|
|
#ifdef TS_TQTHREADSTORAGE
|
|
#include <tqthreadstorage.h>
|
|
#else
|
|
#include <pthread.h>
|
|
#endif
|
|
|
|
#include "tswaitcondition.h"
|
|
|
|
// how difficult ...
|
|
template< typename T >
|
|
T TSDeepCopy( const T& t )
|
|
{
|
|
return TQDeepCopy< T >( t );
|
|
}
|
|
|
|
class TSCurrentThread;
|
|
|
|
/**
|
|
Thread class, internally based on TQThread, which intentionally doesn't have
|
|
dangerous crap like TQThread::terminate() and intentionally has useful features
|
|
like emitting signals to the main thread, currentThread() or support
|
|
for cancelling.
|
|
*/
|
|
class TSThread
|
|
: public TQObject
|
|
{
|
|
TQ_OBJECT
|
|
|
|
public:
|
|
TSThread();
|
|
virtual ~TSThread();
|
|
/**
|
|
* Starts the thread.
|
|
* @see TQThread::start()
|
|
*/
|
|
void start();
|
|
/**
|
|
* Waits for the thread to finish.
|
|
* @see TQThread::wait()
|
|
*/
|
|
void wait( unsigned long time = ULONG_MAX );
|
|
/**
|
|
* Returns true if the thread has finished.
|
|
* @see TQThread::finished()
|
|
*/
|
|
bool finished() const;
|
|
/**
|
|
* Returns true if the thread is running.
|
|
* @see TQThread::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. TQObject::sender()
|
|
* in slots is valid.
|
|
* Example:
|
|
* \code
|
|
* emitSignal( this, TQ_SIGNAL( result( int* )), &result_data );
|
|
* \endcode
|
|
* @see postSignal
|
|
* @see emitCancellableSignal
|
|
*/
|
|
void emitSignal( TQObject* obj, const char* signal );
|
|
template< typename T1 >
|
|
void emitSignal( TQObject* obj, const char* signal, const T1& p1 );
|
|
template< typename T1, typename T2 >
|
|
void emitSignal( TQObject* 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( TQObject* obj, const char* signal );
|
|
template< typename T1 >
|
|
void emitCancellableSignal( TQObject* obj, const char* signal, const T1& p1 );
|
|
template< typename T1, typename T2 >
|
|
void emitCancellableSignal( TQObject* 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. TQObject::sender() in slots is valid, unless
|
|
* the thread instance is destroyed before the signal is processed.
|
|
* @see emitSignal
|
|
*/
|
|
void postSignal( TQObject* obj, const char* signal ); // is emitted _always_ in main thread
|
|
protected:
|
|
/**
|
|
* The code to be executed in the started thread.
|
|
* @see TQThread::run()
|
|
*/
|
|
virtual void run() = 0;
|
|
signals:
|
|
/**
|
|
* Emitted after the thread is terminated.
|
|
*/
|
|
void terminated(); // is emitted _always_ in main thread
|
|
protected:
|
|
/**
|
|
* @internal
|
|
*/
|
|
void customEvent( TQCustomEvent* e );
|
|
private:
|
|
class SignalEvent
|
|
: public TQCustomEvent
|
|
{
|
|
public:
|
|
SignalEvent( const char* sig, TQObject* obj, TQUObject* o )
|
|
: TQCustomEvent( TQEvent::User ), signal( sig ), object( obj ), args( o )
|
|
{
|
|
}
|
|
const TQCString signal;
|
|
TQObject* object;
|
|
TQUObject* args;
|
|
};
|
|
class Helper
|
|
: public TQThread
|
|
{
|
|
public:
|
|
Helper( TSThread* parent );
|
|
protected:
|
|
virtual void run();
|
|
private:
|
|
TSThread* thread;
|
|
};
|
|
void executeThread();
|
|
static void initCurrentThread();
|
|
bool setCancelData( TQMutex*m, TQWaitCondition* c );
|
|
void setSignalData( TQUObject* o, int i );
|
|
void setSignalData( TQUObject* o, const TQImage& i );
|
|
void setSignalData( TQUObject* o, const TQString& s );
|
|
void setSignalData( TQUObject* o, bool b );
|
|
void setSignalData( TQUObject* o, const TQColor& c );
|
|
void setSignalData( TQUObject* o, const char* s );
|
|
void setSignalData( TQUObject* o, const TQSize& );
|
|
void emitSignalInternal( TQObject* obj, const char* signal, TQUObject* o );
|
|
void emitCancellableSignalInternal( TQObject* obj, const char* signal, TQUObject* o );
|
|
friend class Helper;
|
|
friend class TSWaitCondition;
|
|
Helper thread;
|
|
bool cancelling;
|
|
bool emit_pending;
|
|
mutable TQMutex mutex;
|
|
TQMutex signal_mutex;
|
|
TSWaitCondition signal_cond;
|
|
TQMutex* cancel_mutex;
|
|
TQWaitCondition* cancel_cond;
|
|
bool* deleted_flag;
|
|
#ifdef TS_TQTHREADSTORAGE
|
|
static TQThreadStorage< TSThread** >* current_thread;
|
|
#else
|
|
static TSCurrentThread* current_thread;
|
|
#endif
|
|
static TSThread* main_thread;
|
|
private:
|
|
TSThread( const TSThread& );
|
|
TSThread& operator=( const TSThread& );
|
|
};
|
|
|
|
#ifndef TS_TQTHREADSTORAGE
|
|
/**
|
|
* @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
|
|
{
|
|
TQMutexLocker lock( &mutex );
|
|
return cancelling;
|
|
}
|
|
|
|
#include <kdebug.h>
|
|
inline
|
|
bool TSThread::setCancelData( TQMutex* m, TQWaitCondition* c )
|
|
{
|
|
TQMutexLocker 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_TQTHREADSTORAGE
|
|
return *current_thread->localData();
|
|
#else
|
|
return current_thread->localData();
|
|
#endif
|
|
}
|
|
|
|
inline
|
|
TSThread* TSThread::mainThread()
|
|
{
|
|
return main_thread;
|
|
}
|
|
|
|
inline
|
|
void TSThread::setSignalData( TQUObject* o, int i )
|
|
{
|
|
static_QUType_int.set( o, i );
|
|
}
|
|
|
|
inline
|
|
void TSThread::setSignalData( TQUObject* o, const TQImage& i )
|
|
{
|
|
static_QUType_varptr.set( o, &i );
|
|
}
|
|
|
|
inline
|
|
void TSThread::setSignalData( TQUObject* o, const TQString& s )
|
|
{
|
|
static_QUType_TQString.set( o, s );
|
|
}
|
|
|
|
inline
|
|
void TSThread::setSignalData( TQUObject* o, bool b )
|
|
{
|
|
static_QUType_bool.set( o, b );
|
|
}
|
|
|
|
inline
|
|
void TSThread::setSignalData( TQUObject* o, const TQColor& c )
|
|
{
|
|
static_QUType_varptr.set( o, &c );
|
|
}
|
|
|
|
inline
|
|
void TSThread::setSignalData( TQUObject* o, const char* s )
|
|
{
|
|
static_QUType_charstar.set( o, s );
|
|
}
|
|
|
|
inline
|
|
void TSThread::setSignalData( TQUObject* o, const TQSize& s )
|
|
{
|
|
static_QUType_varptr.set( o, &s );
|
|
}
|
|
|
|
inline
|
|
void TSThread::emitSignal( TQObject* obj, const char* signal )
|
|
{
|
|
TQUObject o[ 1 ];
|
|
emitSignalInternal( obj, signal, o );
|
|
}
|
|
|
|
template< typename T1 >
|
|
inline
|
|
void TSThread::emitSignal( TQObject* obj, const char* signal, const T1& p1 )
|
|
{
|
|
TQUObject o[ 2 ];
|
|
setSignalData( o + 1, p1 );
|
|
emitSignalInternal( obj, signal, o );
|
|
}
|
|
|
|
template< typename T1, typename T2 >
|
|
inline
|
|
void TSThread::emitSignal( TQObject* obj, const char* signal, const T1& p1, const T2& p2 )
|
|
{
|
|
TQUObject o[ 3 ];
|
|
setSignalData( o + 1, p1 );
|
|
setSignalData( o + 2, p2 );
|
|
emitSignalInternal( obj, signal, o );
|
|
}
|
|
|
|
inline
|
|
void TSThread::emitCancellableSignal( TQObject* obj, const char* signal )
|
|
{
|
|
TQUObject o[ 1 ];
|
|
emitCancellableSignalInternal( obj, signal, o );
|
|
}
|
|
|
|
template< typename T1 >
|
|
inline
|
|
void TSThread::emitCancellableSignal( TQObject* obj, const char* signal, const T1& p1 )
|
|
{
|
|
TQUObject o[ 2 ];
|
|
setSignalData( o + 1, p1 );
|
|
emitCancellableSignalInternal( obj, signal, o );
|
|
}
|
|
|
|
template< typename T1, typename T2 >
|
|
inline
|
|
void TSThread::emitCancellableSignal( TQObject* obj, const char* signal, const T1& p1, const T2& p2 )
|
|
{
|
|
TQUObject o[ 3 ];
|
|
setSignalData( o + 1, p1 );
|
|
setSignalData( o + 2, p2 );
|
|
emitCancellableSignalInternal( obj, signal, o );
|
|
}
|
|
|
|
|
|
#endif
|