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:
@@ -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
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user