1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-08-10 08:04:25 +02:00

don't assume that exit() will clean up the stack

This commit is contained in:
Leo Franchi
2011-04-06 21:34:59 -04:00
parent ed0574f6b7
commit db7b2d2523

View File

@@ -11,8 +11,8 @@
KDSingleApplicationGuard::Instance::Instance( const QStringList& args, qint64 p ) KDSingleApplicationGuard::Instance::Instance( const QStringList& args, qint64 p )
: arguments( args ), : arguments( args ),
pid( p ) pid( p )
{ {
} }
@@ -61,31 +61,31 @@ void KDSingleApplicationGuard::timerEvent( QTimerEvent* )
using namespace kdtools; using namespace kdtools;
/*! /*!
\class KDSingleApplicationGuard KDSingleApplicationGuard * \class KDSingleApplicationGuard KDSingleApplicationGuard
\brief A guard to protect an application from having several instances. * \brief A guard to protect an application from having several instances.
*
KDSingleApplicationGuard can be used to make sure only one instance of an * KDSingleApplicationGuard can be used to make sure only one instance of an
application is running at the same time. * application is running at the same time.
*
\note As KDSingleApplicationGuard uses QSharedMemory Qt 4.4 or later is required * \note As KDSingleApplicationGuard uses QSharedMemory Qt 4.4 or later is required
*/ */
/*! /*!
\fn void KDSingleApplicationGuard::instanceStarted() * \fn void KDSingleApplicationGuard::instanceStarted()
This signal is emitted by the primary instance when ever one other * This signal is emitted by the primary instance when ever one other
instance was started. * instance was started.
*/ */
/*! /*!
\fn void KDSingleApplicationGuard::instanceExited() * \fn void KDSingleApplicationGuard::instanceExited()
This signal is emitted by the primary instance when ever one other * This signal is emitted by the primary instance when ever one other
instance was exited. * instance was exited.
*/ */
/*! /*!
\fn void KDSingleApplicationGuard::becamePrimaryInstance() * \fn void KDSingleApplicationGuard::becamePrimaryInstance()
This signal is emitted, when the current running application gets the new * This signal is emitted, when the current running application gets the new
primary application. The old primary application has quit. * primary application. The old primary application has quit.
*/ */
enum Command enum Command
@@ -105,8 +105,8 @@ Q_DECLARE_OPERATORS_FOR_FLAGS( Commands )
struct ProcessInfo struct ProcessInfo
{ {
explicit ProcessInfo( Command c = FreeInstance, const QStringList& arguments = QStringList(), qint64 p = -1 ) explicit ProcessInfo( Command c = FreeInstance, const QStringList& arguments = QStringList(), qint64 p = -1 )
: command( c ), : command( c ),
pid( p ) pid( p )
{ {
std::fill_n( commandline, KDSINGLEAPPLICATIONGUARD_MAX_COMMAND_LINE, '\0' ); std::fill_n( commandline, KDSINGLEAPPLICATIONGUARD_MAX_COMMAND_LINE, '\0' );
@@ -149,7 +149,7 @@ struct ProcessInfo
bool operator==( const ProcessInfo& lhs, const ProcessInfo& rhs ) bool operator==( const ProcessInfo& lhs, const ProcessInfo& rhs )
{ {
return lhs.command == rhs.command && return lhs.command == rhs.command &&
::memcmp( lhs.commandline, rhs.commandline, KDSINGLEAPPLICATIONGUARD_MAX_COMMAND_LINE ) == 0; ::memcmp( lhs.commandline, rhs.commandline, KDSINGLEAPPLICATIONGUARD_MAX_COMMAND_LINE ) == 0;
} }
bool operator!=( const ProcessInfo& lhs, const ProcessInfo& rhs ) bool operator!=( const ProcessInfo& lhs, const ProcessInfo& rhs )
@@ -158,21 +158,21 @@ bool operator!=( const ProcessInfo& lhs, const ProcessInfo& rhs )
} }
/*! /*!
This struct contains information about the managed process system. * This struct contains information about the managed process system.
\internal * \internal
*/ */
struct InstanceRegister struct InstanceRegister
{ {
InstanceRegister( KDSingleApplicationGuard::Policy policy = KDSingleApplicationGuard::NoPolicy ) InstanceRegister( KDSingleApplicationGuard::Policy policy = KDSingleApplicationGuard::NoPolicy )
: policy( policy ) : policy( policy )
{ {
std::fill_n( info, KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES, ProcessInfo() ); std::fill_n( info, KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES, ProcessInfo() );
::memcpy( magicCookie, "kdsingleapp", 12 ); ::memcpy( magicCookie, "kdsingleapp", 12 );
} }
/*! /*!
Returns wheter this register was properly initialized by the first instance. * Returns wheter this register was properly initialized by the first instance.
*/ */
bool isValid() const bool isValid() const
{ {
return ::strcmp( magicCookie, "kdsingleapp" ) == 0; return ::strcmp( magicCookie, "kdsingleapp" ) == 0;
@@ -192,18 +192,18 @@ bool operator==( const InstanceRegister& lhs, const InstanceRegister& rhs )
if( lhs.info[ i ] != rhs.info[ i ] ) if( lhs.info[ i ] != rhs.info[ i ] )
return false; return false;
return true; return true;
} }
/*! /*!
\internal * \internal
*/ */
class KDSingleApplicationGuard::Private class KDSingleApplicationGuard::Private
{ {
public: public:
Private( KDSingleApplicationGuard* qq ) Private( KDSingleApplicationGuard* qq )
: q( qq ), : q( qq ),
id( -1 ) id( -1 )
{ {
if( primaryInstance == 0 ) if( primaryInstance == 0 )
primaryInstance = q; primaryInstance = q;
@@ -258,14 +258,14 @@ void SIGINT_handler( int sig )
#endif #endif
/*! /*!
Creates a new KDSingleApplicationGuard guarding \a parent from mulitply instances. * Creates a new KDSingleApplicationGuard guarding \a parent from mulitply instances.
If \a policy is AutoKillOtherInstances (the default), all instances, which try to start, * If \a policy is AutoKillOtherInstances (the default), all instances, which try to start,
are killed automatically and instanceStarted() is emitted. * are killed automatically and instanceStarted() is emitted.
If \a policy is NoPolicy, the other instance will run and instanceStarted() is emitted. * If \a policy is NoPolicy, the other instance will run and instanceStarted() is emitted.
*/ */
KDSingleApplicationGuard::KDSingleApplicationGuard( QCoreApplication* parent, Policy policy ) KDSingleApplicationGuard::KDSingleApplicationGuard( QCoreApplication* parent, Policy policy )
: QObject( parent ), : QObject( parent ),
d( new Private( this ) ) d( new Private( this ) )
{ {
const QString name = parent->applicationName(); const QString name = parent->applicationName();
Q_ASSERT_X( !name.isEmpty(), "KDSingleApplicationGuard::KDSingleApplicationGuard", "applicationName must not be emty" ); Q_ASSERT_X( !name.isEmpty(), "KDSingleApplicationGuard::KDSingleApplicationGuard", "applicationName must not be emty" );
@@ -273,10 +273,10 @@ KDSingleApplicationGuard::KDSingleApplicationGuard( QCoreApplication* parent, Po
// if another instance crashed, the shared memory segment is still there on Unix // if another instance crashed, the shared memory segment is still there on Unix
// the following lines trigger deletion in that case // the following lines trigger deletion in that case
#ifndef Q_WS_WIN #ifndef Q_WS_WIN
d->mem.attach(); d->mem.attach();
d->mem.detach(); d->mem.detach();
#endif #endif
d->policy = policy; d->policy = policy;
@@ -298,52 +298,57 @@ KDSingleApplicationGuard::KDSingleApplicationGuard( QCoreApplication* parent, Po
} }
} }
bool killMyself = false;
KDLockedSharedMemoryPointer< InstanceRegister > instances( &d->mem );
if( !created )
{ {
// we're _not_ the first instance KDLockedSharedMemoryPointer< InstanceRegister > instances( &d->mem );
// but the
bool killOurSelf = false;
// find a new slot... if( !created )
d->id = std::find( instances->info, instances->info + KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES, ProcessInfo() ) - instances->info;
ProcessInfo& info = instances->info[ d->id ];
info = ProcessInfo( NewInstance, parent->arguments(), QCoreApplication::applicationPid() );
killOurSelf = instances->policy == AutoKillOtherInstances;
d->policy = instances->policy;
// but the signal that we tried to start was sent to the primary application
if( killOurSelf )
{ {
info.command |= ExitedInstance; // we're _not_ the first instance
exit( 1 ); // but the
bool killOurSelf = false;
// find a new slot...
d->id = std::find( instances->info, instances->info + KDSINGLEAPPLICATIONGUARD_NUMBER_OF_PROCESSES, ProcessInfo() ) - instances->info;
ProcessInfo& info = instances->info[ d->id ];
info = ProcessInfo( NewInstance, parent->arguments(), QCoreApplication::applicationPid() );
killOurSelf = instances->policy == AutoKillOtherInstances;
d->policy = instances->policy;
// but the signal that we tried to start was sent to the primary application
if( killOurSelf )
{
info.command |= ExitedInstance;
killMyself = true;
}
}
else
{
// ok.... we are the first instance
InstanceRegister reg( policy ); // create a new list
d->id = 0; // our id = 0
// and we've no command
reg.info[ 0 ] = ProcessInfo( NoCommand, parent->arguments(), QCoreApplication::applicationPid() );
*instances = reg; // push this is the process list into shared memory
} }
} }
else // call exit after we let the locker release our memory, as exit() is not guaranteed to clean up objects on the stack
{ if ( killMyself )
// ok.... we are the first instance exit( 1 );
InstanceRegister reg( policy ); // create a new list
d->id = 0; // our id = 0
// and we've no command
reg.info[ 0 ] = ProcessInfo( NoCommand, parent->arguments(), QCoreApplication::applicationPid() );
*instances = reg; // push this is the process list into shared memory
}
#ifndef Q_WS_WIN #ifndef Q_WS_WIN
::signal( SIGINT, SIGINT_handler ); ::signal( SIGINT, SIGINT_handler );
#endif #endif
// now listen for commands // now listen for commands
startTimer( 250 ); startTimer( 250 );
} }
/*! /*!
Destroys this SingleApplicationGuard. * Destroys this SingleApplicationGuard.
If this instance has been the primary instance and no other instance is existing anymore, * If this instance has been the primary instance and no other instance is existing anymore,
the application is shut down completely. Otherwise the destructor selects another instance to * the application is shut down completely. Otherwise the destructor selects another instance to
be the primary instances. * be the primary instances.
*/ */
KDSingleApplicationGuard::~KDSingleApplicationGuard() KDSingleApplicationGuard::~KDSingleApplicationGuard()
{ {
@@ -354,14 +359,14 @@ KDSingleApplicationGuard::~KDSingleApplicationGuard()
} }
/*! /*!
\property KDSingleApplicationGuard::primaryInstance * \property KDSingleApplicationGuard::primaryInstance
Determines wheter this instance is the primary instance. * Determines wheter this instance is the primary instance.
The primary instance is the first instance which was started or an instance which * The primary instance is the first instance which was started or an instance which
got selected by KDSingleApplicationGuard's destructor, when the primary instance was * got selected by KDSingleApplicationGuard's destructor, when the primary instance was
shut down. * shut down.
*
Get this property's value using %isPrimaryInstance(), and monitor changes to it * Get this property's value using %isPrimaryInstance(), and monitor changes to it
using becamePrimaryInstance(). * using becamePrimaryInstance().
*/ */
bool KDSingleApplicationGuard::isPrimaryInstance() const bool KDSingleApplicationGuard::isPrimaryInstance() const
{ {
@@ -369,12 +374,12 @@ bool KDSingleApplicationGuard::isPrimaryInstance() const
} }
/*! /*!
\property KDSingleApplicationGuard::Policy * \property KDSingleApplicationGuard::Policy
Specifies the policy KDSingleApplicationGuard is using when new instances are started. * Specifies the policy KDSingleApplicationGuard is using when new instances are started.
This can only be set in the primary instance. * This can only be set in the primary instance.
*
Get this property's value using %policy(), set it using %setPolicy(), and monitor changes * Get this property's value using %policy(), set it using %setPolicy(), and monitor changes
to it using policyChanged(). * to it using policyChanged().
*/ */
KDSingleApplicationGuard::Policy KDSingleApplicationGuard::policy() const KDSingleApplicationGuard::Policy KDSingleApplicationGuard::policy() const
{ {
@@ -394,7 +399,7 @@ void KDSingleApplicationGuard::setPolicy( Policy policy )
} }
/*! /*!
Returns a list of all currently running instances. * Returns a list of all currently running instances.
*/ */
QList< KDSingleApplicationGuard::Instance > KDSingleApplicationGuard::instances() const QList< KDSingleApplicationGuard::Instance > KDSingleApplicationGuard::instances() const
{ {
@@ -410,9 +415,9 @@ QList< KDSingleApplicationGuard::Instance > KDSingleApplicationGuard::instances(
} }
/*! /*!
Shuts down all other instances. This can only be called from the * Shuts down all other instances. This can only be called from the
the primary instance. * the primary instance.
Shut down is done gracefully via QCoreApplication::quit(). * Shut down is done gracefully via QCoreApplication::quit().
*/ */
void KDSingleApplicationGuard::shutdownOtherInstances() void KDSingleApplicationGuard::shutdownOtherInstances()
{ {
@@ -426,9 +431,9 @@ void KDSingleApplicationGuard::shutdownOtherInstances()
} }
/*! /*!
Kills all other instances. This can only be called from the * Kills all other instances. This can only be called from the
the primary instance. * the primary instance.
Killing is done via exit(1) * Killing is done via exit(1)
*/ */
void KDSingleApplicationGuard::killOtherInstances() void KDSingleApplicationGuard::killOtherInstances()
{ {
@@ -442,7 +447,7 @@ void KDSingleApplicationGuard::killOtherInstances()
} }
/*! /*!
\reimp * \reimp
*/ */
void KDSingleApplicationGuard::timerEvent( QTimerEvent* event ) void KDSingleApplicationGuard::timerEvent( QTimerEvent* event )
{ {
@@ -615,7 +620,7 @@ KDAB_UNITTEST_SIMPLE( KDSingleApplicationGuard, "kdcoretools" ) {
delete spy3; delete spy3;
delete guard3; delete guard3;
} }
#endif // KDTOOLSCORE_UNITTESTS #endif // KDTOOLSCORE_UNITTESTS