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

[Xen-changelog] Have a watch callback return 0 or 1 depending upon whether it would like to



# HG changeset patch
# User emellor@xxxxxxxxxxxxxxxxxxxxxx
# Node ID 210a5b625e30067c8f340452aa1020aa44325124
# Parent  151837f6c26b2cf70d8083915235f4907c9e84a1
Have a watch callback return 0 or 1 depending upon whether it would like to
continue to receive watches.  This means that it is not necessary to probe
around in the xswatch internals to unregister a watch.

Tidy up the hotplug watch handling, moving the nested function out to a
separate place (I don't think that this was a problem in the end, but it was
making me nervous as I was debugging the recent race condition, and I find it
clearer out of the class in any case.  Pass an integer code representing
hotplug status, once it has been parsed from the store, as there are now a few
different places we can detect failure, and it's cleaner to pass a code from
those places.

Small tidy up to XendDomain, removing the unused releaseDomain field.

diff -r 151837f6c26b -r 210a5b625e30 tools/python/xen/xend/XendDomain.py
--- a/tools/python/xen/xend/XendDomain.py       Tue Nov 15 17:47:39 2005
+++ b/tools/python/xen/xend/XendDomain.py       Tue Nov 15 18:08:11 2005
@@ -36,6 +36,7 @@
 from xen.xend.XendError import XendError
 from xen.xend.XendLogging import log
 from xen.xend.server import relocate
+from xen.xend.xenstore.xswatch import xswatch
 
 
 xc = xen.lowlevel.xc.new()
@@ -58,9 +59,11 @@
         # to import XendDomain from XendDomainInfo causes unbounded recursion.
         # So we stuff the XendDomain instance (self) into xroot's components.
         xroot.add_component("xen.xend.XendDomain", self)
+
         self.domains = {}
         self.domains_lock = threading.RLock()
-        self.watchReleaseDomain()
+
+        xswatch("@releaseDomain", self.onReleaseDomain)
 
         self.domains_lock.acquire()
         try:
@@ -112,11 +115,7 @@
             self.refresh()
         finally:
             self.domains_lock.release()
-            
-
-    def watchReleaseDomain(self):
-        from xen.xend.xenstore.xswatch import xswatch
-        self.releaseDomain = xswatch("@releaseDomain", self.onReleaseDomain)
+        return 1
 
 
     def xen_domains(self):
diff -r 151837f6c26b -r 210a5b625e30 
tools/python/xen/xend/server/DevController.py
--- a/tools/python/xen/xend/server/DevController.py     Tue Nov 15 17:47:39 2005
+++ b/tools/python/xen/xend/server/DevController.py     Tue Nov 15 18:08:11 2005
@@ -29,6 +29,12 @@
 HOTPLUG_STATUS_NODE = "hotplug-status"
 HOTPLUG_STATUS_ERROR = "error"
 
+Connected = 1
+Died      = 2
+Error     = 3
+Missing   = 4
+Timeout   = 5
+
 xenbusState = {
     'Unknown'      : 0,
     'Initialising' : 1,
@@ -87,18 +93,28 @@
     def waitForDevice(self, devid):
         log.debug("Waiting for %s.", devid)
         
-        status, fn_ret = self.waitForBackend(devid)
-        if status:
+        status = self.waitForBackend(devid)
+
+        if status == Timeout:
             self.destroyDevice(devid)
-            raise VmError( ("Device %s (%s) could not be connected. "
-                            "Hotplug scripts not working") 
-                            % (devid, self.deviceClass))
-
-        elif fn_ret == HOTPLUG_STATUS_ERROR:
+            raise VmError("Device %s (%s) could not be connected. "
+                          "Hotplug scripts not working" %
+                          (devid, self.deviceClass))
+
+        elif status == Error:
             self.destroyDevice(devid)
-            raise VmError( ("Device %s (%s) could not be connected. "
-                            "Backend device not found!") 
-                            % (devid, self.deviceClass))
+            raise VmError("Device %s (%s) could not be connected. "
+                          "Backend device not found" %
+                          (devid, self.deviceClass))
+
+        elif status == Missing:
+            raise VmError("Device %s (%s) could not be connected. "
+                          "Device not found" % (devid, self.deviceClass))
+
+        elif status == Died:
+            self.destroyDevice(devid)
+            raise VmError("Device %s (%s) could not be connected. "
+                          "Device has died" % (devid, self.deviceClass))
 
 
     def reconfigureDevice(self, devid, config):
@@ -302,35 +318,22 @@
                 raise
 
 
-    def waitForBackend(self,devid):
-        ev = Event()
-
-        def hotplugStatus():
-            log.debug("hotplugStatus %d", devid)
-            
-            try:
-                status = self.readBackend(devid, HOTPLUG_STATUS_NODE)
-            except VmError:
-                status = "died"
-            if status is not None:
-                watch.xs.unwatch(backpath, watch)
-                hotplugStatus.value = status
-                ev.set()
-
-        hotplugStatus.value = None
+    def waitForBackend(self, devid):
+
         frontpath = self.frontendPath(devid)
         backpath = xstransact.Read(frontpath, "backend")
 
         if backpath:
-            watch = xswatch(backpath, hotplugStatus)
+            statusPath = backpath + '/' + HOTPLUG_STATUS_NODE
+            ev = Event()
+            result = { 'status': Timeout }
+            
+            xswatch(statusPath, hotplugStatusCallback, statusPath, ev, result)
 
             ev.wait(DEVICE_CREATE_TIMEOUT)
-            if ev.isSet():
-                return (0, hotplugStatus.value)
-            else:
-                return (-1, hotplugStatus.value)
-        else:
-            return (-1, "missing")
+            return result['status']
+        else:
+            return Missing
 
 
     def backendPath(self, backdom, devid):
@@ -352,3 +355,25 @@
     def frontendMiscPath(self):
         return "%s/device-misc/%s" % (self.vm.getDomainPath(),
                                       self.deviceClass)
+
+
+def hotplugStatusCallback(statusPath, ev, result):
+    log.debug("hotplugStatusCallback %s.", statusPath)
+
+    try:
+        status = xstransact.Read(statusPath)
+
+        if status is not None:
+            if status == HOTPLUG_STATUS_ERROR:
+                result['status'] = Error
+            else:
+                result['status'] = Connected
+        else:
+            return 1
+    except VmError:
+        result['status'] = Died
+
+    log.debug("hotplugStatusCallback %d.", result['status'])
+
+    ev.set()
+    return 0
diff -r 151837f6c26b -r 210a5b625e30 tools/python/xen/xend/xenstore/xswatch.py
--- a/tools/python/xen/xend/xenstore/xswatch.py Tue Nov 15 17:47:39 2005
+++ b/tools/python/xen/xend/xenstore/xswatch.py Tue Nov 15 18:08:11 2005
@@ -5,9 +5,7 @@
 # Public License.  See the file "COPYING" in the main directory of
 # this archive for more details.
 
-import select
 import threading
-from xen.lowlevel import xs
 from xen.xend.xenstore.xsutil import xshandle
 
 from xen.xend.XendLogging import log
@@ -20,37 +18,42 @@
     xslock = threading.Lock()
     
     def __init__(self, path, fn, *args, **kwargs):
+        self.path = path
         self.fn = fn
         self.args = args
         self.kwargs = kwargs
         xswatch.watchStart()
         xswatch.xs.watch(path, self)
 
+
     def watchStart(cls):
         cls.xslock.acquire()
-        if cls.watchThread:
+        try:
+            if cls.watchThread:
+                return
+            cls.xs = xshandle()
+            cls.watchThread = threading.Thread(name="Watcher",
+                                               target=cls.watchMain)
+            cls.watchThread.setDaemon(True)
+            cls.watchThread.start()
+        finally:
             cls.xslock.release()
-            return
-        cls.xs = xshandle()
-        cls.watchThread = threading.Thread(name="Watcher",
-                                           target=cls.watchMain)
-        cls.watchThread.setDaemon(True)
-        cls.watchThread.start()
-        cls.xslock.release()
 
     watchStart = classmethod(watchStart)
+
 
     def watchMain(cls):
         while True:
             try:
                 we = cls.xs.read_watch()
                 watch = we[1]
-                watch.fn(*watch.args, **watch.kwargs)
+                res = watch.fn(*watch.args, **watch.kwargs)
+                if not res:
+                    cls.xs.unwatch(watch.path, watch)
             except:
                 log.exception("read_watch failed")
                 # Ignore this exception -- there's no point throwing it
                 # further on because that will just kill the watcher thread,
                 # which achieves nothing.
 
-
     watchMain = classmethod(watchMain)

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.