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.
195 lines
5.5 KiB
195 lines
5.5 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.
|
|
|
|
****************************************************************************/
|
|
|
|
#include "tsthread.h"
|
|
|
|
#include <tqapplication.h>
|
|
#include <tqmetaobject.h>
|
|
#include <kdebug.h>
|
|
#include <tqguardedptr.h>
|
|
|
|
#include <assert.h>
|
|
|
|
#ifdef TS_TQTHREADSTORAGE
|
|
TQThreadStorage< 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()
|
|
{
|
|
TQMutexLocker lock( &mutex );
|
|
cancelling = true;
|
|
if( cancel_mutex != NULL )
|
|
{
|
|
TQMutexLocker 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_TQTHREADSTORAGE
|
|
current_thread = new TQThreadStorage< 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_TQTHREADSTORAGE
|
|
// store dynamically allocated pointer, so that
|
|
// TQThreadStorage 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( TQObject* obj, const char* signal )
|
|
{
|
|
assert( currentThread() == this );
|
|
tqApp->postEvent( this, new SignalEvent( signal, obj, NULL ));
|
|
}
|
|
|
|
void TSThread::emitSignalInternal( TQObject* obj, const char* signal, TQUObject* o )
|
|
{
|
|
assert( currentThread() == this );
|
|
TQMutexLocker locker( &signal_mutex );
|
|
emit_pending = true;
|
|
tqApp->postEvent( this, new SignalEvent( signal, obj, o ));
|
|
while( emit_pending )
|
|
signal_cond.wait( &signal_mutex );
|
|
}
|
|
|
|
void TSThread::emitCancellableSignalInternal( TQObject* obj, const char* signal, TQUObject* o )
|
|
{
|
|
assert( currentThread() == this );
|
|
// can't use this->mutex, because its locking will be triggered by TSWaitCondition
|
|
TQMutexLocker locker( &signal_mutex );
|
|
emit_pending = true;
|
|
tqApp->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( TQCustomEvent* 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 TQGuardedPtr for self, but faster
|
|
int signal_id = e->object->metaObject()->findSignal( normalizeSignalSlot( e->signal ).data() + 1, true );
|
|
if( signal_id >= 0 )
|
|
e->object->tqt_emit( signal_id, e->args );
|
|
else
|
|
kdWarning() << "Cannot emit signal \"" << e->signal << "\"." << endl;
|
|
if( deleted ) // some slot deleted 'this'
|
|
return;
|
|
deleted_flag = NULL;
|
|
TQMutexLocker locker( &signal_mutex );
|
|
if( emit_pending )
|
|
{
|
|
emit_pending = false;
|
|
signal_cond.wakeOne();
|
|
}
|
|
}
|
|
|
|
#include "tsthread.moc"
|