Commit 49827e90 authored by Matěj Laitl's avatar Matěj Laitl
Browse files

IpodCollection: don't crash when ejecting while the db is being written

Piotr, I think this solves your crash, can you please pull, rebuild &
re-test? Let me know whether the crash is fixed or not.

BUG: 301208
FIXED-IN: 2.6
parent 4128cf8d
......@@ -8,6 +8,7 @@ VERSION 2.6
argument.
BUGFIXES:
* Don't crash if iPod's eject button is hit twice. (BR 301208)
* Don't crash even if the iPod is connected and quickly ejected. (BR 301166)
VERSION 2.6-Beta 1
......
......@@ -339,15 +339,26 @@ IpodCollection::trackForUidUrl( const QString &uidUrl )
void
IpodCollection::slotDestroy()
{
// guard against user hitting the button twice or hitting it while there is another
// write database job alreaddy running
if( m_writeDatabaseJob )
{
IpodWriteDatabaseJob *job = m_writeDatabaseJob.data();
// don't create duplicate connections:
disconnect( job, SIGNAL(destroyed(QObject*)), this, SLOT(slotRemove()) );
disconnect( job, SIGNAL(destroyed(QObject*)), this, SLOT(slotPerformTeardownAndRemove()) );
connect( job, SIGNAL(destroyed(QObject*)), SLOT(slotRemove()) );
}
// this is not racy: slotDestroy() is delivered to main thread, the timer fires in the
// same thread
if( m_writeDatabaseTimer.isActive() )
else if( m_writeDatabaseTimer.isActive() )
{
// write database in a thread so that it need not be written in destructor
m_writeDatabaseTimer.stop();
IpodWriteDatabaseJob *job = new IpodWriteDatabaseJob( this );
connect( job, SIGNAL(done(ThreadWeaver::Job*)), SLOT(slotRemove()) );
m_writeDatabaseJob = job;
connect( job, SIGNAL(done(ThreadWeaver::Job*)), job, SLOT(deleteLater()) );
connect( job, SIGNAL(destroyed(QObject*)), SLOT(slotRemove()) );
ThreadWeaver::Weaver::instance()->enqueue( job );
}
else
......@@ -357,15 +368,26 @@ IpodCollection::slotDestroy()
void
IpodCollection::slotEject()
{
// guard against user hitting the button twice or hitting it while there is another
// write database job alreaddy running
if( m_writeDatabaseJob )
{
IpodWriteDatabaseJob *job = m_writeDatabaseJob.data();
// don't create duplicate connections:
disconnect( job, SIGNAL(destroyed(QObject*)), this, SLOT(slotRemove()) );
disconnect( job, SIGNAL(destroyed(QObject*)), this, SLOT(slotPerformTeardownAndRemove()) );
connect( job, SIGNAL(destroyed(QObject*)), SLOT(slotPerformTeardownAndRemove()) );
}
// this is not racy: slotEject() is delivered to main thread, the timer fires in the
// same thread
if( m_writeDatabaseTimer.isActive() )
else if( m_writeDatabaseTimer.isActive() )
{
// write database now because iPod will be already unmounted in destructor
m_writeDatabaseTimer.stop();
IpodWriteDatabaseJob *job = new IpodWriteDatabaseJob( this );
connect( job, SIGNAL(done(ThreadWeaver::Job*)), SLOT(slotPerformTeardownAndRemove()) );
m_writeDatabaseJob = job;
connect( job, SIGNAL(done(ThreadWeaver::Job*)), job, SLOT(deleteLater()) );
connect( job, SIGNAL(destroyed(QObject*)), SLOT(slotPerformTeardownAndRemove()) );
ThreadWeaver::Weaver::instance()->enqueue( job );
}
else
......@@ -500,7 +522,14 @@ IpodCollection::slotStartWriteDatabaseTimer()
void IpodCollection::slotInitiateDatabaseWrite()
{
if( m_writeDatabaseJob )
{
warning() << __PRETTY_FUNCTION__ << "called while m_writeDatabaseJob still points"
<< "to an older job. Not doing anyhing.";
return;
}
IpodWriteDatabaseJob *job = new IpodWriteDatabaseJob( this );
m_writeDatabaseJob = job;
connect( job, SIGNAL(done(ThreadWeaver::Job*)), job, SLOT(deleteLater()) );
ThreadWeaver::Weaver::instance()->enqueue( job );
}
......
......@@ -29,6 +29,7 @@ namespace Collections { class MemoryCollection; }
namespace IpodMeta { class Track; }
class IphoneMountPoint;
class IpodParseTracksJob;
class IpodWriteDatabaseJob;
class IpodPlaylistProvider;
class QTemporaryFile;
struct _Itdb_iTunesDB;
......@@ -275,6 +276,7 @@ class IpodCollection : public Collections::Collection, public Meta::Observer
QAction *m_ejectAction;
QAction *m_consolidateAction;
QWeakPointer<IpodParseTracksJob> m_parseTracksJob;
QWeakPointer<IpodWriteDatabaseJob> m_writeDatabaseJob;
};
#endif // IPODCOLLECTION_H
......@@ -16,8 +16,9 @@
#include "IpodWriteDatabaseJob.h"
#include "IpodCollection.h"
IpodWriteDatabaseJob::IpodWriteDatabaseJob( const QWeakPointer<IpodCollection> &collection )
IpodWriteDatabaseJob::IpodWriteDatabaseJob( IpodCollection *collection )
: Job()
, m_coll( collection )
{
......@@ -26,8 +27,7 @@ IpodWriteDatabaseJob::IpodWriteDatabaseJob( const QWeakPointer<IpodCollection> &
void
IpodWriteDatabaseJob::run()
{
if( m_coll )
m_coll.data()->writeDatabase();
m_coll->writeDatabase();
}
#include "IpodWriteDatabaseJob.moc"
......@@ -17,21 +17,26 @@
#ifndef IPODWRITEDATABASEJOB_H
#define IPODWRITEDATABASEJOB_H
#include "IpodCollection.h"
#include <ThreadWeaver/Job>
class IpodCollection;
/**
* A job designed to call IpodCollection::writeDatabase() in a thread so that main
* thread is not blocked with it. It is guaranteed by IpodCollection that is doesn't
* destory itself while this job is alive. Memory management of this job is up to
* the caller of it.
*/
class IpodWriteDatabaseJob : public ThreadWeaver::Job
{
Q_OBJECT
public:
explicit IpodWriteDatabaseJob( const QWeakPointer<IpodCollection> &collection );
explicit IpodWriteDatabaseJob( IpodCollection *collection );
virtual void run();
private:
QWeakPointer<IpodCollection> m_coll;
IpodCollection *m_coll;
};
#endif // IPODWRITEDATABASEJOB_H
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment