xen-vtx-unstable

annotate tools/python/xen/xend/server/controller.py @ 1677:7dcb491e6c4a

bitkeeper revision 1.1041.7.1 (40eaa1b63pn-AWBaQWrFszKHGANStQ)

Tidy up messaging to device backends.
Add message response handlers indexed by message id instead of
relying on a queue of deferreds.
Tidy up error handling so that deferred errors are caught.
author mjw@wray-m-3.hpl.hp.com
date Tue Jul 06 12:57:26 2004 +0000 (2004-07-06)
parents d3666e462d59
children 35e97fc65a8b
rev   line source
mjw@1654 1 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
mjw@1654 2
mjw@1623 3 from twisted.internet import defer
mjw@1677 4 defer.Deferred.debug = 1
mjw@1623 5
mjw@1623 6 import channel
mjw@1623 7 from messages import msgTypeName
mjw@1623 8
mjw@1677 9 DEBUG=0
mjw@1677 10
mjw@1677 11 class OutOfOrderError(RuntimeError):
mjw@1677 12 """Error reported when a response arrives out of order.
mjw@1677 13 """
mjw@1677 14 pass
mjw@1677 15
mjw@1677 16 class Responder:
mjw@1677 17 """Handler for a response to a message.
mjw@1677 18 """
mjw@1677 19
mjw@1677 20 def __init__(self, mid, deferred):
mjw@1677 21 """Create a responder.
mjw@1677 22
mjw@1677 23 mid message id of response to handle
mjw@1677 24 deferred deferred object holding the callbacks
mjw@1677 25 """
mjw@1677 26 self.mid = mid
mjw@1677 27 self.deferred = deferred
mjw@1677 28
mjw@1677 29 def responseReceived(self, msg):
mjw@1677 30 if self.deferred.called: return
mjw@1677 31 self.deferred.callback(msg)
mjw@1677 32
mjw@1677 33 def error(self, err):
mjw@1677 34 if self.deferred.called: return
mjw@1677 35 self.deferred.errback(err)
mjw@1677 36
mjw@1623 37 class CtrlMsgRcvr:
mjw@1623 38 """Abstract class for things that deal with a control interface to a domain.
mjw@1654 39
mjw@1654 40 Instance variables:
mjw@1654 41
mjw@1654 42 dom : the domain we are a control interface for
mjw@1654 43 majorTypes: list of major message types we are interested in
mjw@1654 44 subTypes : mapping of message subtypes to methods
mjw@1654 45
mjw@1654 46 channel : channel to the domain
mjw@1654 47 idx : channel index
mjw@1623 48 """
mjw@1623 49
mjw@1623 50
mjw@1623 51 def __init__(self):
mjw@1623 52 self.channelFactory = channel.channelFactory()
mjw@1623 53 self.majorTypes = [ ]
mjw@1623 54 self.subTypes = {}
mjw@1623 55 self.dom = None
mjw@1623 56 self.channel = None
mjw@1623 57 self.idx = None
mjw@1677 58 self.responders = []
mjw@1677 59 # Timeout (in seconds) for deferreds.
mjw@1677 60 self.timeout = 10
mjw@1677 61
mjw@1677 62 def setTimeout(self, timeout):
mjw@1677 63 self.timeout = timeout
mjw@1623 64
mjw@1623 65 def requestReceived(self, msg, type, subtype):
mjw@1654 66 """Dispatch a request to handlers.
mjw@1654 67
mjw@1654 68 msg message
mjw@1654 69 type major message type
mjw@1654 70 subtype minor message type
mjw@1654 71 """
mjw@1677 72 msgid = msg.get_header()['id']
mjw@1677 73 if DEBUG:
mjw@1677 74 print 'requestReceived>', self, msgid, msgTypeName(type, subtype)
mjw@1623 75 method = self.subTypes.get(subtype)
mjw@1623 76 if method:
mjw@1623 77 method(msg, 1)
mjw@1677 78 elif DEBUG:
mjw@1623 79 print ('requestReceived> No handler: Message type %s %d:%d'
mjw@1623 80 % (msgTypeName(type, subtype), type, subtype)), self
mjw@1623 81
mjw@1623 82 def responseReceived(self, msg, type, subtype):
mjw@1654 83 """Dispatch a response to handlers.
mjw@1654 84
mjw@1654 85 msg message
mjw@1654 86 type major message type
mjw@1654 87 subtype minor message type
mjw@1654 88 """
mjw@1677 89 msgid = msg.get_header()['id']
mjw@1677 90 if DEBUG:
mjw@1677 91 print 'responseReceived>', self, msgid, msgTypeName(type, subtype)
mjw@1677 92 if self.callResponders(msg):
mjw@1677 93 return
mjw@1623 94 method = self.subTypes.get(subtype)
mjw@1623 95 if method:
mjw@1623 96 method(msg, 0)
mjw@1677 97 elif DEBUG:
mjw@1623 98 print ('responseReceived> No handler: Message type %s %d:%d'
mjw@1623 99 % (msgTypeName(type, subtype), type, subtype)), self
mjw@1623 100
mjw@1677 101 def addResponder(self, mid, deferred):
mjw@1677 102 """Add a responder for a message id.
mjw@1677 103 The deferred is called with callback(msg) when a response
mjw@1677 104 with the given message id arrives. Responses are expected
mjw@1677 105 to arrive in order of message id. When a response arrives,
mjw@1677 106 waiting responders for messages with lower id have errback
mjw@1677 107 called with an OutOfOrder error.
mjw@1677 108
mjw@1677 109 mid message id of response expected
mjw@1677 110 deferred a Deferred to handle the response
mjw@1677 111
mjw@1677 112 returns Responder
mjw@1677 113 """
mjw@1677 114 if self.timeout > 0:
mjw@1677 115 deferred.setTimeout(self.timeout)
mjw@1677 116 resp = Responder(mid, deferred)
mjw@1677 117 self.responders.append(resp)
mjw@1677 118 return resp
mjw@1677 119
mjw@1677 120 def callResponders(self, msg):
mjw@1677 121 """Call any waiting responders for a response message.
mjw@1677 122
mjw@1677 123 msg response message
mjw@1677 124
mjw@1677 125 returns 1 if there was a responder for the message, 0 otherwise
mjw@1677 126 """
mjw@1677 127 hdr = msg.get_header()
mjw@1677 128 mid = hdr['id']
mjw@1677 129 handled = 0
mjw@1677 130 while self.responders:
mjw@1677 131 resp = self.responders[0]
mjw@1677 132 if resp.mid > mid:
mjw@1677 133 break
mjw@1677 134 self.responders.pop()
mjw@1677 135 if resp.mid < mid:
mjw@1677 136 print 'handleResponse> Out of order:', resp.mid, mid
mjw@1677 137 resp.error(OutOfOrderError())
mjw@1677 138 else:
mjw@1677 139 handled = 1
mjw@1677 140 resp.responseReceived(msg)
mjw@1677 141 break
mjw@1677 142 return handled
mjw@1677 143
mjw@1623 144 def lostChannel(self):
mjw@1654 145 """Called when the channel to the domain is lost.
mjw@1654 146 """
mjw@1623 147 pass
mjw@1623 148
mjw@1623 149 def registerChannel(self):
mjw@1654 150 """Register interest in our major message types with the
mjw@1654 151 channel to our domain.
mjw@1654 152 """
mjw@1623 153 self.channel = self.channelFactory.domChannel(self.dom)
mjw@1623 154 self.idx = self.channel.getIndex()
mjw@1623 155 if self.majorTypes:
mjw@1623 156 self.channel.registerDevice(self.majorTypes, self)
mjw@1623 157
mjw@1623 158 def deregisterChannel(self):
mjw@1654 159 """Deregister interest in our major message types with the
mjw@1654 160 channel to our domain.
mjw@1654 161 """
mjw@1623 162 if self.channel:
mjw@1623 163 self.channel.deregisterDevice(self)
mjw@1623 164 del self.channel
mjw@1623 165
mjw@1623 166 def produceRequests(self):
mjw@1654 167 """Produce any queued requests.
mjw@1654 168
mjw@1654 169 return number produced
mjw@1654 170 """
mjw@1623 171 return 0
mjw@1623 172
mjw@1677 173 def writeRequest(self, msg, response=None):
mjw@1654 174 """Write a request to the channel.
mjw@1677 175
mjw@1677 176 msg message
mjw@1677 177 response Deferred to handle the response (optional)
mjw@1654 178 """
mjw@1623 179 if self.channel:
mjw@1677 180 if DEBUG: print 'CtrlMsgRcvr>writeRequest>', self, msg
mjw@1677 181 if response:
mjw@1677 182 self.addResponder(msg.get_header()['id'], response)
mjw@1623 183 self.channel.writeRequest(msg)
mjw@1623 184 else:
mjw@1623 185 print 'CtrlMsgRcvr>writeRequest>', 'no channel!', self
mjw@1623 186
mjw@1623 187 def writeResponse(self, msg):
mjw@1654 188 """Write a response to the channel.
mjw@1654 189 """
mjw@1623 190 if self.channel:
mjw@1677 191 if DEBUG: print 'CtrlMsgRcvr>writeResponse>', self, msg
mjw@1623 192 self.channel.writeResponse(msg)
mjw@1623 193 else:
mjw@1623 194 print 'CtrlMsgRcvr>writeResponse>', 'no channel!', self
mjw@1623 195
mjw@1623 196 class ControllerFactory(CtrlMsgRcvr):
mjw@1623 197 """Abstract class for factories creating controllers.
mjw@1623 198 Maintains a table of instances.
mjw@1654 199
mjw@1654 200 Instance variables:
mjw@1654 201
mjw@1654 202 instances : mapping of index to controller instance
mjw@1654 203 dlist : list of deferreds
mjw@1654 204 dom : domain
mjw@1623 205 """
mjw@1623 206
mjw@1623 207 def __init__(self):
mjw@1623 208 CtrlMsgRcvr.__init__(self)
mjw@1623 209 self.instances = {}
mjw@1623 210 self.dlist = []
mjw@1623 211 self.dom = 0
mjw@1623 212
mjw@1623 213 def addInstance(self, instance):
mjw@1654 214 """Add a controller instance (under its index).
mjw@1654 215 """
mjw@1623 216 self.instances[instance.idx] = instance
mjw@1623 217
mjw@1623 218 def getInstance(self, idx):
mjw@1654 219 """Get a controller instance from its index.
mjw@1654 220 """
mjw@1623 221 return self.instances.get(idx)
mjw@1623 222
mjw@1623 223 def getInstances(self):
mjw@1654 224 """Get a list of all controller instances.
mjw@1654 225 """
mjw@1623 226 return self.instances.values()
mjw@1623 227
mjw@1623 228 def getInstanceByDom(self, dom):
mjw@1654 229 """Get the controller instance for the given domain.
mjw@1654 230 """
mjw@1623 231 for inst in self.instances.values():
mjw@1623 232 if inst.dom == dom:
mjw@1623 233 return inst
mjw@1623 234 return None
mjw@1623 235
mjw@1623 236 def delInstance(self, instance):
mjw@1654 237 """Delete an instance from the table.
mjw@1654 238 """
mjw@1623 239 if instance.idx in self.instances:
mjw@1623 240 del self.instances[instance.idx]
mjw@1623 241
mjw@1623 242 def createInstance(self, dom, recreate=0):
mjw@1654 243 """Create an instance. Define in a subclass.
mjw@1654 244 """
mjw@1623 245 raise NotImplementedError()
mjw@1623 246
mjw@1623 247 def instanceClosed(self, instance):
mjw@1654 248 """Callback called when an instance is closed (usually by the instance).
mjw@1654 249 """
mjw@1623 250 self.delInstance(instance)
mjw@1623 251
mjw@1623 252 class Controller(CtrlMsgRcvr):
mjw@1623 253 """Abstract class for a device controller attached to a domain.
mjw@1623 254 """
mjw@1623 255
mjw@1623 256 def __init__(self, factory, dom):
mjw@1623 257 CtrlMsgRcvr.__init__(self)
mjw@1623 258 self.factory = factory
mjw@1623 259 self.dom = int(dom)
mjw@1623 260 self.channel = None
mjw@1623 261 self.idx = None
mjw@1623 262
mjw@1623 263 def close(self):
mjw@1654 264 """Close the controller.
mjw@1654 265 """
mjw@1623 266 self.lostChannel()
mjw@1623 267
mjw@1623 268 def lostChannel(self):
mjw@1654 269 """The controller channel has been lost.
mjw@1654 270 """
mjw@1664 271 self.deregisterChannel()
mjw@1623 272 self.factory.instanceClosed(self)
mjw@1623 273
mjw@1623 274 class Dev:
mjw@1654 275 """Abstract class for a device attached to a device controller.
mjw@1654 276 """
mjw@1654 277
mjw@1623 278 def __init__(self, controller):
mjw@1623 279 self.controller = controller
mjw@1623 280 self.props = {}
mjw@1623 281
mjw@1623 282 def setprop(self, k, v):
mjw@1623 283 self.props[k] = v
mjw@1623 284
mjw@1623 285 def getprop(self, k, v=None):
mjw@1623 286 return self.props.get(k, v)
mjw@1623 287
mjw@1623 288 def hasprop(self, k):
mjw@1623 289 return k in self.props
mjw@1623 290
mjw@1623 291 def delprop(self, k):
mjw@1623 292 if k in self.props:
mjw@1623 293 del self.props[k]
mjw@1623 294
mjw@1623 295 def sxpr(self):
mjw@1623 296 raise NotImplementedError()
mjw@1623 297
mjw@1623 298