Move opening of connections into a background thread to avoid locking the UI

This commit is contained in:
Daniel P. Berrange 2007-09-10 20:56:01 -04:00
parent 99c92b9471
commit 96eb9f5f24
3 changed files with 74 additions and 43 deletions

View File

@ -26,6 +26,8 @@ from time import time
import logging
from socket import gethostbyaddr, gethostname
import dbus
import threading
import gtk
from virtManager.domain import vmmDomain
from virtManager.network import vmmNetwork
@ -96,6 +98,8 @@ class vmmConnection(gobject.GObject):
[]),
"state-changed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
[]),
"connect-error": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
[str]),
}
STATE_DISCONNECTED = 0
@ -108,6 +112,8 @@ class vmmConnection(gobject.GObject):
self.config = config
self.readOnly = readOnly
self.connectThread = None
self.connectError = None
self.uri = uri
if self.uri is None or self.uri.lower() == "xen":
self.uri = "xen:///"
@ -279,6 +285,15 @@ class vmmConnection(gobject.GObject):
self.state = self.STATE_CONNECTING
self.emit("state-changed")
logging.debug("Scheduling background open thread for " + self.uri)
self.connectThread = threading.Thread(target = self._open_thread, name="Connect " + self.uri)
self.connectThread.setDaemon(True)
self.connectThread.start()
def _open_thread(self):
logging.debug("Background thread is running")
try:
if self.readOnly is None:
try:
@ -293,12 +308,42 @@ class vmmConnection(gobject.GObject):
else:
self.vmm = libvirt.open(self.uri)
self.state = self.STATE_ACTIVE
self.tick()
self.emit("state-changed")
except:
self.state = self.STATE_DISCONNECTED
(type, value, stacktrace) = sys.exc_info ()
# Detailed error message, in English so it can be Googled.
self.connectError = \
("Unable to open connection to hypervisor URI '%s':\n" %
str(self.uri)) + \
str(type) + " " + str(value) + "\n" + \
traceback.format_exc (stacktrace)
logging.error(self.connectError)
# We want to kill off this thread asap, so schedule a gobject
# idle even to inform the UI of result
logging.debug("Background open thread complete, scheduling notify")
gtk.gdk.threads_enter()
try:
gobject.idle_add(self._open_notify)
finally:
gtk.gdk.threads_leave()
self.connectThread = None
def _open_notify(self):
logging.debug("Notifying open result")
gtk.gdk.threads_enter()
try:
if self.state == self.STATE_ACTIVE:
self.tick()
self.emit("state-changed")
raise
if self.state == self.STATE_DISCONNECTED:
self.emit("connect-error", self.connectError)
self.connectError = None
finally:
gtk.gdk.threads_leave()
def pause(self):
if self.state != self.STATE_ACTIVE:

View File

@ -34,7 +34,6 @@ from virtManager.console import vmmConsole
from virtManager.asyncjob import vmmAsyncJob
from virtManager.create import vmmCreate
from virtManager.serialcon import vmmSerialConsole
from virtManager.error import vmmErrorDialog
from virtManager.host import vmmHost
class vmmEngine(gobject.GObject):
@ -82,43 +81,6 @@ class vmmEngine(gobject.GObject):
self.show_manager()
return conn
except:
(type, value, stacktrace) = sys.exc_info ()
# Detailed error message, in English so it can be Googled.
details = \
("Unable to open connection to hypervisor URI '%s':\n" %
str(uri)) + \
str(type) + " " + str(value) + "\n" + \
traceback.format_exc (stacktrace)
logging.error (details)
# Error dialog.
if uri is None:
uri = "xen"
if uri == "xen":
dg = vmmErrorDialog (None, 0, gtk.MESSAGE_ERROR,
gtk.BUTTONS_CLOSE,
_("Unable to open a connection to the Xen hypervisor/daemon.\n\n" +
"Verify that:\n" +
" - A Xen host kernel was booted\n" +
" - The Xen service has been started\n"),
details)
elif uri.startswith("qemu:"):
dg = vmmErrorDialog (None, 0, gtk.MESSAGE_ERROR,
gtk.BUTTONS_CLOSE,
_("Unable to open a connection to the QEMU management daemon.\n\n" +
"Verify that:\n" +
" - The 'libvirt_qemud' daemon has been started\n"),
details)
else:
dg = vmmErrorDialog (None, 0, gtk.MESSAGE_ERROR,
gtk.BUTTONS_CLOSE,
_("Unable to open connection to hypervisor '%s'") % str(uri),
details)
dg.set_title(_("Virtual Machine Manager Connection Failure"))
dg.run()
dg.hide()
dg.destroy()
return None
def _connect_cancelled(self, connect):

View File

@ -22,13 +22,14 @@ import gtk
import gtk.glade
import threading
import logging
import sys
import sparkline
import libvirt
from virtManager.connection import vmmConnection
from virtManager.asyncjob import vmmAsyncJob
from virtManager.error import vmmErrorDialog
VMLIST_SORT_ID = 1
VMLIST_SORT_NAME = 2
@ -503,7 +504,7 @@ class vmmManager(gobject.GObject):
row[ROW_VCPUS] = conn.host_active_processor_count()
row[ROW_MEM] = conn.pretty_current_memory()
row[ROW_MEM_USAGE] = conn.current_memory_percentage()
if conn.get_state() == vmmConnection.STATE_DISCONNECTED:
if conn.get_state() in [vmmConnection.STATE_DISCONNECTED, vmmConnection.STATE_CONNECTING]:
row[ROW_ACTION] = gtk.STOCK_DELETE
parent = self.rows[conn.get_uri()].iter
if parent is not None:
@ -942,6 +943,7 @@ class vmmManager(gobject.GObject):
conn.connect("vm-removed", self.vm_removed)
conn.connect("resources-sampled", self.conn_refresh_resources)
conn.connect("state-changed", self.conn_state_changed)
conn.connect("connect-error", self._connect_error)
conn.connect("vm-started", self.vm_started)
# add the connection to the treeModel
vmlist = self.window.get_widget("vm-list")
@ -970,4 +972,26 @@ class vmmManager(gobject.GObject):
logging.debug("Deactivating connection %s" % conn.get_uri())
conn.pause()
def _connect_error(self, conn, details):
if conn.get_driver() == "xen" and not conn.is_remote():
dg = vmmErrorDialog (None, 0, gtk.MESSAGE_ERROR,
gtk.BUTTONS_CLOSE,
_("Unable to open a connection to the Xen hypervisor/daemon.\n\n" +
"Verify that:\n" +
" - A Xen host kernel was booted\n" +
" - The Xen service has been started\n"),
details)
else:
dg = vmmErrorDialog (None, 0, gtk.MESSAGE_ERROR,
gtk.BUTTONS_CLOSE,
_("Unable to open a connection to the libvirt management daemon.\n\n" +
"Verify that:\n" +
" - The 'libvirtd' daemon has been started\n"),
details)
dg.set_title(_("Virtual Machine Manager Connection Failure"))
dg.run()
dg.hide()
dg.destroy()
gobject.type_register(vmmManager)