@@ -26,28 +26,13 @@ void Setup::setCleanupTimeout(unsigned long timeout)
2626void Setup::removeSetup (const QString &name, bool waitForFinished)
2727{
2828 QMutexLocker _ (&SetupPrivate::setupMutex);
29- if (SetupPrivate::engines.contains (name)) {
30- auto &info = SetupPrivate::engines[name];
31- if (info.engine ) {
32- qCDebug (qdssetup) << " Finalizing engine of setup" << name;
33- QMetaObject::invokeMethod (info.engine , " finalize" , Qt::QueuedConnection);
34- info.engine = nullptr ;
35- } else
36- qCDebug (qdssetup) << " Engine of setup" << name << " already finalizing" ;
37-
38- if (waitForFinished) {
39- if (!info.thread ->wait (SetupPrivate::timeout)) {
40- qCWarning (qdssetup) << " Workerthread of setup" << name << " did not finish before the timout. Terminating..." ;
41- info.thread ->terminate ();
42- auto wRes = info.thread ->wait (100 );
43- qCDebug (qdssetup) << " Terminate result for setup" << name << " :"
44- << wRes;
45- }
46- info.thread ->deleteLater ();
47-
48- _.unlock (); // unlock first
49- QCoreApplication::processEvents ();// required to perform queued events
50- }
29+ auto mThread = SetupPrivate::engines.value (name);
30+ _.unlock (); // unlock first
31+
32+ if (mThread ) {
33+ mThread ->stopEngine ();
34+ if (waitForFinished)
35+ mThread ->waitAndTerminate (SetupPrivate::timeout);
5136 } else // no there -> remove defaults (either already removed does nothing, or remove passive)
5237 DefaultsPrivate::removeDefaults (name);
5338}
@@ -443,6 +428,9 @@ Setup &Setup::setAccountTrusted(const QByteArray &importData, const QString &pas
443428
444429void Setup::create (const QString &name)
445430{
431+ if (QThread::currentThread () != qApp->thread ())
432+ qCWarning (qdssetup) << " Setup::create should only be called from the main thread" ;
433+
446434 QMutexLocker _ (&SetupPrivate::setupMutex);
447435 if (SetupPrivate::engines.contains (name))
448436 throw SetupExistsException (name);
@@ -463,36 +451,22 @@ void Setup::create(const QString &name)
463451 engine->prepareInitialAccount (d->initialImport );
464452
465453 // create and connect the new thread
466- auto thread = new QThread ();
467- engine->moveToThread (thread);
468- QObject::connect (thread, &QThread::started,
469- engine, &ExchangeEngine::initialize);
470- QObject::connect (thread, &QThread::finished,
471- engine, &ExchangeEngine::deleteLater);
472- // unlock as soon as the engine has been destroyed
473- QObject::connect (engine, &ExchangeEngine::destroyed, qApp, [lockFile, name](){
474- qCDebug (qdssetup) << " Engine for setup" << name << " destroyed - removing lockfile" ;
475- lockFile->unlock ();
476- delete lockFile;
477- }, Qt::DirectConnection); // direct connection required
454+ auto thread = new EngineThread{name, engine, lockFile};
478455 // once the thread finished, clear the engine from the cache of known ones
479- QObject::connect (thread, &QThread::finished, thread, [name, thread](){
480- qCDebug (qdssetup) << " Thread for setup" << name << " stopped - setup completly removed" ;
456+ QObject::connect (thread, &QThread::finished, [name](){
481457 QMutexLocker _cn (&SetupPrivate::setupMutex);
482458 SetupPrivate::engines.remove (name);
459+ _cn.unlock ();
483460 DefaultsPrivate::removeDefaults (name);
484- thread->deleteLater ();
485- }, Qt::QueuedConnection); // queued connection, sent from within the thread to thread object on current thread
461+ }); // queued connection, sent from within the thread to thread object on current thread
486462
487463 // start the thread and cache engine data
488- thread-> start ( );
489- SetupPrivate::engines. insert (name, { thread, engine} );
464+ SetupPrivate::engines. insert (name, thread );
465+ thread-> startEngine ( );
490466}
491467
492468bool Setup::createPassive (const QString &name, int timeout)
493469{
494- QMutexLocker _ (&SetupPrivate::setupMutex);
495-
496470 // create storage dir and defaults
497471 auto storageDir = d->createStorageDir (name);
498472 d->createDefaults (name, storageDir, true );
@@ -527,30 +501,27 @@ bool Setup::createPassive(const QString &name, int timeout)
527501
528502const QString SetupPrivate::DefaultLocalDir = QStringLiteral(" ./qtdatasync/default" );
529503QMutex SetupPrivate::setupMutex (QMutex::Recursive);
530- QHash<QString, SetupPrivate::SetupInfo > SetupPrivate::engines;
504+ QHash<QString, QPointer<EngineThread> > SetupPrivate::engines;
531505unsigned long SetupPrivate::timeout = ULONG_MAX;
532506
533507void SetupPrivate::cleanupHandler ()
534508{
535509 QMutexLocker _ (&setupMutex);
536- for (auto it = engines.begin (); it != engines.end (); it++) {
537- if (it->engine ) {
538- qCDebug (qdssetup) << " Finalizing engine of setup" << it.key () << " because of app quit" ;
539- QMetaObject::invokeMethod (it->engine , " finalize" , Qt::QueuedConnection);
540- it->engine = nullptr ;
541- }
542- }
543- for (auto it = engines.constBegin (); it != engines.constEnd (); it++) {
544- if (!it->thread ->wait (timeout)) {
545- qCWarning (qdssetup) << " Workerthread of setup" << it.key () << " did not finish before the timout. Terminating..." ;
546- it->thread ->terminate ();
547- auto wRes = it->thread ->wait (100 );
548- qCDebug (qdssetup) << " Terminate result for setup" << it.key () << " :"
549- << wRes;
510+ auto threads = engines.values ();
511+ engines.clear ();
512+ _.unlock ();
513+
514+ for (auto &thread : threads) {
515+ if (thread->stopEngine () &&
516+ thread->thread () != QThread::currentThread ()) {
517+ qCCritical (qdssetup) << " Stopping datasync thread" << thread->name ()
518+ << " from the main thread even though it was created on a different thread!"
519+ << " This can lead to synchronization errors. You should always stop all other threads before quitting the application." ;
550520 }
551- it->thread ->deleteLater ();
552521 }
553- engines.clear ();
522+ for (auto &thread : threads)
523+ thread->waitAndTerminate (timeout);
524+
554525 DefaultsPrivate::clearDefaults ();
555526}
556527
@@ -562,7 +533,7 @@ unsigned long SetupPrivate::currentTimeout()
562533ExchangeEngine *SetupPrivate::engine (const QString &setupName)
563534{
564535 QMutexLocker _ (&setupMutex);
565- auto engine = engines.value (setupName). engine ;
536+ auto engine = engines.value (setupName)-> engine () ;
566537 if (!engine)
567538 throw SetupDoesNotExistException (setupName);
568539 else
@@ -627,13 +598,6 @@ SetupPrivate::SetupPrivate() :
627598 }
628599{}
629600
630- SetupPrivate::SetupInfo::SetupInfo () = default;
631-
632- SetupPrivate::SetupInfo::SetupInfo (QThread *thread, ExchangeEngine *engine) :
633- thread{thread},
634- engine{engine}
635- {}
636-
637601// ------------- Exceptions -------------
638602
639603SetupException::SetupException (const QString &setupName, const QString &message) :
0 commit comments