From nobody Fri May 3 09:26:16 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1491316310576131.53313808523126; Tue, 4 Apr 2017 07:31:50 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 0728D65CFF; Tue, 4 Apr 2017 14:31:49 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id C9BF299EAD; Tue, 4 Apr 2017 14:31:48 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 8068318523C5; Tue, 4 Apr 2017 14:31:48 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v34EVi3x024995 for ; Tue, 4 Apr 2017 10:31:44 -0400 Received: by smtp.corp.redhat.com (Postfix) id 60E1090C78; Tue, 4 Apr 2017 14:31:44 +0000 (UTC) Received: from dhcp-17-113.lcy.redhat.com (unknown [10.42.17.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9CEF08FE4E; Tue, 4 Apr 2017 14:31:41 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 0728D65CFF Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 0728D65CFF From: "Daniel P. Berrange" To: libvir-list@redhat.com Date: Tue, 4 Apr 2017 15:31:28 +0100 Message-Id: <20170404143134.12141-2-berrange@redhat.com> In-Reply-To: <20170404143134.12141-1-berrange@redhat.com> References: <20170404143134.12141-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-loop: libvir-list@redhat.com Cc: Wojtek Porczyk Subject: [libvirt] [PATCH v3 1/7] Allow for ff callbacks to be called by custom event implementations X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Tue, 04 Apr 2017 14:31:49 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: Wojtek Porczyk The documentation says: > If the opaque user data requires free'ing when the handle is > unregistered, then a 2nd callback can be supplied for this purpose. > This callback needs to be invoked from a clean stack. If 'ff' > callbacks are invoked directly from the virEventRemoveHandleFunc they > will likely deadlock in libvirt. And they did deadlock. In removeTimeout too. Now we supply a custom function to pick it from the opaque blob and fire. Signed-off-by: Wojtek Porczyk Signed-off-by: Daniel P. Berrange --- libvirt-override.c | 68 ++++++++++++++++++++++++++++++-------------------= ---- libvirt-override.py | 23 ++++++++++++++++++ sanitytest.py | 3 ++- 3 files changed, 63 insertions(+), 31 deletions(-) diff --git a/libvirt-override.c b/libvirt-override.c index 93c7ef0..a762941 100644 --- a/libvirt-override.c +++ b/libvirt-override.c @@ -5223,6 +5223,9 @@ libvirt_virEventAddHandleFunc(int fd, =20 VIR_PY_TUPLE_SET_GOTO(pyobj_args, 3, cb_args, cleanup); =20 + /* If changing contents of the opaque object, please also change + * virEventInvokeFreeCallback() in libvirt-override.py + */ VIR_PY_TUPLE_SET_GOTO(cb_args, 0, libvirt_virEventHandleCallbackWrap(c= b), cleanup); VIR_PY_TUPLE_SET_GOTO(cb_args, 1, libvirt_virVoidPtrWrap(opaque), clea= nup); VIR_PY_TUPLE_SET_GOTO(cb_args, 2, libvirt_virFreeCallbackWrap(ff), cle= anup); @@ -5279,10 +5282,7 @@ libvirt_virEventRemoveHandleFunc(int watch) { PyObject *result =3D NULL; PyObject *pyobj_args; - PyObject *opaque; - PyObject *ff; int retval =3D -1; - virFreeCallback cff; =20 LIBVIRT_ENSURE_THREAD_STATE; =20 @@ -5292,20 +5292,11 @@ libvirt_virEventRemoveHandleFunc(int watch) VIR_PY_TUPLE_SET_GOTO(pyobj_args, 0, libvirt_intWrap(watch), cleanup); =20 result =3D PyEval_CallObject(removeHandleObj, pyobj_args); - if (!result) { + if (result) { + retval =3D 0; + } else { PyErr_Print(); PyErr_Clear(); - } else if (!PyTuple_Check(result) || PyTuple_Size(result) !=3D 3) { - DEBUG("%s: %s must return opaque obj registered with %s" - "to avoid leaking libvirt memory\n", - __FUNCTION__, NAME(removeHandle), NAME(addHandle)); - } else { - opaque =3D PyTuple_GetItem(result, 1); - ff =3D PyTuple_GetItem(result, 2); - cff =3D PyvirFreeCallback_Get(ff); - if (cff) - (*cff)(PyvirVoidPtr_Get(opaque)); - retval =3D 0; } =20 cleanup: @@ -5350,6 +5341,9 @@ libvirt_virEventAddTimeoutFunc(int timeout, =20 VIR_PY_TUPLE_SET_GOTO(pyobj_args, 2, cb_args, cleanup); =20 + /* If changing contents of the opaque object, please also change + * virEventInvokeFreeCallback() in libvirt-override.py + */ VIR_PY_TUPLE_SET_GOTO(cb_args, 0, libvirt_virEventTimeoutCallbackWrap(= cb), cleanup); VIR_PY_TUPLE_SET_GOTO(cb_args, 1, libvirt_virVoidPtrWrap(opaque), clea= nup); VIR_PY_TUPLE_SET_GOTO(cb_args, 2, libvirt_virFreeCallbackWrap(ff), cle= anup); @@ -5403,10 +5397,7 @@ libvirt_virEventRemoveTimeoutFunc(int timer) { PyObject *result =3D NULL; PyObject *pyobj_args; - PyObject *opaque; - PyObject *ff; int retval =3D -1; - virFreeCallback cff; =20 LIBVIRT_ENSURE_THREAD_STATE; =20 @@ -5416,20 +5407,11 @@ libvirt_virEventRemoveTimeoutFunc(int timer) VIR_PY_TUPLE_SET_GOTO(pyobj_args, 0, libvirt_intWrap(timer), cleanup); =20 result =3D PyEval_CallObject(removeTimeoutObj, pyobj_args); - if (!result) { + if (result) { + retval =3D 0; + } else { PyErr_Print(); PyErr_Clear(); - } else if (!PyTuple_Check(result) || PyTuple_Size(result) !=3D 3) { - DEBUG("%s: %s must return opaque obj registered with %s" - "to avoid leaking libvirt memory\n", - __FUNCTION__, NAME(removeTimeout), NAME(addTimeout)); - } else { - opaque =3D PyTuple_GetItem(result, 1); - ff =3D PyTuple_GetItem(result, 2); - cff =3D PyvirFreeCallback_Get(ff); - if (cff) - (*cff)(PyvirVoidPtr_Get(opaque)); - retval =3D 0; } =20 cleanup: @@ -5558,6 +5540,31 @@ libvirt_virEventInvokeTimeoutCallback(PyObject *self= ATTRIBUTE_UNUSED, return VIR_PY_INT_SUCCESS; } =20 +static PyObject * +libvirt_virEventInvokeFreeCallback(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + PyObject *py_f; + PyObject *py_opaque; + virFreeCallback cb; + void *opaque; + + if (!PyArg_ParseTuple(args, (char *) "OO:virEventInvokeFreeCallback", + &py_f, &py_opaque)) + return NULL; + + cb =3D (virFreeCallback) PyvirEventHandleCallback_Get(py_f); + opaque =3D (void *) PyvirVoidPtr_Get(py_opaque); + + if (cb) { + LIBVIRT_BEGIN_ALLOW_THREADS; + cb(opaque); + LIBVIRT_END_ALLOW_THREADS; + } + + return VIR_PY_INT_SUCCESS; +} + static void libvirt_virEventHandleCallback(int watch, int fd, @@ -9572,6 +9579,7 @@ static PyMethodDef libvirtMethods[] =3D { {(char *) "virEventAddTimeout", libvirt_virEventAddTimeout, METH_VARAR= GS, NULL}, {(char *) "virEventInvokeHandleCallback", libvirt_virEventInvokeHandle= Callback, METH_VARARGS, NULL}, {(char *) "virEventInvokeTimeoutCallback", libvirt_virEventInvokeTimeo= utCallback, METH_VARARGS, NULL}, + {(char *) "virEventInvokeFreeCallback", libvirt_virEventInvokeFreeCall= back, METH_VARARGS, NULL}, {(char *) "virNodeListDevices", libvirt_virNodeListDevices, METH_VARAR= GS, NULL}, #if LIBVIR_CHECK_VERSION(0, 10, 2) {(char *) "virConnectListAllNodeDevices", libvirt_virConnectListAllNod= eDevices, METH_VARARGS, NULL}, diff --git a/libvirt-override.py b/libvirt-override.py index 63f8ecb..b0b24ef 100644 --- a/libvirt-override.py +++ b/libvirt-override.py @@ -211,3 +211,26 @@ def virEventAddTimeout(timeout, cb, opaque): ret =3D libvirtmod.virEventAddTimeout(timeout, cbData) if ret =3D=3D -1: raise libvirtError ('virEventAddTimeout() failed') return ret + + +# +# a caller for the ff callbacks for custom event loop implementations +# + +def virEventInvokeFreeCallback(opaque): + """ + Execute callback which frees the opaque buffer + + @opaque: the opaque object passed to addHandle or addTimeout + + WARNING: This function should not be called from any call by libvirt's + core. It will most probably cause deadlock in C-level libvirt code. + Instead it should be scheduled and called from implementation's stack. + + See https://libvirt.org/html/libvirt-libvirt-event.html#virEventAddHan= dleFunc + for more information. + + This function is not dependent on any event loop implementation. + """ + + libvirtmod.virEventInvokeFreeCallback(opaque[2], opaque[1]) diff --git a/sanitytest.py b/sanitytest.py index a140ba2..7183baa 100644 --- a/sanitytest.py +++ b/sanitytest.py @@ -349,7 +349,8 @@ for klass in gotfunctions: continue for func in sorted(gotfunctions[klass]): # These are pure python methods with no C APi - if func in ["connect", "getConnect", "domain", "getDomain"]: + if func in ["connect", "getConnect", "domain", "getDomain", + "virEventInvokeFreeCallback"]: continue =20 key =3D "%s.%s" % (klass, func) --=20 2.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Fri May 3 09:26:16 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1491316314389539.7390741321568; Tue, 4 Apr 2017 07:31:54 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 15F9267EB9; Tue, 4 Apr 2017 14:31:53 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id D79E67F625; Tue, 4 Apr 2017 14:31:52 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 7B2E218523CE; Tue, 4 Apr 2017 14:31:52 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v34EVjRD025000 for ; Tue, 4 Apr 2017 10:31:45 -0400 Received: by smtp.corp.redhat.com (Postfix) id 545604F9E9; Tue, 4 Apr 2017 14:31:45 +0000 (UTC) Received: from dhcp-17-113.lcy.redhat.com (unknown [10.42.17.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id A3E968FE4E; Tue, 4 Apr 2017 14:31:44 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 15F9267EB9 Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx09.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 15F9267EB9 From: "Daniel P. Berrange" To: libvir-list@redhat.com Date: Tue, 4 Apr 2017 15:31:29 +0100 Message-Id: <20170404143134.12141-3-berrange@redhat.com> In-Reply-To: <20170404143134.12141-1-berrange@redhat.com> References: <20170404143134.12141-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-loop: libvir-list@redhat.com Cc: Wojtek Porczyk Subject: [libvirt] [PATCH v3 2/7] Add asyncio event loop implementation X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Tue, 04 Apr 2017 14:31:53 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: Wojtek Porczyk This is usable only on python >=3D 3.4 (or 3.3 with out-of-tree asyncio), however it should be harmless for anyone with older python versions. In simplest case, to have the callbacks queued on the default loop: >>> import libvirtaio >>> libvirtaio.virEventRegisterAsyncIOImpl() The function is not present on non-compatible platforms. Signed-off-by: Wojtek Porczyk --- MANIFEST.in | 1 + libvirt-python.spec.in | 2 + libvirtaio.py | 399 +++++++++++++++++++++++++++++++++++++++++++++= ++++ setup.py | 12 ++ 4 files changed, 414 insertions(+) create mode 100644 libvirtaio.py diff --git a/MANIFEST.in b/MANIFEST.in index 0d66f9c..b6788f4 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -31,6 +31,7 @@ include libvirt-qemu-override-api.xml include libvirt-qemu-override.c include libvirt-utils.h include libvirt-utils.c +include libvirtaio.py include MANIFEST include README include sanitytest.py diff --git a/libvirt-python.spec.in b/libvirt-python.spec.in index 3021ebd..5ad0292 100644 --- a/libvirt-python.spec.in +++ b/libvirt-python.spec.in @@ -86,11 +86,13 @@ rm -f %{buildroot}%{_libdir}/python*/site-packages/*egg= -info %defattr(-,root,root) %doc ChangeLog AUTHORS NEWS README COPYING COPYING.LESSER examples/ %{_libdir}/python3*/site-packages/libvirt.py* +%{_libdir}/python3*/site-packages/libvirtaio.py* %{_libdir}/python3*/site-packages/libvirt_qemu.py* %{_libdir}/python3*/site-packages/libvirt_lxc.py* %{_libdir}/python3*/site-packages/__pycache__/libvirt.cpython-*.py* %{_libdir}/python3*/site-packages/__pycache__/libvirt_qemu.cpython-*.py* %{_libdir}/python3*/site-packages/__pycache__/libvirt_lxc.cpython-*.py* +%{_libdir}/python3*/site-packages/__pycache__/libvirtaio.cpython-*.py* %{_libdir}/python3*/site-packages/libvirtmod* %endif =20 diff --git a/libvirtaio.py b/libvirtaio.py new file mode 100644 index 0000000..7c8c396 --- /dev/null +++ b/libvirtaio.py @@ -0,0 +1,399 @@ +# +# libvirtaio -- asyncio adapter for libvirt +# Copyright (C) 2017 Wojtek Porczyk +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, see +# . +# + +'''Libvirt event loop implementation using asyncio + +Register the implementation of default loop: + + >>> import libvirtaio + >>> libvirtaio.virEventRegisterAsyncIOImpl() + +.. seealso:: + https://libvirt.org/html/libvirt-libvirt-event.html +''' + +__author__ =3D 'Wojtek Porczyk ' +__license__ =3D 'LGPL-2.1+' +__all__ =3D ['virEventAsyncIOImpl', 'virEventRegisterAsyncIOImpl'] + +import asyncio +import itertools +import logging +import warnings + +import libvirt + +try: + from asyncio import ensure_future +except ImportError: + from asyncio import async as ensure_future + + +class Callback(object): + '''Base class for holding callback + + :param virEventAsyncIOImpl impl: the implementation in which we run + :param cb: the callback itself + :param opaque: the opaque tuple passed by libvirt + ''' + # pylint: disable=3Dtoo-few-public-methods + + _iden_counter =3D itertools.count() + + def __init__(self, impl, cb, opaque, *args, **kwargs): + super().__init__(*args, **kwargs) + self.iden =3D next(self._iden_counter) + self.impl =3D impl + self.cb =3D cb + self.opaque =3D opaque + + assert self.iden not in self.impl.callbacks, \ + 'found {} callback: {!r}'.format( + self.iden, self.impl.callbacks[self.iden]) + self.impl.callbacks[self.iden] =3D self + + def __repr__(self): + return '<{} iden=3D{}>'.format(self.__class__.__name__, self.iden) + + def close(self): + '''Schedule *ff* callback''' + self.impl.log.debug('callback %d close(), scheduling ff', self.ide= n) + self.impl.schedule_ff_callback(self.opaque) + +# +# file descriptors +# + +class Descriptor(object): + '''Manager of one file descriptor + + :param virEventAsyncIOImpl impl: the implementation in which we run + :param int fd: the file descriptor + ''' + def __init__(self, impl, fd): + self.impl =3D impl + self.fd =3D fd + self.callbacks =3D {} + + def _handle(self, event): + '''Dispatch the event to the descriptors + + :param int event: The event (from libvirt's constants) being dispa= tched + ''' + for callback in self.callbacks.values(): + if callback.event is not None and callback.event & event: + callback.cb(callback.iden, self.fd, event, callback.opaque) + + def update(self): + '''Register or unregister callbacks at event loop + + This should be called after change of any ``.event`` in callbacks. + ''' + # It seems like loop.add_{reader,writer} can be run multiple times + # and will still register the callback only once. Likewise, + # remove_{reader,writer} may be run even if the reader/writer + # is not registered (and will just return False). + + # For the edge case of empty callbacks, any() returns False. + if any(callback.event & ~( + libvirt.VIR_EVENT_HANDLE_READABLE | + libvirt.VIR_EVENT_HANDLE_WRITABLE) + for callback in self.callbacks.values()): + warnings.warn( + 'The only event supported are VIR_EVENT_HANDLE_READABLE ' + 'and VIR_EVENT_HANDLE_WRITABLE', + UserWarning) + + if any(callback.event & libvirt.VIR_EVENT_HANDLE_READABLE + for callback in self.callbacks.values()): + self.impl.loop.add_reader( + self.fd, self._handle, libvirt.VIR_EVENT_HANDLE_READABLE) + else: + self.impl.loop.remove_reader(self.fd) + + if any(callback.event & libvirt.VIR_EVENT_HANDLE_WRITABLE + for callback in self.callbacks.values()): + self.impl.loop.add_writer( + self.fd, self._handle, libvirt.VIR_EVENT_HANDLE_WRITABLE) + else: + self.impl.loop.remove_writer(self.fd) + + def add_handle(self, callback): + '''Add a callback to the descriptor + + :param FDCallback callback: the callback to add + :rtype: None + + After adding the callback, it is immediately watched. + ''' + self.callbacks[callback.iden] =3D callback + self.update() + + def remove_handle(self, iden): + '''Remove a callback from the descriptor + + :param int iden: the identifier of the callback + :returns: the callback + :rtype: FDCallback + + After removing the callback, the descriptor may be unwatched, if t= here + are no more handles for it. + ''' + callback =3D self.callbacks.pop(iden) + self.update() + return callback + + def close(self): + '''''' + self.callbacks.clear() + self.update() + +class DescriptorDict(dict): + '''Descriptors collection + + This is used internally by virEventAsyncIOImpl to hold descriptors. + ''' + def __init__(self, impl): + super().__init__() + self.impl =3D impl + + def __missing__(self, fd): + descriptor =3D Descriptor(self.impl, fd) + self[fd] =3D descriptor + return descriptor + +class FDCallback(Callback): + '''Callback for file descriptor (watcher) + + :param Descriptor descriptor: the descriptor manager + :param int event: bitset of events on which to fire the callback + ''' + # pylint: disable=3Dtoo-few-public-methods + + def __init__(self, *args, descriptor, event, **kwargs): + super().__init__(*args, **kwargs) + self.descriptor =3D descriptor + self.event =3D event + + def __repr__(self): + return '<{} iden=3D{} fd=3D{} event=3D{}>'.format( + self.__class__.__name__, self.iden, self.descriptor.fd, self.e= vent) + + def update(self, event): + '''Update the callback and fix descriptor's watchers''' + self.event =3D event + self.descriptor.update() + +# +# timeouts +# + +class TimeoutCallback(Callback): + '''Callback for timer''' + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.timeout =3D -1 + self._task =3D None + + def __repr__(self): + return '<{} iden=3D{} timeout=3D{}>'.format( + self.__class__.__name__, self.iden, self.timeout) + + @asyncio.coroutine + def _timer(self): + '''An actual timer running on the event loop. + + This is a coroutine. + ''' + while True: + try: + if self.timeout > 0: + timeout =3D self.timeout * 1e-3 + self.impl.log.debug('sleeping %r', timeout) + yield from asyncio.sleep(timeout) + else: + # scheduling timeout for next loop iteration + yield + + except asyncio.CancelledError: + self.impl.log.debug('timer %d cancelled', self.iden) + break + + self.cb(self.iden, self.opaque) + self.impl.log.debug('timer %r callback ended', self.iden) + + def update(self, timeout): + '''Start or the timer, possibly updating timeout''' + self.timeout =3D timeout + + if self.timeout >=3D 0 and self._task is None: + self.impl.log.debug('timer %r start', self.iden) + self._task =3D ensure_future(self._timer(), + loop=3Dself.impl.loop) + + elif self.timeout < 0 and self._task is not None: + self.impl.log.debug('timer %r stop', self.iden) + self._task.cancel() # pylint: disable=3Dno-member + self._task =3D None + + def close(self): + '''Stop the timer and call ff callback''' + super(TimeoutCallback, self).close() + self.update(timeout=3D-1) + +# +# main implementation +# + +class virEventAsyncIOImpl(object): + '''Libvirt event adapter to asyncio. + + :param loop: asyncio's event loop + + If *loop* is not specified, the current (or default) event loop is use= d. + ''' + + def __init__(self, loop=3DNone): + self.loop =3D loop or asyncio.get_event_loop() + self.callbacks =3D {} + self.descriptors =3D DescriptorDict(self) + self.log =3D logging.getLogger(self.__class__.__name__) + + def register(self): + '''Register this instance as event loop implementation''' + # pylint: disable=3Dbad-whitespace + self.log.debug('register()') + libvirt.virEventRegisterImpl( + self._add_handle, self._update_handle, self._remove_handle, + self._add_timeout, self._update_timeout, self._remove_timeout) + return self + + def schedule_ff_callback(self, opaque): + '''Schedule a ff callback from one of the handles or timers''' + self.loop.call_soon(libvirt.virEventInvokeFreeCallback, opaque) + + def is_idle(self): + '''Returns False if there are leftovers from a connection + + Those may happen if there are sematical problems while closing + a connection. For example, not deregistered events before .close(). + ''' + return not self.callbacks + + def _add_handle(self, fd, event, cb, opaque): + '''Register a callback for monitoring file handle events + + :param int fd: file descriptor to listen on + :param int event: bitset of events on which to fire the callback + :param cb: the callback to be called when an event occurrs + :param opaque: user data to pass to the callback + :rtype: int + :returns: handle watch number to be used for updating and unregist= ering for events + + .. seealso:: + https://libvirt.org/html/libvirt-libvirt-event.html#virEventAd= dHandleFuncFunc + ''' + self.log.debug('add_handle(fd=3D%d, event=3D%d, cb=3D%r, opaque=3D= %r)', + fd, event, cb, opaque) + callback =3D FDCallback(self, cb, opaque, + descriptor=3Dself.descriptors[fd], event=3Devent) + self.callbacks[callback.iden] =3D callback + self.descriptors[fd].add_handle(callback) + return callback.iden + + def _update_handle(self, watch, event): + '''Change event set for a monitored file handle + + :param int watch: file descriptor watch to modify + :param int event: new events to listen on + + .. seealso:: + https://libvirt.org/html/libvirt-libvirt-event.html#virEventUp= dateHandleFunc + ''' + self.log.debug('update_handle(watch=3D%d, event=3D%d)', watch, eve= nt) + return self.callbacks[watch].update(event=3Devent) + + def _remove_handle(self, watch): + '''Unregister a callback from a file handle. + + :param int watch: file descriptor watch to stop listening on + :returns: None (see source for explanation) + + .. seealso:: + https://libvirt.org/html/libvirt-libvirt-event.html#virEventRe= moveHandleFunc + ''' + self.log.debug('remove_handle(watch=3D%d)', watch) + callback =3D self.callbacks.pop(watch) + fd =3D callback.descriptor.fd + assert callback is self.descriptors[fd].remove_handle(watch) + if len(self.descriptors[fd].callbacks) =3D=3D 0: + del self.descriptors[fd] + callback.close() + + def _add_timeout(self, timeout, cb, opaque): + '''Register a callback for a timer event + + :param int timeout: the timeout to monitor + :param cb: the callback to call when timeout has expired + :param opaque: user data to pass to the callback + :rtype: int + :returns: a timer value + + .. seealso:: + https://libvirt.org/html/libvirt-libvirt-event.html#virEventAd= dTimeoutFunc + ''' + self.log.debug('add_timeout(timeout=3D%d, cb=3D%r, opaque=3D%r)', + timeout, cb, opaque) + callback =3D TimeoutCallback(self, cb, opaque) + self.callbacks[callback.iden] =3D callback + callback.update(timeout=3Dtimeout) + return callback.iden + + def _update_timeout(self, timer, timeout): + '''Change frequency for a timer + + :param int timer: the timer to modify + :param int timeout: the new timeout value in ms + + .. seealso:: + https://libvirt.org/html/libvirt-libvirt-event.html#virEventUp= dateTimeoutFunc + ''' + self.log.debug('update_timeout(timer=3D%d, timeout=3D%d)', timer, = timeout) + return self.callbacks[timer].update(timeout=3Dtimeout) + + def _remove_timeout(self, timer): + '''Unregister a callback for a timer + + :param int timer: the timer to remove + :returns: None (see source for explanation) + + .. seealso:: + https://libvirt.org/html/libvirt-libvirt-event.html#virEventRe= moveTimeoutFunc + ''' + self.log.debug('remove_timeout(timer=3D%d)', timer) + callback =3D self.callbacks.pop(timer) + callback.close() + +def virEventRegisterAsyncIOImpl(loop=3DNone): + '''Arrange for libvirt's callbacks to be dispatched via asyncio event = loop + + The implementation object is returned, but in normal usage it can safe= ly be + discarded. + ''' + return virEventAsyncIOImpl(loop=3Dloop).register() diff --git a/setup.py b/setup.py index 71998e2..c95170c 100755 --- a/setup.py +++ b/setup.py @@ -14,6 +14,7 @@ import sys import os import os.path import re +import shutil import time =20 MIN_LIBVIRT =3D "0.9.11" @@ -50,6 +51,12 @@ def have_libvirt_lxc(): except DistutilsExecError: return False =20 +def have_libvirtaio(): + # This depends on asyncio, which in turn depends on "yield from" synta= x. + # The asyncio module itself is in standard library since 3.4, but ther= e is + # an out-of-tree version compatible with 3.3. + return sys.version_info >=3D (3, 3) + def get_pkgconfig_data(args, mod, required=3DTrue): """Run pkg-config to and return content associated with it""" f =3D os.popen("%s %s %s" % (get_pkgcfg(), " ".join(args), mod)) @@ -124,6 +131,9 @@ def get_module_lists(): c_modules.append(modulelxc) py_modules.append("libvirt_lxc") =20 + if have_libvirtaio(): + py_modules.append("libvirtaio") + return c_modules, py_modules =20 =20 @@ -141,6 +151,8 @@ class my_build(build): self.spawn([sys.executable, "generator.py", "libvirt-qemu", apis[1= ]]) if have_libvirt_lxc(): self.spawn([sys.executable, "generator.py", "libvirt-lxc", api= s[2]]) + if have_libvirtaio(): + shutil.copy('libvirtaio.py', 'build') =20 build.run(self) =20 --=20 2.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Fri May 3 09:26:16 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1491316310097815.4152619882117; Tue, 4 Apr 2017 07:31:50 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 135A27AE9E; Tue, 4 Apr 2017 14:31:48 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id D924F94480; Tue, 4 Apr 2017 14:31:47 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 8435018521CB; Tue, 4 Apr 2017 14:31:47 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v34EVkVP025010 for ; Tue, 4 Apr 2017 10:31:46 -0400 Received: by smtp.corp.redhat.com (Postfix) id 6AEED8D15D; Tue, 4 Apr 2017 14:31:46 +0000 (UTC) Received: from dhcp-17-113.lcy.redhat.com (unknown [10.42.17.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id BEDE090C67; Tue, 4 Apr 2017 14:31:45 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 135A27AE9E Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx01.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 135A27AE9E From: "Daniel P. Berrange" To: libvir-list@redhat.com Date: Tue, 4 Apr 2017 15:31:30 +0100 Message-Id: <20170404143134.12141-4-berrange@redhat.com> In-Reply-To: <20170404143134.12141-1-berrange@redhat.com> References: <20170404143134.12141-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-loop: libvir-list@redhat.com Cc: Wojtek Porczyk Subject: [libvirt] [PATCH v3 3/7] event-test: free opaque data when removing callbacks X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.25]); Tue, 04 Apr 2017 14:31:48 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The pure python event loop impl has to call libvirt.virEventInvokeFreeCallback to free the event opaque data from a clean stack context Signed-off-by: Daniel P. Berrange --- examples/event-test.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/event-test.py b/examples/event-test.py index a1105a3..851c09b 100755 --- a/examples/event-test.py +++ b/examples/event-test.py @@ -107,6 +107,7 @@ class virEventLoopPure: self.nextTimerID =3D 1 self.handles =3D [] self.timers =3D [] + self.cleanup =3D [] self.quit =3D False =20 # The event loop can be used from multiple threads at once. @@ -178,6 +179,11 @@ class virEventLoopPure: def run_once(self): sleep =3D -1 self.runningPoll =3D True + + for opaque in self.cleanup: + libvirt.virEventInvokeFreeCallback(opaque) + self.cleanup =3D [] + try: next =3D self.next_timeout() debug("Next timeout due at %d" % next) @@ -300,8 +306,9 @@ class virEventLoopPure: handles =3D [] for h in self.handles: if h.get_id() =3D=3D handleID: - self.poll.unregister(h.get_fd()) debug("Remove handle %d fd %d" % (handleID, h.get_fd())) + self.poll.unregister(h.get_fd()) + self.cleanup.append(h.opaque) else: handles.append(h) self.handles =3D handles @@ -313,7 +320,9 @@ class virEventLoopPure: for h in self.timers: if h.get_id() !=3D timerID: timers.append(h) + else: debug("Remove timer %d" % timerID) + self.cleanup.append(h.opaque) self.timers =3D timers self.interrupt() =20 --=20 2.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Fri May 3 09:26:16 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1491316311587172.63201469670094; Tue, 4 Apr 2017 07:31:51 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D0F30F1293; Tue, 4 Apr 2017 14:31:49 +0000 (UTC) Received: from colo-mx.corp.redhat.com (unknown [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id AA63E7E4FF; Tue, 4 Apr 2017 14:31:49 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 62C935EC64; Tue, 4 Apr 2017 14:31:49 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v34EVlfO025020 for ; Tue, 4 Apr 2017 10:31:47 -0400 Received: by smtp.corp.redhat.com (Postfix) id 55D0C8EF4C; Tue, 4 Apr 2017 14:31:47 +0000 (UTC) Received: from dhcp-17-113.lcy.redhat.com (unknown [10.42.17.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id A9B934F9E9; Tue, 4 Apr 2017 14:31:46 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com D0F30F1293 Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com D0F30F1293 From: "Daniel P. Berrange" To: libvir-list@redhat.com Date: Tue, 4 Apr 2017 15:31:31 +0100 Message-Id: <20170404143134.12141-5-berrange@redhat.com> In-Reply-To: <20170404143134.12141-1-berrange@redhat.com> References: <20170404143134.12141-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-loop: libvir-list@redhat.com Cc: Wojtek Porczyk Subject: [libvirt] [PATCH v3 4/7] event-test: add timeout to exit event loop X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Tue, 04 Apr 2017 14:31:50 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Signed-off-by: Daniel P. Berrange --- examples/event-test.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/examples/event-test.py b/examples/event-test.py index 851c09b..751a140 100755 --- a/examples/event-test.py +++ b/examples/event-test.py @@ -651,15 +651,17 @@ def usage(): print(" --help, -h Print(this help message") print(" --debug, -d Print(debug output") print(" --loop, -l Toggle event-loop-implementation") + print(" --timeout=3DSECS Quit after SECS seconds running") =20 def main(): try: - opts, args =3D getopt.getopt(sys.argv[1:], "hdl", ["help", "debug"= , "loop"]) + opts, args =3D getopt.getopt(sys.argv[1:], "hdl", ["help", "debug"= , "loop", "timeout=3D"]) except getopt.GetoptError as err: # print help information and exit: print(str(err)) # will print something like "option -a not recogni= zed" usage() sys.exit(2) + timeout =3D None for o, a in opts: if o in ("-h", "--help"): usage() @@ -670,6 +672,8 @@ def main(): if o in ("-l", "--loop"): global use_pure_python_event_loop use_pure_python_event_loop ^=3D True + if o in ("--timeout"): + timeout =3D int(a) =20 if len(args) >=3D 1: uri =3D args[0] @@ -741,7 +745,9 @@ def main(): # of demo we'll just go to sleep. The other option is to # run the event loop in your main thread if your app is # totally event based. - while run: + count =3D 0 + while run and (timeout is None or count < timeout): + count =3D count + 1 time.sleep(1) =20 =20 --=20 2.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Fri May 3 09:26:16 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1491316313991812.994030152534; Tue, 4 Apr 2017 07:31:53 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2132FC04BD3B; Tue, 4 Apr 2017 14:31:52 +0000 (UTC) Received: from colo-mx.corp.redhat.com (unknown [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id DFCBD90C70; Tue, 4 Apr 2017 14:31:51 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 998AB5EC66; Tue, 4 Apr 2017 14:31:51 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v34EVmqF025034 for ; Tue, 4 Apr 2017 10:31:48 -0400 Received: by smtp.corp.redhat.com (Postfix) id AD0AA8FE55; Tue, 4 Apr 2017 14:31:48 +0000 (UTC) Received: from dhcp-17-113.lcy.redhat.com (unknown [10.42.17.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id 9E13A92058; Tue, 4 Apr 2017 14:31:47 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 2132FC04BD3B Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 2132FC04BD3B From: "Daniel P. Berrange" To: libvir-list@redhat.com Date: Tue, 4 Apr 2017 15:31:32 +0100 Message-Id: <20170404143134.12141-6-berrange@redhat.com> In-Reply-To: <20170404143134.12141-1-berrange@redhat.com> References: <20170404143134.12141-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-loop: libvir-list@redhat.com Cc: Wojtek Porczyk Subject: [libvirt] [PATCH v3 5/7] event-test: unregister callbacks & close conn on exit X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Tue, 04 Apr 2017 14:31:53 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" In order to test cleanup code paths we must unregister all callbacks and close the connection on shutdown. Since cleanup happens in the background, we do a short sleep to allow the main loop to run its cleanup too. Signed-off-by: Daniel P. Berrange --- examples/event-test.py | 95 +++++++++++++++++++++++++++++++---------------= ---- 1 file changed, 59 insertions(+), 36 deletions(-) diff --git a/examples/event-test.py b/examples/event-test.py index 751a140..ac9fbe1 100755 --- a/examples/event-test.py +++ b/examples/event-test.py @@ -702,42 +702,47 @@ def main(): =20 #Add 2 lifecycle callbacks to prove this works with more than just one vc.domainEventRegister(myDomainEventCallback1,None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE,= myDomainEventCallback2, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_REBOOT, my= DomainEventRebootCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_RTC_CHANGE= , myDomainEventRTCChangeCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_WATCHDOG, = myDomainEventWatchdogCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR, = myDomainEventIOErrorCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_GRAPHICS, = myDomainEventGraphicsCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_IO_ERROR_R= EASON, myDomainEventIOErrorReasonCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_CONTROL_ER= ROR, myDomainEventControlErrorCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_BLOCK_JOB,= myDomainEventBlockJobCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_DISK_CHANG= E, myDomainEventDiskChangeCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_TRAY_CHANG= E, myDomainEventTrayChangeCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_PMWAKEUP, = myDomainEventPMWakeupCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_PMSUSPEND,= myDomainEventPMSuspendCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_BALLOON_CH= ANGE, myDomainEventBalloonChangeCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_PMSUSPEND_= DISK, myDomainEventPMSuspendDiskCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_DEVICE_REM= OVED, myDomainEventDeviceRemovedCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_BLOCK_JOB_= 2, myDomainEventBlockJob2Callback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_TUNABLE, m= yDomainEventTunableCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_AGENT_LIFE= CYCLE, myDomainEventAgentLifecycleCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_DEVICE_ADD= ED, myDomainEventDeviceAddedCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_MIGRATION_= ITERATION, myDomainEventMigrationIteration, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_JOB_COMPLE= TED, myDomainEventJobCompletedCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_DEVICE_REM= OVAL_FAILED, myDomainEventDeviceRemovalFailedCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_METADATA_C= HANGE, myDomainEventMetadataChangeCallback, None) - vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN_EVENT_ID_BLOCK_THRE= SHOLD, myDomainEventBlockThresholdCallback, None) - - vc.networkEventRegisterAny(None, libvirt.VIR_NETWORK_EVENT_ID_LIFECYCL= E, myNetworkEventLifecycleCallback, None) - - vc.storagePoolEventRegisterAny(None, libvirt.VIR_STORAGE_POOL_EVENT_ID= _LIFECYCLE, myStoragePoolEventLifecycleCallback, None) - vc.storagePoolEventRegisterAny(None, libvirt.VIR_STORAGE_POOL_EVENT_ID= _REFRESH, myStoragePoolEventRefreshCallback, None) - - vc.nodeDeviceEventRegisterAny(None, libvirt.VIR_NODE_DEVICE_EVENT_ID_L= IFECYCLE, myNodeDeviceEventLifecycleCallback, None) - vc.nodeDeviceEventRegisterAny(None, libvirt.VIR_NODE_DEVICE_EVENT_ID_U= PDATE, myNodeDeviceEventUpdateCallback, None) - - vc.secretEventRegisterAny(None, libvirt.VIR_SECRET_EVENT_ID_LIFECYCLE,= mySecretEventLifecycleCallback, None) - vc.secretEventRegisterAny(None, libvirt.VIR_SECRET_EVENT_ID_VALUE_CHAN= GED, mySecretEventValueChanged, None) + domcallbacks =3D [] + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_LIFECYCLE, myDomainEventCallback2, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_REBOOT, myDomainEventRebootCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_RTC_CHANGE, myDomainEventRTCChangeCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_WATCHDOG, myDomainEventWatchdogCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_IO_ERROR, myDomainEventIOErrorCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_GRAPHICS, myDomainEventGraphicsCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_IO_ERROR_REASON, myDomainEventIOErrorReasonCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_CONTROL_ERROR, myDomainEventControlErrorCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_BLOCK_JOB, myDomainEventBlockJobCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_DISK_CHANGE, myDomainEventDiskChangeCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_TRAY_CHANGE, myDomainEventTrayChangeCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_PMWAKEUP, myDomainEventPMWakeupCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_PMSUSPEND, myDomainEventPMSuspendCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_BALLOON_CHANGE, myDomainEventBalloonChangeCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_PMSUSPEND_DISK, myDomainEventPMSuspendDiskCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_DEVICE_REMOVED, myDomainEventDeviceRemovedCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_BLOCK_JOB_2, myDomainEventBlockJob2Callback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_TUNABLE, myDomainEventTunableCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_AGENT_LIFECYCLE, myDomainEventAgentLifecycleCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_DEVICE_ADDED, myDomainEventDeviceAddedCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_MIGRATION_ITERATION, myDomainEventMigrationIteration, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_JOB_COMPLETED, myDomainEventJobCompletedCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_DEVICE_REMOVAL_FAILED, myDomainEventDeviceRemovalFailedCallback, = None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_METADATA_CHANGE, myDomainEventMetadataChangeCallback, None)) + domcallbacks.append(vc.domainEventRegisterAny(None, libvirt.VIR_DOMAIN= _EVENT_ID_BLOCK_THRESHOLD, myDomainEventBlockThresholdCallback, None)) + + netcallbacks =3D [] + netcallbacks.append(vc.networkEventRegisterAny(None, libvirt.VIR_NETWO= RK_EVENT_ID_LIFECYCLE, myNetworkEventLifecycleCallback, None)) + + poolcallbacks =3D [] + poolcallbacks.append(vc.storagePoolEventRegisterAny(None, libvirt.VIR_= STORAGE_POOL_EVENT_ID_LIFECYCLE, myStoragePoolEventLifecycleCallback, None)) + poolcallbacks.append(vc.storagePoolEventRegisterAny(None, libvirt.VIR_= STORAGE_POOL_EVENT_ID_REFRESH, myStoragePoolEventRefreshCallback, None)) + + devcallbacks =3D [] + devcallbacks.append(vc.nodeDeviceEventRegisterAny(None, libvirt.VIR_NO= DE_DEVICE_EVENT_ID_LIFECYCLE, myNodeDeviceEventLifecycleCallback, None)) + devcallbacks.append(vc.nodeDeviceEventRegisterAny(None, libvirt.VIR_NO= DE_DEVICE_EVENT_ID_UPDATE, myNodeDeviceEventUpdateCallback, None)) + + seccallbacks =3D [] + seccallbacks.append(vc.secretEventRegisterAny(None, libvirt.VIR_SECRET= _EVENT_ID_LIFECYCLE, mySecretEventLifecycleCallback, None)) + seccallbacks.append(vc.secretEventRegisterAny(None, libvirt.VIR_SECRET= _EVENT_ID_VALUE_CHANGED, mySecretEventValueChanged, None)) =20 vc.setKeepAlive(5, 3) =20 @@ -750,6 +755,24 @@ def main(): count =3D count + 1 time.sleep(1) =20 + vc.domainEventDeregister(myDomainEventCallback1) + + for id in seccallbacks: + vc.secretEventDeregisterAny(id) + for id in devcallbacks: + vc.nodeDeviceEventDeregisterAny(id) + for id in poolcallbacks: + vc.storagePoolEventDeregisterAny(id) + for id in netcallbacks: + vc.networkEventDeregisterAny(id) + for id in domcallbacks: + vc.domainEventDeregisterAny(id) + + vc.unregisterCloseCallback() + vc.close() + + # Allow delayed event loop cleanup to run, just for sake of testing + time.sleep(2) =20 if __name__ =3D=3D "__main__": main() --=20 2.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Fri May 3 09:26:16 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1491316318155834.7849422966699; Tue, 4 Apr 2017 07:31:58 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 9952F787E7; Tue, 4 Apr 2017 14:31:56 +0000 (UTC) Received: from colo-mx.corp.redhat.com (unknown [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 71B5B4F9E9; Tue, 4 Apr 2017 14:31:56 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 29FBA5EC68; Tue, 4 Apr 2017 14:31:56 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v34EVnJo025045 for ; Tue, 4 Apr 2017 10:31:49 -0400 Received: by smtp.corp.redhat.com (Postfix) id E7D7F9204A; Tue, 4 Apr 2017 14:31:49 +0000 (UTC) Received: from dhcp-17-113.lcy.redhat.com (unknown [10.42.17.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id 39A2E90C78; Tue, 4 Apr 2017 14:31:48 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 9952F787E7 Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx03.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 9952F787E7 From: "Daniel P. Berrange" To: libvir-list@redhat.com Date: Tue, 4 Apr 2017 15:31:33 +0100 Message-Id: <20170404143134.12141-7-berrange@redhat.com> In-Reply-To: <20170404143134.12141-1-berrange@redhat.com> References: <20170404143134.12141-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-loop: libvir-list@redhat.com Cc: Wojtek Porczyk Subject: [libvirt] [PATCH v3 6/7] event-test: rename example event loop impl X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.27]); Tue, 04 Apr 2017 14:31:57 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" Use the name 'Poll' instead of 'Pure' for the event loop demo, since there's now a second pure python loop impl available. Signed-off-by: Daniel P. Berrange --- examples/event-test.py | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/examples/event-test.py b/examples/event-test.py index ac9fbe1..e67984f 100755 --- a/examples/event-test.py +++ b/examples/event-test.py @@ -39,10 +39,10 @@ def debug(msg): # # It is a pure python implementation based around the poll() API # -class virEventLoopPure: +class virEventLoopPoll: # This class contains the data we need to track for a # single file handle - class virEventLoopPureHandle: + class virEventLoopPollHandle: def __init__(self, handle, fd, events, cb, opaque): self.handle =3D handle self.fd =3D fd @@ -70,7 +70,7 @@ class virEventLoopPure: =20 # This class contains the data we need to track for a # single periodic timer - class virEventLoopPureTimer: + class virEventLoopPollTimer: def __init__(self, timer, interval, cb, opaque): self.timer =3D timer self.interval =3D interval @@ -142,14 +142,14 @@ class virEventLoopPure: =20 return next =20 - # Lookup a virEventLoopPureHandle object based on file descriptor + # Lookup a virEventLoopPollHandle object based on file descriptor def get_handle_by_fd(self, fd): for h in self.handles: if h.get_fd() =3D=3D fd: return h return None =20 - # Lookup a virEventLoopPureHandle object based on its event loop ID + # Lookup a virEventLoopPollHandle object based on its event loop ID def get_handle_by_id(self, handleID): for h in self.handles: if h.get_id() =3D=3D handleID: @@ -253,7 +253,7 @@ class virEventLoopPure: handleID =3D self.nextHandleID + 1 self.nextHandleID =3D self.nextHandleID + 1 =20 - h =3D self.virEventLoopPureHandle(handleID, fd, events, cb, opaque) + h =3D self.virEventLoopPollHandle(handleID, fd, events, cb, opaque) self.handles.append(h) =20 self.poll.register(fd, self.events_to_poll(events)) @@ -272,7 +272,7 @@ class virEventLoopPure: timerID =3D self.nextTimerID + 1 self.nextTimerID =3D self.nextTimerID + 1 =20 - h =3D self.virEventLoopPureTimer(timerID, interval, cb, opaque) + h =3D self.virEventLoopPollTimer(timerID, interval, cb, opaque) self.timers.append(h) self.interrupt() =20 @@ -361,7 +361,7 @@ class virEventLoopPure: =20 # This single global instance of the event loop wil be used for # monitoring libvirt events -eventLoop =3D virEventLoopPure() +eventLoop =3D virEventLoopPoll() =20 # This keeps track of what thread is running the event loop, # (if it is run in a background thread) @@ -371,7 +371,7 @@ eventLoopThread =3D None # These next set of 6 methods are the glue between the official # libvirt events API, and our particular impl of the event loop # -# There is no reason why the 'virEventLoopPure' has to be used. +# There is no reason why the 'virEventLoopPoll' has to be used. # An application could easily may these 6 glue methods hook into # another event loop such as GLib's, or something like the python # Twisted event framework. @@ -402,7 +402,7 @@ def virEventRemoveTimerImpl(timerID): =20 # This tells libvirt what event loop implementation it # should use -def virEventLoopPureRegister(): +def virEventLoopPollRegister(): libvirt.virEventRegisterImpl(virEventAddHandleImpl, virEventUpdateHandleImpl, virEventRemoveHandleImpl, @@ -411,7 +411,7 @@ def virEventLoopPureRegister(): virEventRemoveTimerImpl) =20 # Directly run the event loop in the current thread -def virEventLoopPureRun(): +def virEventLoopPollRun(): global eventLoop eventLoop.run_loop() =20 @@ -420,10 +420,10 @@ def virEventLoopNativeRun(): libvirt.virEventRunDefaultImpl() =20 # Spawn a background thread to run the event loop -def virEventLoopPureStart(): +def virEventLoopPollStart(): global eventLoopThread - virEventLoopPureRegister() - eventLoopThread =3D threading.Thread(target=3DvirEventLoopPureRun, nam= e=3D"libvirtEventLoop") + virEventLoopPollRegister() + eventLoopThread =3D threading.Thread(target=3DvirEventLoopPollRun, nam= e=3D"libvirtEventLoop") eventLoopThread.setDaemon(True) eventLoopThread.start() =20 @@ -684,7 +684,7 @@ def main(): =20 # Run a background thread with the event loop if use_pure_python_event_loop: - virEventLoopPureStart() + virEventLoopPollStart() else: virEventLoopNativeStart() =20 --=20 2.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Fri May 3 09:26:16 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1491316321493152.25490396050202; Tue, 4 Apr 2017 07:32:01 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.phx2.redhat.com [10.5.11.13]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 1CF25C05678E; Tue, 4 Apr 2017 14:32:00 +0000 (UTC) Received: from colo-mx.corp.redhat.com (unknown [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id DABCE93DD9; Tue, 4 Apr 2017 14:31:59 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 937705EC6A; Tue, 4 Apr 2017 14:31:59 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id v34EVoUi025053 for ; Tue, 4 Apr 2017 10:31:50 -0400 Received: by smtp.corp.redhat.com (Postfix) id E047390C5E; Tue, 4 Apr 2017 14:31:50 +0000 (UTC) Received: from dhcp-17-113.lcy.redhat.com (unknown [10.42.17.113]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3F0C790C6D; Tue, 4 Apr 2017 14:31:50 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 1CF25C05678E Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=libvir-list-bounces@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 1CF25C05678E From: "Daniel P. Berrange" To: libvir-list@redhat.com Date: Tue, 4 Apr 2017 15:31:34 +0100 Message-Id: <20170404143134.12141-8-berrange@redhat.com> In-Reply-To: <20170404143134.12141-1-berrange@redhat.com> References: <20170404143134.12141-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 X-loop: libvir-list@redhat.com Cc: Wojtek Porczyk Subject: [libvirt] [PATCH v3 7/7] event-test: add ability to run the asyncio event loop X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.13 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.32]); Tue, 04 Apr 2017 14:32:00 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" The event test program '--loop' arg is modified to take the name of an event loop impl to run. eg 'event-test.py --loop asyncio' Signed-off-by: Daniel P. Berrange --- examples/event-test.py | 50 +++++++++++++++++++++++++++++++++++-----------= ---- 1 file changed, 35 insertions(+), 15 deletions(-) diff --git a/examples/event-test.py b/examples/event-test.py index e67984f..3bca9e2 100755 --- a/examples/event-test.py +++ b/examples/event-test.py @@ -15,16 +15,19 @@ import errno import time import threading =20 -# For the sake of demonstration, this example program includes -# an implementation of a pure python event loop. Most applications -# would be better off just using the default libvirt event loop -# APIs, instead of implementing this in python. The exception is -# where an application wants to integrate with an existing 3rd -# party event loop impl +# This example can use three different event loop impls. It defaults +# to a portable pure-python impl based on poll that is implemented +# in this file. # -# Change this to 'False' to make the demo use the native -# libvirt event loop impl -use_pure_python_event_loop =3D True +# When Python >=3D 3.4, it can optionally use an impl based on the +# new asyncio module. +# +# Finally, it can also use the libvirt native event loop impl +# +# This setting thus allows 'poll', 'native' or 'asyncio' as valid +# choices +# +event_impl =3D "poll" =20 do_debug =3D False def debug(msg): @@ -415,6 +418,11 @@ def virEventLoopPollRun(): global eventLoop eventLoop.run_loop() =20 +def virEventLoopAIORun(loop): + import asyncio + asyncio.set_event_loop(loop) + loop.run_forever() + def virEventLoopNativeRun(): while True: libvirt.virEventRunDefaultImpl() @@ -427,6 +435,16 @@ def virEventLoopPollStart(): eventLoopThread.setDaemon(True) eventLoopThread.start() =20 +def virEventLoopAIOStart(): + global eventLoopThread + import libvirtaio + import asyncio + loop =3D asyncio.new_event_loop() + libvirtaio.virEventRegisterAsyncIOImpl(loop=3Dloop) + eventLoopThread =3D threading.Thread(target=3DvirEventLoopAIORun, args= =3D(loop,), name=3D"libvirtEventLoop") + eventLoopThread.setDaemon(True) + eventLoopThread.start() + def virEventLoopNativeStart(): global eventLoopThread libvirt.virEventRegisterDefaultImpl() @@ -650,12 +668,12 @@ def usage(): print(" uri will default to qemu:///system") print(" --help, -h Print(this help message") print(" --debug, -d Print(debug output") - print(" --loop, -l Toggle event-loop-implementation") + print(" --loop=3DTYPE, -l Choose event-loop-implementation (native= , poll, asyncio)") print(" --timeout=3DSECS Quit after SECS seconds running") =20 def main(): try: - opts, args =3D getopt.getopt(sys.argv[1:], "hdl", ["help", "debug"= , "loop", "timeout=3D"]) + opts, args =3D getopt.getopt(sys.argv[1:], "hdl:", ["help", "debug= ", "loop=3D", "timeout=3D"]) except getopt.GetoptError as err: # print help information and exit: print(str(err)) # will print something like "option -a not recogni= zed" @@ -670,8 +688,8 @@ def main(): global do_debug do_debug =3D True if o in ("-l", "--loop"): - global use_pure_python_event_loop - use_pure_python_event_loop ^=3D True + global event_impl + event_impl =3D a if o in ("--timeout"): timeout =3D int(a) =20 @@ -680,11 +698,13 @@ def main(): else: uri =3D "qemu:///system" =20 - print("Using uri:" + uri) + print("Using uri '%s' and event loop '%s'" % (uri, event_impl)) =20 # Run a background thread with the event loop - if use_pure_python_event_loop: + if event_impl =3D=3D "poll": virEventLoopPollStart() + elif event_impl =3D=3D "asyncio": + virEventLoopAIOStart() else: virEventLoopNativeStart() =20 --=20 2.9.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list