[libvirt] [PATCHv2] python: Fix emulatorpin API bindings

The addition of emulator pinning APIs didn't think of doing the right job with python APIs for them. The default generator produced unusable code for this. This patch switches to proper code as in the case of domain Vcpu pining. This change can be classified as a python API-breaker but in the state the code was before I doubt anyone was able to use it successfully. --- python/generator.py | 2 + python/libvirt-override-api.xml | 18 +++++- python/libvirt-override.c | 118 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+), 2 deletions(-) diff --git a/python/generator.py b/python/generator.py index 6a25c2d..0aeb675 100755 --- a/python/generator.py +++ b/python/generator.py @@ -418,6 +418,8 @@ skip_impl = ( 'virDomainPinVcpu', 'virDomainPinVcpuFlags', 'virDomainGetVcpuPinInfo', + 'virDomainGetEmulatorPinInfo', + 'virDomainPinEmulator', 'virSecretGetValue', 'virSecretSetValue', 'virSecretGetUUID', diff --git a/python/libvirt-override-api.xml b/python/libvirt-override-api.xml index 5976fb2..c720610 100644 --- a/python/libvirt-override-api.xml +++ b/python/libvirt-override-api.xml @@ -237,10 +237,24 @@ <function name='virDomainGetVcpuPinInfo' file='python'> <info>Query the CPU affinity setting of all virtual CPUs of domain</info> <return type='unsigned char *' info='the array of cpumap'/> - <arg name='domain' type='virDomainPtr' info='pointer to domain object, or NULL for Domain0'/> + <arg name='domain' type='virDomainPtr' info='pointer to domain object'/> + <arg name='flags' type='int' info='an OR'ed set of virDomainModificationImpact'/> + </function> + <function name='virDomainGetEmulatorPinInfo' file='python'> + <info>Query the CPU affinity setting of the emulator process of domain</info> + <return type='unsigned char *' info='the array of cpumap'/> + <arg name='domain' type='virDomainPtr' info='pointer to domain object'/> <arg name='flags' type='int' info='an OR'ed set of virDomainModificationImpact'/> </function> - <function name='virDomainSetSchedulerParameters' file='python'> + <function name='virDomainPinEmulator' file='python'> + <info>Dynamically change the real CPUs which can be allocated to the emulator process of a domain. + This function requires privileged access to the hypervisor.</info> + <return type='int' info='0 in case of success, -1 in case of failure.'/> + <arg name='domain' type='virDomainPtr' info='pointer to domain object, or NULL for Domain0'/> + <arg name='cpumap' type='unsigned char *' info='pointer to a bit map of real CPUs (in 8-bit bytes) (IN) Each bit set to 1 means that corresponding CPU is usable. Bytes are stored in little-endian order: CPU0-7, 8-15... In each byte, lowest CPU number is least significant bit.'/> + <arg name='flags' type='int' info='flags to specify'/> + </function> + <function name='virDomainSetSchedulerParameters' file='python'> <info>Change the scheduler parameters</info> <return type='int' info='-1 in case of error, 0 in case of success.'/> <arg name='domain' type='virDomainPtr' info='pointer to domain object'/> diff --git a/python/libvirt-override.c b/python/libvirt-override.c index 9637598..f6573e1 100644 --- a/python/libvirt-override.c +++ b/python/libvirt-override.c @@ -1664,6 +1664,122 @@ cleanup: return VIR_PY_NONE; } + +static PyObject * +libvirt_virDomainPinEmulator(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + virDomainPtr domain; + PyObject *pyobj_domain, *pycpumap; + unsigned char *cpumap = NULL; + int cpumaplen, i, tuple_size, cpunum; + int i_retval; + unsigned int flags; + + if (!PyArg_ParseTuple(args, (char *)"OOi:virDomainPinVcpu", + &pyobj_domain, &pycpumap, &flags)) + return NULL; + + domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); + + if ((cpunum = getPyNodeCPUCount(virDomainGetConnect(domain))) < 0) + return VIR_PY_INT_FAIL; + + cpumaplen = VIR_CPU_MAPLEN(cpunum); + + if (!PyTuple_Check(pycpumap)) { + PyErr_SetString(PyExc_TypeError, "Unexpected type, tuple is required"); + return NULL; + } + + if ((tuple_size = PyTuple_Size(pycpumap)) == -1) + return NULL; + + if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) + return PyErr_NoMemory(); + + for (i = 0; i < tuple_size; i++) { + PyObject *flag = PyTuple_GetItem(pycpumap, i); + bool b; + + if (!flag || libvirt_boolUnwrap(flag, &b) < 0) { + VIR_FREE(cpumap); + return VIR_PY_INT_FAIL; + } + + if (b) + VIR_USE_CPU(cpumap, i); + else + VIR_UNUSE_CPU(cpumap, i); + } + + for (; i < cpunum; i++) + VIR_UNUSE_CPU(cpumap, i); + + LIBVIRT_BEGIN_ALLOW_THREADS; + i_retval = virDomainPinEmulator(domain, cpumap, cpumaplen, flags); + LIBVIRT_END_ALLOW_THREADS; + + VIR_FREE(cpumap); + + if (i_retval < 0) + return VIR_PY_INT_FAIL; + + return VIR_PY_INT_SUCCESS; +} + + +static PyObject * +libvirt_virDomainGetEmulatorPinInfo(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{ + virDomainPtr domain; + PyObject *pyobj_domain; + PyObject *pycpumap; + unsigned char *cpumap; + size_t cpumaplen; + size_t pcpu; + unsigned int flags; + int ret; + int cpunum; + + if (!PyArg_ParseTuple(args, (char *)"Oi:virDomainEmulatorPinInfo", + &pyobj_domain, &flags)) + return NULL; + + domain = (virDomainPtr) PyvirDomain_Get(pyobj_domain); + + if ((cpunum = getPyNodeCPUCount(virDomainGetConnect(domain))) < 0) + return VIR_PY_NONE; + + cpumaplen = VIR_CPU_MAPLEN(cpunum); + + if (VIR_ALLOC_N(cpumap, cpumaplen) < 0) + return PyErr_NoMemory(); + + LIBVIRT_BEGIN_ALLOW_THREADS; + ret = virDomainGetEmulatorPinInfo(domain, cpumap, cpumaplen, flags); + LIBVIRT_END_ALLOW_THREADS; + if (ret < 0) { + VIR_FREE(cpumap); + return VIR_PY_NONE; + } + + if (!(pycpumap = PyTuple_New(cpunum))) { + VIR_FREE(cpumap); + return NULL; + } + + for (pcpu = 0; pcpu < cpunum; pcpu++) + PyTuple_SET_ITEM(pycpumap, pcpu, + PyBool_FromLong(VIR_CPU_USABLE(cpumap, cpumaplen, + 0, pcpu))); + + VIR_FREE(cpumap); + return pycpumap; +} + + /************************************************************************ * * * Global error handler at the Python level * @@ -6705,6 +6821,8 @@ static PyMethodDef libvirtMethods[] = { {(char *) "virDomainPinVcpu", libvirt_virDomainPinVcpu, METH_VARARGS, NULL}, {(char *) "virDomainPinVcpuFlags", libvirt_virDomainPinVcpuFlags, METH_VARARGS, NULL}, {(char *) "virDomainGetVcpuPinInfo", libvirt_virDomainGetVcpuPinInfo, METH_VARARGS, NULL}, + {(char *) "virDomainGetEmulatorPinInfo", libvirt_virDomainGetEmulatorPinInfo, METH_VARARGS, NULL}, + {(char *) "virDomainPinEmulator", libvirt_virDomainPinEmulator, METH_VARARGS, NULL}, {(char *) "virConnectListStoragePools", libvirt_virConnectListStoragePools, METH_VARARGS, NULL}, {(char *) "virConnectListDefinedStoragePools", libvirt_virConnectListDefinedStoragePools, METH_VARARGS, NULL}, {(char *) "virConnectListAllStoragePools", libvirt_virConnectListAllStoragePools, METH_VARARGS, NULL}, -- 1.8.1.5

On 03/20/2013 08:48 AM, Peter Krempa wrote:
The addition of emulator pinning APIs didn't think of doing the right job with python APIs for them. The default generator produced unusable code for this.
This patch switches to proper code as in the case of domain Vcpu pining. This change can be classified as a python API-breaker but in the state the code was before I doubt anyone was able to use it successfully. --- python/generator.py | 2 + python/libvirt-override-api.xml | 18 +++++- python/libvirt-override.c | 118 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+), 2 deletions(-)
+++ b/python/libvirt-override-api.xml @@ -237,10 +237,24 @@ <function name='virDomainGetVcpuPinInfo' file='python'> <info>Query the CPU affinity setting of all virtual CPUs of domain</info> <return type='unsigned char *' info='the array of cpumap'/> - <arg name='domain' type='virDomainPtr' info='pointer to domain object, or NULL for Domain0'/> + <arg name='domain' type='virDomainPtr' info='pointer to domain object'/> + <arg name='flags' type='int' info='an OR'ed set of virDomainModificationImpact'/> + </function> + <function name='virDomainGetEmulatorPinInfo' file='python'> + <info>Query the CPU affinity setting of the emulator process of domain</info> + <return type='unsigned char *' info='the array of cpumap'/> + <arg name='domain' type='virDomainPtr' info='pointer to domain object'/> <arg name='flags' type='int' info='an OR'ed set of virDomainModificationImpact'/>
I'd LOVE to make python treat flags as an optional argument that defaults to 0 when not present, instead of a mandatory argument, but I don't know enough about python bindings to provide a patch. That would be a separate cleanup for a lot more than just this function, though.
</function> - <function name='virDomainSetSchedulerParameters' file='python'> + <function name='virDomainPinEmulator' file='python'> + <info>Dynamically change the real CPUs which can be allocated to the emulator process of a domain. + This function requires privileged access to the hypervisor.</info> + <return type='int' info='0 in case of success, -1 in case of failure.'/> + <arg name='domain' type='virDomainPtr' info='pointer to domain object, or NULL for Domain0'/> + <arg name='cpumap' type='unsigned char *' info='pointer to a bit map of real CPUs (in 8-bit bytes) (IN) Each bit set to 1 means that corresponding CPU is usable. Bytes are stored in little-endian order: CPU0-7, 8-15... In each byte, lowest CPU number is least significant bit.'/> + <arg name='flags' type='int' info='flags to specify'/> + </function> + <function name='virDomainSetSchedulerParameters' file='python'>
Looks like an unintentional whitespace change (turning 4 spaces into 5) snuck in here.
+static PyObject * +libvirt_virDomainGetEmulatorPinInfo(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{
+ + for (pcpu = 0; pcpu < cpunum; pcpu++) + PyTuple_SET_ITEM(pycpumap, pcpu, + PyBool_FromLong(VIR_CPU_USABLE(cpumap, cpumaplen, + 0, pcpu)));
The counterpart of libvirt_virDomainGetVpcpuPinInfo() used PyTuple_SetItem instead of PyTuple_SET_ITEM; any reason? At any rate, this looks sane modulo the whitespace tweak, so: ACK. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org

On 03/20/13 21:12, Eric Blake wrote:
On 03/20/2013 08:48 AM, Peter Krempa wrote:
The addition of emulator pinning APIs didn't think of doing the right job with python APIs for them. The default generator produced unusable code for this.
This patch switches to proper code as in the case of domain Vcpu pining. This change can be classified as a python API-breaker but in the state the code was before I doubt anyone was able to use it successfully. --- python/generator.py | 2 + python/libvirt-override-api.xml | 18 +++++- python/libvirt-override.c | 118 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 136 insertions(+), 2 deletions(-)
+static PyObject * +libvirt_virDomainGetEmulatorPinInfo(PyObject *self ATTRIBUTE_UNUSED, + PyObject *args) +{
+ + for (pcpu = 0; pcpu < cpunum; pcpu++) + PyTuple_SET_ITEM(pycpumap, pcpu, + PyBool_FromLong(VIR_CPU_USABLE(cpumap, cpumaplen, + 0, pcpu)));
The counterpart of libvirt_virDomainGetVpcpuPinInfo() used PyTuple_SetItem instead of PyTuple_SET_ITEM; any reason?
I wanted to make it explicit that we don't care about the return value.
At any rate, this looks sane modulo the whitespace tweak, so:
ACK.
I fixed the whitespace and pushed. Thanks Peter
participants (2)
-
Eric Blake
-
Peter Krempa