[virt-tools-list] [virt-manager PATCH v2 3/6] virtManager: object: domain: Spawn thread for set time

Michael Weiser michael.weiser at gmx.de
Fri Jan 3 20:12:33 UTC 2020


Sleeping in a loop waiting for the qemu guest agent to come online would
leave an annoying progress dialog while the domain would actually be
fully useable already. Additionally, multiple progress dialogs could
actually accumulate on screen if the user managed to suspend/resume fast
enough or the timeout was just long enough.

Defer regular retries into a separate thread to allow the progress
dialog to disappear immediately after the actual action completed. The
thread is encapsulated in a new class _vmmDomainSetTimeThread which
holds state, decides whether to at all wait for an agent to come online
or even try to set the guest time in the first place. It also holds
state (thread running or not), configuration (timeout and retry
interval) and provides an interface to start and stop the time setting
operation.

A later patch will wire up stopping the operation.

Signed-off-by: Michael Weiser <michael.weiser at gmx.de>
Suggested-by: Cole Robinson <crobinso at redhat.com>
---
 virtManager/object/domain.py | 73 +++++++++++++++++++++++++++++-------
 1 file changed, 59 insertions(+), 14 deletions(-)

diff --git a/virtManager/object/domain.py b/virtManager/object/domain.py
index 355fca97..584a57a0 100644
--- a/virtManager/object/domain.py
+++ b/virtManager/object/domain.py
@@ -181,39 +181,84 @@ class vmmDomainSnapshot(vmmLibvirtObject):
 
 
 class _vmmDomainSetTimeThread(vmmGObject):
+    """
+    A separate thread handling time setting operations as not to block the main
+    UI.
+    """
     def __init__(self, domain):
         vmmGObject.__init__(self)
         self._domain = domain
+        self._do_cancel = threading.Event()
+        self._do_cancel.clear()
+        self._thread = None
 
     def start(self):
+        """
+        Start time setting thread if setting time is supported by the
+        connection. Stop the old thread first. May block until the old thread
+        terminates.
+        """
+        self.stop()
+
         # Only run the API for qemu and test drivers, they are the only ones
         # that support it. This will save spamming logs with error output.
         if not self._domain.conn.is_qemu() and not self._domain.conn.is_test():
             return
 
-        if self._domain.conn.is_qemu():
-            # For qemu, only run the API if the VM has the qemu guest agent in
-            # the XML.
-            if not self._domain.has_agent():
-                return
+        # For qemu, only run the API if the VM has the qemu guest agent in
+        # the XML.
+        if self._domain.conn.is_qemu() and not self._domain.has_agent():
+            return
+
+        log.debug("Starting time setting thread")
+        self._thread = threading.Thread(name='settime thread',
+                                        target=self._do_loop)
+        self._thread.start()
+
+    def stop(self):
+        """
+        Signal running thread to terminate and wait for it to do so.
+        """
+        if not self._thread:
+            return
+
+        log.debug("Stopping time setting thread")
+        self._do_cancel.set()
+        # thread may be in a loop waiting for an agent to come online or just
+        # waiting for a set time operation to finish
+        self._thread.join()
+        self._thread = None
+        self._do_cancel.clear()
 
-            # wait for agent to come online
+    def _do_loop(self):
+        """
+        Run the domain's set time operation. Potentially wait for a guest agent
+        to come online beforehand.
+        """
+        if self._domain.conn.is_qemu():
+            # Setting time of a qemu domain can only work if an agent is
+            # defined and online. We only get here if one is defined. So wait
+            # for it to come online now.
             maxwait = 5
             sleep = 0.5
-            for _ in range(0, int(maxwait / sleep)):
-                if self._domain.agent_ready():
-                    break
+            waited = 0
+            while waited < maxwait and not self._domain.agent_ready():
                 log.debug("Waiting for qemu guest agent to come online...")
-                time.sleep(sleep)
-            else:
-                if not self._domain.agent_ready():
-                    log.debug("Giving up on qemu guest agent for time sync")
+
+                # sleep some time and potentially abort
+                if self._do_cancel.wait(sleep):
                     return
 
+                waited += sleep
+
+            if not self._domain.agent_ready():
+                log.debug("Giving up on qemu guest agent for time sync")
+                return
+
         self._domain.set_time()
 
     def _cleanup(self):
-        pass
+        self.stop()
 
 
 class vmmDomain(vmmLibvirtObject):
-- 
2.24.1





More information about the virt-tools-list mailing list