[geary] Use new ReetrantProgressMonitor for folder open: Refs bug #730483



commit 3a157b42cc26e6fbd30ca6b59256f0ec5d3a3995
Author: Jim Nelson <jim yorba org>
Date:   Wed May 21 12:39:16 2014 -0700

    Use new ReetrantProgressMonitor for folder open: Refs bug #730483
    
    open_remote_async() is reetrant and ProgressMonitor is not, and my
    previous attempts to work around this impedence mismatch are obviously
    not working.  This introduces a reentrant progress monitor for folder
    opens only, although it might be useful elsewhere.

 src/engine/api/geary-progress-monitor.vala         |   46 ++++++++++++++++++++
 .../imap-engine/imap-engine-minimal-folder.vala    |    5 +-
 2 files changed, 48 insertions(+), 3 deletions(-)
---
diff --git a/src/engine/api/geary-progress-monitor.vala b/src/engine/api/geary-progress-monitor.vala
index ee0040d..6ffcbfd 100644
--- a/src/engine/api/geary-progress-monitor.vala
+++ b/src/engine/api/geary-progress-monitor.vala
@@ -69,6 +69,52 @@ public abstract class Geary.ProgressMonitor : BaseObject {
 }
 
 /**
+ * A reentrant { link ProgressMonitor}.
+ *
+ * This is not thread-safe; it's designed for single-threaded asynchronous (non-blocking) use.
+ */
+
+public class Geary.ReentrantProgressMonitor : Geary.ProgressMonitor {
+    private int start_count = 0;
+    
+    public ReentrantProgressMonitor(ProgressType type) {
+        this.progress_type = type;
+    }
+    
+    /**
+     * @inheritDoc
+     *
+     * Unlike the base class implementation, this may be called multiple times successively without
+     * a problem, but each must be matched by a { link notify_finish} to completely stop the
+     * monitor.
+     *
+     * This is not thread-safe; it's designed for single-threaded asynchronous (non-blocking) use.
+     */
+    public override void notify_start() {
+        if (start_count++ == 0)
+            base.notify_start();
+    }
+    
+    /**
+     * @inheritDoc
+     *
+     * Unlike the base class implementation, this may be called multiple times successively as
+     * long as they were matched by a prior { link notify_start}.
+     *
+     * This is not thread-safe; it's designed for single-threaded asynchronous (non-blocking) use.
+     */
+    public override void notify_finish() {
+        bool finished = (--start_count == 0);
+        
+        // prevent underflow before signalling
+        start_count = start_count.clamp(0, int.MAX);
+        
+        if (finished)
+            base.notify_finish();
+    }
+}
+
+/**
  * Captures the progress of a single action.
  */
 public class Geary.SimpleProgressMonitor : Geary.ProgressMonitor {
diff --git a/src/engine/imap-engine/imap-engine-minimal-folder.vala 
b/src/engine/imap-engine/imap-engine-minimal-folder.vala
index f5b7423..94223c6 100644
--- a/src/engine/imap-engine/imap-engine-minimal-folder.vala
+++ b/src/engine/imap-engine/imap-engine-minimal-folder.vala
@@ -55,7 +55,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.AbstractFolder, Geary.Folde
         _special_folder_type = special_folder_type;
         _properties.add(local_folder.get_properties());
         
-        opening_monitor = new Geary.SimpleProgressMonitor(Geary.ProgressType.ACTIVITY);
+        opening_monitor = new Geary.ReentrantProgressMonitor(Geary.ProgressType.ACTIVITY);
         
         email_flag_watcher = new EmailFlagWatcher(this);
         email_flag_watcher.email_flags_changed.connect(on_email_flags_changed);
@@ -544,8 +544,7 @@ private class Geary.ImapEngine.MinimalFolder : Geary.AbstractFolder, Geary.Folde
         // to ensure this isn't running when open_remote_async() is called again (due to a connection
         // reestablishment), stop this monitoring from running *before* launching close_internal_async
         // ... in essence, guard against reentrancy, which is possible
-        if (!opening_monitor.is_in_progress)
-            opening_monitor.notify_start();
+        opening_monitor.notify_start();
         
         // following blocks of code are fairly tricky because if the remote open fails need to
         // carefully back out and possibly retry


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]