[libvirt] Domain Event Handlers

Hello, I have been playing around with the libvirt domain event handlers in Python and am seeing something surprising. I am using trunk libvirt and `event-test.py` with some more of the debugging strings uncommented. When I trigger my first event: virsh # define xppro-sp2-0.img.xml Domain xppro-sp2-0.img defined from xppro-sp2-0.img.xml The timeout and handle callbacks are called, but not my domainEventRegister handler: Invoking Timeout CB Invoking Handle CB When I trigger a second event: virsh # create xppro-sp2-0.img.xml Domain xppro-sp2-0.img created from xppro-sp2-0.img.xml my event handler for the first event is finally called: Invoking Timeout CB domainEventHandler EVENT: Domain xppro-sp2-0.img(-1) Added 1 Invoking Handle CB Likewise for a third event: virsh # destroy xppro-sp2-0.img Domain xppro-sp2-0.img destroyed Invoking Timeout CB domainEventHandler EVENT: Domain xppro-sp2-0.img(1) Started 0 Invoking Handle CB So my handler is always one event behind. This behavior is not intended is it? Am I missing either something in `event-test.py` or in how I am using virsh that would correct this behavior? Thank you, Noah

On Thu, May 14, 2009 at 06:43:10PM -0700, Noah Zoschke wrote:
Hello,
I have been playing around with the libvirt domain event handlers in Python and am seeing something surprising. I am using trunk libvirt and `event-test.py` with some more of the debugging strings uncommented.
When I trigger my first event:
[snip]
So my handler is always one event behind.
This behavior is not intended is it? Am I missing either something in `event-test.py` or in how I am using virsh that would correct this behavior?
This is not intended behaviour. I have verified that I see the same problem when running the event-test.py demo program. The C based example event-test.c does work correctly. So either this is a bug in the python demo program, or a bug in the python APIs for events. Not sure which yet... Regards, Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Mon, May 18, 2009 at 01:25:35PM +0100, Daniel P. Berrange wrote:
On Thu, May 14, 2009 at 06:43:10PM -0700, Noah Zoschke wrote:
Hello,
I have been playing around with the libvirt domain event handlers in Python and am seeing something surprising. I am using trunk libvirt and `event-test.py` with some more of the debugging strings uncommented.
When I trigger my first event:
[snip]
So my handler is always one event behind.
This behavior is not intended is it? Am I missing either something in `event-test.py` or in how I am using virsh that would correct this behavior?
This is not intended behaviour. I have verified that I see the same problem when running the event-test.py demo program. The C based example event-test.c does work correctly. So either this is a bug in the python demo program, or a bug in the python APIs for events. Not sure which yet...
The demo program is horribly broken wrt handling timeouts Also the python binding was not incrementing the ref count on the domain objects it was wrapping. Daniel diff -r 08f3de2814fb examples/domain-events/events-python/event-test.py --- a/examples/domain-events/events-python/event-test.py Mon May 18 13:15:33 2009 +0100 +++ b/examples/domain-events/events-python/event-test.py Mon May 18 13:53:59 2009 +0100 @@ -6,6 +6,8 @@ import select mypoll = select.poll() TIMEOUT_MS = 1000 +debug = False + # handle globals h_fd = 0 h_events = 0 @@ -66,8 +68,9 @@ def myPollEventToEventHandleType(events) return ret; def myAddHandle(fd, events, cb, opaque): - global h_fd, h_events, h_cb, h_opaque - #print "Adding Handle %s %s %s %s" % (str(fd), str(events), str(cb), str(opaque)) + global h_fd, h_events, h_cb, h_opaque, debug + if debug: + print "Adding Handle %s %s %s %s" % (str(fd), str(events), str(cb), str(opaque)) h_fd = fd h_events = events h_cb = cb @@ -76,36 +79,48 @@ def myAddHandle(fd, events, cb, opaque): return 0 def myUpdateHandle(watch, event): - global h_fd, h_events - #print "Updating Handle %s %s" % (str(h_fd), str(event)) + global h_fd, h_events, debug + if debug: + print "Updating Handle %s %s" % (str(h_fd), str(event)) h_events = event mypoll.unregister(h_fd) mypoll.register(h_fd, myEventHandleTypeToPollEvent(event)) def myRemoveHandle(watch): - global h_fd - #print "Removing Handle %s" % str(h_fd) + global h_fd, debug + if debug: + print "Removing Handle %s" % str(h_fd) mypoll.unregister(h_fd) h_fd = 0 return h_opaque def myAddTimeout(timeout, cb, opaque): - global t_active, t_timeout, t_cb, t_opaque - #print "Adding Timeout %s %s %s" % (str(timeout), str(cb), str(opaque)) - t_active = 1; + global t_active, t_timeout, t_cb, t_opaque, debug + if debug: + print "Adding Timeout %s %s %s" % (str(timeout), str(cb), str(opaque)) + if timeout == -1: + t_active = 0 + else: + t_active = 1 t_timeout = timeout; t_cb = cb; t_opaque = opaque; return 0 def myUpdateTimeout(timer, timeout): - global t_timeout - #print "Updating Timeout %s %s" % (str(timer), str(timeout)) + global t_timeout, t_active, debug + if debug: + print "Updating Timeout %s %s" % (str(timer), str(timeout)) + if timeout == -1: + t_active = 0 + else: + t_active = 1 t_timeout = timeout; def myRemoveTimeout(timer): - global t_active - #print "Removing Timeout %s" % str(timer) + global t_active, debug + if debug: + print "Removing Timeout %s" % str(timer) t_active = 0; return t_opaque @@ -159,6 +174,8 @@ def main(): while 1: try: + if debug: + print "Poll sleep %d" % t_active sts = mypoll.poll(TIMEOUT_MS) except select.error, err: if err[0] == errno.EINTR: @@ -168,17 +185,19 @@ def main(): print "Keyboard Interrupt caught - exiting cleanly" break + if t_cb and t_active == 1: + if debug: + print "Invoking Timeout CB" + t_cb(t_timeout, t_opaque[0], t_opaque[1]) + if not sts: - #print "Timed out" + if debug: + print "Timed out" continue rfd = sts[0][0] revents = sts[0][1] - if t_active: - #print "Invoking Timeout CB" - t_cb(t_timeout, t_opaque[0], t_opaque[1]) - if revents & select.POLLHUP: print "Reset by peer"; return -1; diff -r 08f3de2814fb python/libvir.c --- a/python/libvir.c Mon May 18 13:15:33 2009 +0100 +++ b/python/libvir.c Mon May 18 13:53:59 2009 +0100 @@ -1653,6 +1653,7 @@ libvirt_virConnectDomainEventCallback(vi LIBVIRT_ENSURE_THREAD_STATE; /* Create a python instance of this virDomainPtr */ + virDomainRef(dom); pyobj_dom = libvirt_virDomainPtrWrap(dom); pyobj_dom_args = PyTuple_New(2); if(PyTuple_SetItem(pyobj_dom_args, 0, pyobj_conn_inst)!=0) { Daniel -- |: Red Hat, Engineering, London -o- http://people.redhat.com/berrange/ :| |: http://libvirt.org -o- http://virt-manager.org -o- http://ovirt.org :| |: http://autobuild.org -o- http://search.cpan.org/~danberr/ :| |: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|

On Mon, May 18, 2009 at 01:54:28PM +0100, Daniel P. Berrange wrote:
On Mon, May 18, 2009 at 01:25:35PM +0100, Daniel P. Berrange wrote:
On Thu, May 14, 2009 at 06:43:10PM -0700, Noah Zoschke wrote:
Hello,
I have been playing around with the libvirt domain event handlers in Python and am seeing something surprising. I am using trunk libvirt and `event-test.py` with some more of the debugging strings uncommented.
When I trigger my first event:
[snip]
So my handler is always one event behind.
This behavior is not intended is it? Am I missing either something in `event-test.py` or in how I am using virsh that would correct this behavior?
This is not intended behaviour. I have verified that I see the same problem when running the event-test.py demo program. The C based example event-test.c does work correctly. So either this is a bug in the python demo program, or a bug in the python APIs for events. Not sure which yet...
The demo program is horribly broken wrt handling timeouts
Also the python binding was not incrementing the ref count on the domain objects it was wrapping.
Daniel
diff -r 08f3de2814fb examples/domain-events/events-python/event-test.py --- a/examples/domain-events/events-python/event-test.py Mon May 18 13:15:33 2009 +0100 +++ b/examples/domain-events/events-python/event-test.py Mon May 18 13:53:59 2009 +0100 @@ -6,6 +6,8 @@ import select mypoll = select.poll() TIMEOUT_MS = 1000
+debug = False + # handle globals h_fd = 0 h_events = 0 @@ -66,8 +68,9 @@ def myPollEventToEventHandleType(events) return ret;
def myAddHandle(fd, events, cb, opaque): - global h_fd, h_events, h_cb, h_opaque - #print "Adding Handle %s %s %s %s" % (str(fd), str(events), str(cb), str(opaque)) + global h_fd, h_events, h_cb, h_opaque, debug + if debug: + print "Adding Handle %s %s %s %s" % (str(fd), str(events), str(cb), str(opaque)) h_fd = fd h_events = events h_cb = cb @@ -76,36 +79,48 @@ def myAddHandle(fd, events, cb, opaque): return 0
def myUpdateHandle(watch, event): - global h_fd, h_events - #print "Updating Handle %s %s" % (str(h_fd), str(event)) + global h_fd, h_events, debug + if debug: + print "Updating Handle %s %s" % (str(h_fd), str(event)) h_events = event mypoll.unregister(h_fd) mypoll.register(h_fd, myEventHandleTypeToPollEvent(event))
def myRemoveHandle(watch): - global h_fd - #print "Removing Handle %s" % str(h_fd) + global h_fd, debug + if debug: + print "Removing Handle %s" % str(h_fd) mypoll.unregister(h_fd) h_fd = 0 return h_opaque
def myAddTimeout(timeout, cb, opaque): - global t_active, t_timeout, t_cb, t_opaque - #print "Adding Timeout %s %s %s" % (str(timeout), str(cb), str(opaque)) - t_active = 1; + global t_active, t_timeout, t_cb, t_opaque, debug + if debug: + print "Adding Timeout %s %s %s" % (str(timeout), str(cb), str(opaque)) + if timeout == -1: + t_active = 0 + else: + t_active = 1 t_timeout = timeout; t_cb = cb; t_opaque = opaque; return 0
def myUpdateTimeout(timer, timeout): - global t_timeout - #print "Updating Timeout %s %s" % (str(timer), str(timeout)) + global t_timeout, t_active, debug + if debug: + print "Updating Timeout %s %s" % (str(timer), str(timeout)) + if timeout == -1: + t_active = 0 + else: + t_active = 1 t_timeout = timeout;
def myRemoveTimeout(timer): - global t_active - #print "Removing Timeout %s" % str(timer) + global t_active, debug + if debug: + print "Removing Timeout %s" % str(timer) t_active = 0; return t_opaque
@@ -159,6 +174,8 @@ def main():
while 1: try: + if debug: + print "Poll sleep %d" % t_active sts = mypoll.poll(TIMEOUT_MS) except select.error, err: if err[0] == errno.EINTR: @@ -168,17 +185,19 @@ def main(): print "Keyboard Interrupt caught - exiting cleanly" break
+ if t_cb and t_active == 1: + if debug: + print "Invoking Timeout CB" + t_cb(t_timeout, t_opaque[0], t_opaque[1]) + if not sts: - #print "Timed out" + if debug: + print "Timed out" continue
rfd = sts[0][0] revents = sts[0][1]
- if t_active: - #print "Invoking Timeout CB" - t_cb(t_timeout, t_opaque[0], t_opaque[1]) - if revents & select.POLLHUP: print "Reset by peer"; return -1; diff -r 08f3de2814fb python/libvir.c --- a/python/libvir.c Mon May 18 13:15:33 2009 +0100 +++ b/python/libvir.c Mon May 18 13:53:59 2009 +0100 @@ -1653,6 +1653,7 @@ libvirt_virConnectDomainEventCallback(vi LIBVIRT_ENSURE_THREAD_STATE;
/* Create a python instance of this virDomainPtr */ + virDomainRef(dom); pyobj_dom = libvirt_virDomainPtrWrap(dom); pyobj_dom_args = PyTuple_New(2); if(PyTuple_SetItem(pyobj_dom_args, 0, pyobj_conn_inst)!=0) {
ACK, looks fine to me, Daniel -- Daniel Veillard | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ daniel@veillard.com | Rpmfind RPM search engine http://rpmfind.net/ http://veillard.com/ | virtualization library http://libvirt.org/
participants (3)
-
Daniel P. Berrange
-
Daniel Veillard
-
Noah Zoschke