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 import logging
from socket import gethostbyaddr, gethostname from socket import gethostbyaddr, gethostname
import dbus import dbus
import threading
import gtk
from virtManager.domain import vmmDomain from virtManager.domain import vmmDomain
from virtManager.network import vmmNetwork from virtManager.network import vmmNetwork
@ -96,6 +98,8 @@ class vmmConnection(gobject.GObject):
[]), []),
"state-changed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, "state-changed": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
[]), []),
"connect-error": (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE,
[str]),
} }
STATE_DISCONNECTED = 0 STATE_DISCONNECTED = 0
@ -108,6 +112,8 @@ class vmmConnection(gobject.GObject):
self.config = config self.config = config
self.readOnly = readOnly self.readOnly = readOnly
self.connectThread = None
self.connectError = None
self.uri = uri self.uri = uri
if self.uri is None or self.uri.lower() == "xen": if self.uri is None or self.uri.lower() == "xen":
self.uri = "xen:///" self.uri = "xen:///"
@ -279,6 +285,15 @@ class vmmConnection(gobject.GObject):
self.state = self.STATE_CONNECTING self.state = self.STATE_CONNECTING
self.emit("state-changed") 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: try:
if self.readOnly is None: if self.readOnly is None:
try: try:
@ -293,12 +308,42 @@ class vmmConnection(gobject.GObject):
else: else:
self.vmm = libvirt.open(self.uri) self.vmm = libvirt.open(self.uri)
self.state = self.STATE_ACTIVE self.state = self.STATE_ACTIVE
self.tick()
self.emit("state-changed")
except: except:
self.state = self.STATE_DISCONNECTED 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") 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): def pause(self):
if self.state != self.STATE_ACTIVE: if self.state != self.STATE_ACTIVE:

View File

@ -34,7 +34,6 @@ from virtManager.console import vmmConsole
from virtManager.asyncjob import vmmAsyncJob from virtManager.asyncjob import vmmAsyncJob
from virtManager.create import vmmCreate from virtManager.create import vmmCreate
from virtManager.serialcon import vmmSerialConsole from virtManager.serialcon import vmmSerialConsole
from virtManager.error import vmmErrorDialog
from virtManager.host import vmmHost from virtManager.host import vmmHost
class vmmEngine(gobject.GObject): class vmmEngine(gobject.GObject):
@ -82,43 +81,6 @@ class vmmEngine(gobject.GObject):
self.show_manager() self.show_manager()
return conn return conn
except: 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 return None
def _connect_cancelled(self, connect): def _connect_cancelled(self, connect):

View File

@ -22,13 +22,14 @@ import gtk
import gtk.glade import gtk.glade
import threading import threading
import logging import logging
import sys
import sparkline import sparkline
import libvirt import libvirt
from virtManager.connection import vmmConnection from virtManager.connection import vmmConnection
from virtManager.asyncjob import vmmAsyncJob from virtManager.asyncjob import vmmAsyncJob
from virtManager.error import vmmErrorDialog
VMLIST_SORT_ID = 1 VMLIST_SORT_ID = 1
VMLIST_SORT_NAME = 2 VMLIST_SORT_NAME = 2
@ -503,7 +504,7 @@ class vmmManager(gobject.GObject):
row[ROW_VCPUS] = conn.host_active_processor_count() row[ROW_VCPUS] = conn.host_active_processor_count()
row[ROW_MEM] = conn.pretty_current_memory() row[ROW_MEM] = conn.pretty_current_memory()
row[ROW_MEM_USAGE] = conn.current_memory_percentage() 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 row[ROW_ACTION] = gtk.STOCK_DELETE
parent = self.rows[conn.get_uri()].iter parent = self.rows[conn.get_uri()].iter
if parent is not None: if parent is not None:
@ -942,6 +943,7 @@ class vmmManager(gobject.GObject):
conn.connect("vm-removed", self.vm_removed) conn.connect("vm-removed", self.vm_removed)
conn.connect("resources-sampled", self.conn_refresh_resources) conn.connect("resources-sampled", self.conn_refresh_resources)
conn.connect("state-changed", self.conn_state_changed) conn.connect("state-changed", self.conn_state_changed)
conn.connect("connect-error", self._connect_error)
conn.connect("vm-started", self.vm_started) conn.connect("vm-started", self.vm_started)
# add the connection to the treeModel # add the connection to the treeModel
vmlist = self.window.get_widget("vm-list") vmlist = self.window.get_widget("vm-list")
@ -970,4 +972,26 @@ class vmmManager(gobject.GObject):
logging.debug("Deactivating connection %s" % conn.get_uri()) logging.debug("Deactivating connection %s" % conn.get_uri())
conn.pause() 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) gobject.type_register(vmmManager)