ia64/xen-unstable

view tools/python/xen/xend/EventServer.py @ 6552:a9873d384da4

Merge.
author adsharma@los-vmm.sc.intel.com
date Thu Aug 25 12:24:48 2005 -0700 (2005-08-25)
parents 112d44270733 fa0754a9f64f
children dfaf788ab18c
line source
1 #============================================================================
2 # This library is free software; you can redistribute it and/or
3 # modify it under the terms of version 2.1 of the GNU Lesser General Public
4 # License as published by the Free Software Foundation.
5 #
6 # This library is distributed in the hope that it will be useful,
7 # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
9 # Lesser General Public License for more details.
10 #
11 # You should have received a copy of the GNU Lesser General Public
12 # License along with this library; if not, write to the Free Software
13 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
14 #============================================================================
15 # Copyright (C) 2004, 2005 Mike Wray <mike.wray@hp.com>
16 #============================================================================
18 """Simple publish/subscribe event server.
20 """
21 import string
22 from threading import Lock
24 import scheduler
26 # subscribe a.b.c h: map a.b.c -> h
27 # subscribe a.b.* h: map a.b.* -> h
28 # subscribe a.b.? h: map a.b.? -> h
29 #
30 # for event a.b.c.d:
31 #
32 # lookup a.b.c.d, call handlers
33 #
34 # lookup a.b.c.?, call handlers
35 #
36 # lookup a.b.c.d.*, call handlers
37 # lookup a.b.c.*, call handlers
38 # lookup a.b.*, call handlers
39 # lookup a.*, call handlers
40 # lookup *, call handlers
42 # a.b.c.d = (a b c d)
43 # a.b.c.? = (a b c _)
44 # a.b.c.* = (a b c . _)
46 class EventServer:
48 DOT = '.'
49 QUERY = '?'
50 DOT_QUERY = DOT + QUERY
51 STAR = '*'
52 DOT_STAR = DOT + STAR
54 def __init__(self, run=0):
55 self.handlers = {}
56 self.run = run
57 self.queue = []
58 self.lock = Lock()
60 def start(self):
61 """Enable event handling. Sends any queued events.
62 """
63 try:
64 self.lock.acquire()
65 self.run = 1
66 queue = self.queue
67 self.queue = []
68 finally:
69 self.lock.release()
70 for (e,v) in queue:
71 self.inject(e, v)
73 def stop(self):
74 """Suspend event handling. Events injected while suspended
75 are queued until we are started again.
76 """
77 try:
78 self.lock.acquire()
79 self.run = 0
80 finally:
81 self.lock.release()
83 def subscribe(self, event, handler):
84 """Subscribe to an event. For example 'a.b.c.d'.
85 A subcription like 'a.b.c.?' ending in '?' matches any value
86 for the '?'. A subscription like 'a.b.c.*' ending in '*' matches
87 any event type with the same prefix, 'a.b.c' in this case.
89 event event name
90 handler event handler fn(event, val)
91 """
92 try:
93 self.lock.acquire()
94 hl = self.handlers.get(event)
95 if hl is None:
96 self.handlers[event] = [handler]
97 else:
98 hl.append(handler)
99 finally:
100 self.lock.release()
102 def unsubscribe_all(self, event=None):
103 """Unsubscribe all handlers for a given event, or all handlers.
105 event event (optional)
106 """
107 try:
108 self.lock.acquire()
109 if event == None:
110 self.handlers.clear()
111 elif event in self.handlers:
112 del self.handlers[event]
113 finally:
114 self.lock.release()
116 def unsubscribe(self, event, handler):
117 """Unsubscribe a given event and handler.
119 event event
120 handler handler
121 """
122 try:
123 self.lock.acquire()
124 hl = self.handlers.get(event)
125 if hl is None:
126 return
127 if handler in hl:
128 hl.remove(handler)
129 finally:
130 self.lock.release()
132 def inject(self, event, val, async=1):
133 """Inject an event. Handlers for it are called if running, otherwise
134 it is queued.
136 event event type
137 val event value
138 """
139 try:
140 self.lock.acquire()
141 if not self.run:
142 self.queue.append( (event, val) )
143 return
144 finally:
145 self.lock.release()
147 if async:
148 scheduler.now(self.call_handlers, [event, val])
149 else:
150 self.call_handlers(event, val)
152 def call_handlers(self, event, val):
153 """Internal method to call event handlers.
154 """
155 #print ">event", event, val
156 self.call_event_handlers(event, event, val)
157 self.call_query_handlers(event, val)
158 self.call_star_handlers(event, val)
160 def call_event_handlers(self, key, event, val):
161 """Call the handlers for an event.
162 It is safe for handlers to subscribe or unsubscribe.
164 key key for handler list
165 event event type
166 val event value
167 """
168 try:
169 self.lock.acquire()
170 hl = self.handlers.get(key)
171 if hl is None:
172 return
173 # Copy the handler list so that handlers can call
174 # subscribe/unsubscribe safely - python list iteration
175 # is not safe against list modification.
176 hl = hl[:]
177 finally:
178 self.lock.release()
179 # Must not hold the lock while calling the handlers.
180 for h in hl:
181 try:
182 h(event, val)
183 except:
184 pass
186 def call_query_handlers(self, event, val):
187 """Call regex handlers for events matching 'event' that end in '?'.
189 event event type
190 val event value
191 """
192 dot_idx = event.rfind(self.DOT)
193 if dot_idx == -1:
194 self.call_event_handlers(self.QUERY, event, val)
195 else:
196 event_query = event[0:dot_idx] + self.DOT_QUERY
197 self.call_event_handlers(event_query, event, val)
199 def call_star_handlers(self, event, val):
200 """Call regex handlers for events matching 'event' that end in '*'.
202 event event type
203 val event value
204 """
205 etype = string.split(event, self.DOT)
206 for i in range(len(etype), 0, -1):
207 event_star = self.DOT.join(etype[0:i]) + self.DOT_STAR
208 self.call_event_handlers(event_star, event, val)
209 self.call_event_handlers(self.STAR, event, val)
211 def instance():
212 global inst
213 try:
214 inst
215 except:
216 inst = EventServer()
217 inst.start()
218 return inst
220 def main():
221 def sys_star(event, val):
222 print 'sys_star', event, val
224 def sys_foo(event, val):
225 print 'sys_foo', event, val
226 s.unsubscribe('sys.foo', sys_foo)
228 def sys_foo2(event, val):
229 print 'sys_foo2', event, val
231 def sys_bar(event, val):
232 print 'sys_bar', event, val
234 def sys_foo_bar(event, val):
235 print 'sys_foo_bar', event, val
237 def foo_bar(event, val):
238 print 'foo_bar', event, val
240 s = EventServer()
241 s.start()
242 s.subscribe('sys.*', sys_star)
243 s.subscribe('sys.foo', sys_foo)
244 s.subscribe('sys.foo', sys_foo2)
245 s.subscribe('sys.bar', sys_bar)
246 s.subscribe('sys.foo.bar', sys_foo_bar)
247 s.subscribe('foo.bar', foo_bar)
248 s.inject('sys.foo', 'hello')
249 print
250 s.inject('sys.bar', 'hello again')
251 print
252 s.inject('sys.foo.bar', 'hello again')
253 print
254 s.inject('foo.bar', 'hello again')
255 print
256 s.inject('foo', 'hello again')
257 print
258 s.start()
259 s.unsubscribe('sys.*', sys_star)
260 s.unsubscribe_all('sys.*')
261 s.inject('sys.foo', 'hello')
263 if __name__ == "__main__":
264 main()