Don't abort propagation job abortions synchronously from finished
authorJocelyn Turcotte <jturcotte@woboq.com>
Fri, 17 Feb 2017 11:57:24 +0000 (12:57 +0100)
committerJocelyn Turcotte <jturcotte@woboq.com>
Thu, 23 Feb 2017 16:54:33 +0000 (17:54 +0100)
This leads to crashes since we changed the connection to the parent
jobs not to be queued anymore.
We don't really need to bubble up the finished state through
parents in that case, and it would also mean that we'd recurse
all the way through leaves as we go up to each parent. So just call
abort directly on the OwncloudPropagator and make sure the abortion
call is posted to the event loop.

src/libsync/owncloudpropagator.cpp
src/libsync/owncloudpropagator.h

index 40e3c6786d9653601f69c84d9caa52be4a3ebcb6..dc5ab5a3ffc47bcdef13cec02305c276c8b504b1 100644 (file)
@@ -171,6 +171,11 @@ void PropagateItemJob::done(SyncFileItem::Status status, const QString &errorStr
 
     emit propagator()->itemCompleted(_item);
     emit finished(status);
+
+    if (status == SyncFileItem::FatalError) {
+        // Abort all remaining jobs.
+        propagator()->abort();
+    }
 }
 
 /**
@@ -669,12 +674,9 @@ void PropagatorCompositeJob::slotSubJobFinished(SyncFileItem::Status status)
     ASSERT(i >= 0);
     _runningJobs.remove(i);
 
-    if (status == SyncFileItem::FatalError) {
-        abort();
-        _state = Finished;
-        emit finished(status);
-        return;
-    } else if (status == SyncFileItem::NormalError || status == SyncFileItem::SoftError) {
+    if (status == SyncFileItem::FatalError
+        || status == SyncFileItem::NormalError
+        || status == SyncFileItem::SoftError) {
         _hasError = status;
     }
 
index 0ef06ee70e15b280efe59d5ce109619bc2dfe722..ccb7e6d3c317495348ab4fa089c97817cec7eb7e 100644 (file)
@@ -331,9 +331,11 @@ public:
     void abort() {
         _abortRequested.fetchAndStoreOrdered(true);
         if (_rootJob) {
-            _rootJob->abort();
+            // We're possibly already in an item's finished stack
+            QMetaObject::invokeMethod(_rootJob.data(), "abort", Qt::QueuedConnection);
         }
-        emitFinished(SyncFileItem::NormalError);
+        // abort() of all jobs will likely have already resulted in finished being emitted, but just in case.
+        QMetaObject::invokeMethod(this, "emitFinished", Qt::QueuedConnection, Q_ARG(SyncFileItem::Status, SyncFileItem::NormalError));
     }
 
     // timeout in seconds