ia64/xen-unstable

changeset 7837:210a5b625e30

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.
author emellor@leeni.uk.xensource.com
date Tue Nov 15 19:08:11 2005 +0100 (2005-11-15)
parents 151837f6c26b
children 009eb32c0ae4
files tools/python/xen/xend/XendDomain.py tools/python/xen/xend/server/DevController.py tools/python/xen/xend/xenstore/xswatch.py
line diff
     1.1 --- a/tools/python/xen/xend/XendDomain.py	Tue Nov 15 18:47:39 2005 +0100
     1.2 +++ b/tools/python/xen/xend/XendDomain.py	Tue Nov 15 19:08:11 2005 +0100
     1.3 @@ -36,6 +36,7 @@ from xen.xend import XendCheckpoint
     1.4  from xen.xend.XendError import XendError
     1.5  from xen.xend.XendLogging import log
     1.6  from xen.xend.server import relocate
     1.7 +from xen.xend.xenstore.xswatch import xswatch
     1.8  
     1.9  
    1.10  xc = xen.lowlevel.xc.new()
    1.11 @@ -58,9 +59,11 @@ class XendDomain:
    1.12          # to import XendDomain from XendDomainInfo causes unbounded recursion.
    1.13          # So we stuff the XendDomain instance (self) into xroot's components.
    1.14          xroot.add_component("xen.xend.XendDomain", self)
    1.15 +
    1.16          self.domains = {}
    1.17          self.domains_lock = threading.RLock()
    1.18 -        self.watchReleaseDomain()
    1.19 +
    1.20 +        xswatch("@releaseDomain", self.onReleaseDomain)
    1.21  
    1.22          self.domains_lock.acquire()
    1.23          try:
    1.24 @@ -112,11 +115,7 @@ class XendDomain:
    1.25              self.refresh()
    1.26          finally:
    1.27              self.domains_lock.release()
    1.28 -            
    1.29 -
    1.30 -    def watchReleaseDomain(self):
    1.31 -        from xen.xend.xenstore.xswatch import xswatch
    1.32 -        self.releaseDomain = xswatch("@releaseDomain", self.onReleaseDomain)
    1.33 +        return 1
    1.34  
    1.35  
    1.36      def xen_domains(self):
     2.1 --- a/tools/python/xen/xend/server/DevController.py	Tue Nov 15 18:47:39 2005 +0100
     2.2 +++ b/tools/python/xen/xend/server/DevController.py	Tue Nov 15 19:08:11 2005 +0100
     2.3 @@ -29,6 +29,12 @@ DEVICE_CREATE_TIMEOUT = 5
     2.4  HOTPLUG_STATUS_NODE = "hotplug-status"
     2.5  HOTPLUG_STATUS_ERROR = "error"
     2.6  
     2.7 +Connected = 1
     2.8 +Died      = 2
     2.9 +Error     = 3
    2.10 +Missing   = 4
    2.11 +Timeout   = 5
    2.12 +
    2.13  xenbusState = {
    2.14      'Unknown'      : 0,
    2.15      'Initialising' : 1,
    2.16 @@ -87,18 +93,28 @@ class DevController:
    2.17      def waitForDevice(self, devid):
    2.18          log.debug("Waiting for %s.", devid)
    2.19          
    2.20 -        status, fn_ret = self.waitForBackend(devid)
    2.21 -        if status:
    2.22 +        status = self.waitForBackend(devid)
    2.23 +
    2.24 +        if status == Timeout:
    2.25 +            self.destroyDevice(devid)
    2.26 +            raise VmError("Device %s (%s) could not be connected. "
    2.27 +                          "Hotplug scripts not working" %
    2.28 +                          (devid, self.deviceClass))
    2.29 +
    2.30 +        elif status == Error:
    2.31              self.destroyDevice(devid)
    2.32 -            raise VmError( ("Device %s (%s) could not be connected. "
    2.33 -                            "Hotplug scripts not working") 
    2.34 -                            % (devid, self.deviceClass))
    2.35 +            raise VmError("Device %s (%s) could not be connected. "
    2.36 +                          "Backend device not found" %
    2.37 +                          (devid, self.deviceClass))
    2.38  
    2.39 -        elif fn_ret == HOTPLUG_STATUS_ERROR:
    2.40 +        elif status == Missing:
    2.41 +            raise VmError("Device %s (%s) could not be connected. "
    2.42 +                          "Device not found" % (devid, self.deviceClass))
    2.43 +
    2.44 +        elif status == Died:
    2.45              self.destroyDevice(devid)
    2.46 -            raise VmError( ("Device %s (%s) could not be connected. "
    2.47 -                            "Backend device not found!") 
    2.48 -                            % (devid, self.deviceClass))
    2.49 +            raise VmError("Device %s (%s) could not be connected. "
    2.50 +                          "Device has died" % (devid, self.deviceClass))
    2.51  
    2.52  
    2.53      def reconfigureDevice(self, devid, config):
    2.54 @@ -302,35 +318,22 @@ class DevController:
    2.55                  raise
    2.56  
    2.57  
    2.58 -    def waitForBackend(self,devid):
    2.59 -        ev = Event()
    2.60 +    def waitForBackend(self, devid):
    2.61  
    2.62 -        def hotplugStatus():
    2.63 -            log.debug("hotplugStatus %d", devid)
    2.64 -            
    2.65 -            try:
    2.66 -                status = self.readBackend(devid, HOTPLUG_STATUS_NODE)
    2.67 -            except VmError:
    2.68 -                status = "died"
    2.69 -            if status is not None:
    2.70 -                watch.xs.unwatch(backpath, watch)
    2.71 -                hotplugStatus.value = status
    2.72 -                ev.set()
    2.73 -
    2.74 -        hotplugStatus.value = None
    2.75          frontpath = self.frontendPath(devid)
    2.76          backpath = xstransact.Read(frontpath, "backend")
    2.77  
    2.78          if backpath:
    2.79 -            watch = xswatch(backpath, hotplugStatus)
    2.80 +            statusPath = backpath + '/' + HOTPLUG_STATUS_NODE
    2.81 +            ev = Event()
    2.82 +            result = { 'status': Timeout }
    2.83 +            
    2.84 +            xswatch(statusPath, hotplugStatusCallback, statusPath, ev, result)
    2.85  
    2.86              ev.wait(DEVICE_CREATE_TIMEOUT)
    2.87 -            if ev.isSet():
    2.88 -                return (0, hotplugStatus.value)
    2.89 -            else:
    2.90 -                return (-1, hotplugStatus.value)
    2.91 +            return result['status']
    2.92          else:
    2.93 -            return (-1, "missing")
    2.94 +            return Missing
    2.95  
    2.96  
    2.97      def backendPath(self, backdom, devid):
    2.98 @@ -352,3 +355,25 @@ class DevController:
    2.99      def frontendMiscPath(self):
   2.100          return "%s/device-misc/%s" % (self.vm.getDomainPath(),
   2.101                                        self.deviceClass)
   2.102 +
   2.103 +
   2.104 +def hotplugStatusCallback(statusPath, ev, result):
   2.105 +    log.debug("hotplugStatusCallback %s.", statusPath)
   2.106 +
   2.107 +    try:
   2.108 +        status = xstransact.Read(statusPath)
   2.109 +
   2.110 +        if status is not None:
   2.111 +            if status == HOTPLUG_STATUS_ERROR:
   2.112 +                result['status'] = Error
   2.113 +            else:
   2.114 +                result['status'] = Connected
   2.115 +        else:
   2.116 +            return 1
   2.117 +    except VmError:
   2.118 +        result['status'] = Died
   2.119 +
   2.120 +    log.debug("hotplugStatusCallback %d.", result['status'])
   2.121 +
   2.122 +    ev.set()
   2.123 +    return 0
     3.1 --- a/tools/python/xen/xend/xenstore/xswatch.py	Tue Nov 15 18:47:39 2005 +0100
     3.2 +++ b/tools/python/xen/xend/xenstore/xswatch.py	Tue Nov 15 19:08:11 2005 +0100
     3.3 @@ -5,9 +5,7 @@
     3.4  # Public License.  See the file "COPYING" in the main directory of
     3.5  # this archive for more details.
     3.6  
     3.7 -import select
     3.8  import threading
     3.9 -from xen.lowlevel import xs
    3.10  from xen.xend.xenstore.xsutil import xshandle
    3.11  
    3.12  from xen.xend.XendLogging import log
    3.13 @@ -20,37 +18,42 @@ class xswatch:
    3.14      xslock = threading.Lock()
    3.15      
    3.16      def __init__(self, path, fn, *args, **kwargs):
    3.17 +        self.path = path
    3.18          self.fn = fn
    3.19          self.args = args
    3.20          self.kwargs = kwargs
    3.21          xswatch.watchStart()
    3.22          xswatch.xs.watch(path, self)
    3.23  
    3.24 +
    3.25      def watchStart(cls):
    3.26          cls.xslock.acquire()
    3.27 -        if cls.watchThread:
    3.28 +        try:
    3.29 +            if cls.watchThread:
    3.30 +                return
    3.31 +            cls.xs = xshandle()
    3.32 +            cls.watchThread = threading.Thread(name="Watcher",
    3.33 +                                               target=cls.watchMain)
    3.34 +            cls.watchThread.setDaemon(True)
    3.35 +            cls.watchThread.start()
    3.36 +        finally:
    3.37              cls.xslock.release()
    3.38 -            return
    3.39 -        cls.xs = xshandle()
    3.40 -        cls.watchThread = threading.Thread(name="Watcher",
    3.41 -                                           target=cls.watchMain)
    3.42 -        cls.watchThread.setDaemon(True)
    3.43 -        cls.watchThread.start()
    3.44 -        cls.xslock.release()
    3.45  
    3.46      watchStart = classmethod(watchStart)
    3.47  
    3.48 +
    3.49      def watchMain(cls):
    3.50          while True:
    3.51              try:
    3.52                  we = cls.xs.read_watch()
    3.53                  watch = we[1]
    3.54 -                watch.fn(*watch.args, **watch.kwargs)
    3.55 +                res = watch.fn(*watch.args, **watch.kwargs)
    3.56 +                if not res:
    3.57 +                    cls.xs.unwatch(watch.path, watch)
    3.58              except:
    3.59                  log.exception("read_watch failed")
    3.60                  # Ignore this exception -- there's no point throwing it
    3.61                  # further on because that will just kill the watcher thread,
    3.62                  # which achieves nothing.
    3.63  
    3.64 -
    3.65      watchMain = classmethod(watchMain)