[libvirt] [PATCH v2 2/2] Add asyncio event loop implementation
Daniel P. Berrange
berrange at redhat.com
Tue Apr 4 11:55:11 UTC 2017
On Fri, Mar 17, 2017 at 02:35:53PM +0100, Wojtek Porczyk wrote:
> +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=too-few-public-methods
> +
> + _iden_counter = itertools.count()
> +
> + def __init__(self, impl, cb, opaque, *args, **kwargs):
> + super().__init__(*args, **kwargs)
> + self.iden = next(self._iden_counter)
> + self.impl = impl
> + self.cb = cb
> + self.opaque = 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] = self
> +
> + def __repr__(self):
> + return '<{} iden={}>'.format(self.__clas__.__name__, self.iden)
This looks like it should be 'self.__class__'
> +class TimeoutCallback(Callback):
> + '''Callback for timer'''
> + def __init__(self, *args, timeout, **kwargs):
> + super().__init__(*args, **kwargs)
> + self.timeout = timeout
> + self._task = None
> +
> + def __repr__(self):
> + return '<{} iden={} timeout={}>'.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:
> + assert self.timeout >= 0, \
> + 'invalid timeout {} for running timer'.format(self.timeout)
When I test, this assert always fires. It seems that when we call 'close',
setting timeout==-1, this _timer coroutine continues for one more iteration
before CancelledError is triggered.
> +
> + try:
> + if self.timeout > 0:
> + timeout = 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=None):
> + '''Start or the timer, possibly updating timeout'''
> + if timeout is not None:
> + self.timeout = timeout
> +
Using timeout=None as the default looks wrong to me - It should
be either mandatory, or -1 IMHO.
> + if self.timeout >= 0 and self._task is None:
> + self.impl.log.debug('timer %r start', self.iden)
> + self._task = ensure_future(self._timer(),
> + loop=self.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=no-member
> + self._task = None
> +
> + def close(self):
> + '''Stop the timer and call ff callback'''
> + self.timeout = -1
> + self.update()
> + super().close()
> diff --git a/setup.py b/setup.py
> index 120ddd5..bac9010 100755
> --- a/setup.py
> +++ b/setup.py
> @@ -14,6 +14,7 @@ import sys
> import os
> import os.path
> import re
> +import shutil
> import time
>
> MIN_LIBVIRT = "0.9.11"
> @@ -50,6 +51,12 @@ def have_libvirt_lxc():
> except DistutilsExecError:
> return False
>
> +def have_libvirtaio():
> + # This depends on asyncio, which in turn depends on "yield from" syntax.
> + # The asyncio module itself is in standard library since 3.4, but there is
> + # an out-of-tree version compatible with 3.3.
> + return sys.version_info >= (3, 3)
> +
> def get_pkgconfig_data(args, mod, required=True):
> """Run pkg-config to and return content associated with it"""
> f = 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")
>
> + if have_libvirtaio():
> + py_modules.append("libvirtaio")
> +
> return c_modules, py_modules
>
>
> @@ -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", apis[2]])
> + if have_libvirtaio():
> + shutil.copy('libvirtaio.py', 'build')
>
> build.run(self)
We also need to add libvirtaio.py to MANIFEST.in to ensure it gets into
the dist
Regards,
Daniel
--
|: http://berrange.com -o- http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org -o- http://virt-manager.org :|
|: http://entangle-photo.org -o- http://search.cpan.org/~danberr/ :|
More information about the libvir-list
mailing list