[libvirt] [PATCH v2] Add two NUMA tuning python bindings APIs

Guan Nan Ren gren at redhat.com
Tue Jan 24 12:07:59 UTC 2012


  Thanks for these comments.
  I will refactor the loop code, rethink about other codes and make v3 patch.

  Guannan Ren

----- Original Message -----
From: "Eric Blake" <eblake at redhat.com>
To: "Guannan Ren" <gren at redhat.com>
Cc: libvir-list at redhat.com
Sent: Saturday, January 21, 2012 11:04:15 PM
Subject: Re: [libvirt] [PATCH v2] Add two NUMA tuning python bindings APIs

On 01/19/2012 02:16 AM, Guannan Ren wrote:
>         *virDomainSetNumaParameters
>         *virDomainGetNumaParameters
> ---
>  python/libvirt-override-api.xml |   13 +++
>  python/libvirt-override.c       |  186 +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 199 insertions(+), 0 deletions(-)
> 

>  static PyObject *
> +libvirt_virDomainSetNumaParameters(PyObject *self ATTRIBUTE_UNUSED,
> +                                     PyObject *args) {

> +    LIBVIRT_BEGIN_ALLOW_THREADS;
> +    i_retval = virDomainGetNumaParameters(domain, params, &nparams, flags);
> +    LIBVIRT_END_ALLOW_THREADS;

Why are we getting the existing parameters, instead of just blindly
constructing params based on args?  I think that's a waste of effort,
considering that libvirt will already reject things if the user passes
in unknown key names.  Besides,

> +
> +    if (i_retval < 0) {
> +        free(params);
> +        return VIR_PY_INT_FAIL;
> +    }
> +
> +    /* convert to a Python tuple of long objects */
> +    for (i = 0; i < nparams; i++) {
> +        PyObject *key, *val;
> +        key = libvirt_constcharPtrWrap(params[i].field);
> +        val = PyDict_GetItem(info, key);
> +        Py_DECREF(key);
> +
> +        if (val == NULL)
> +            continue;

this says that you will silently discard any unknown keys passed in from
the python code, whereas libvirt would noisily reject unknown keys.  I
don't think the python code should behave differently from the C code.

> +
> +        switch (params[i].type) {
> +        case VIR_TYPED_PARAM_INT:
> +            params[i].value.i = (int)PyInt_AS_LONG(val);
> +            break;

We're starting to repeat this code sequence in several places - we ought
to refactor things to share this conversion to and from python types and
virTypedParameter, so that all of the glue code can share the same
conversions (and fixing bugs in one will fix all of them at the same time).

> +static PyObject *
> +libvirt_virDomainGetNumaParameters(PyObject *self ATTRIBUTE_UNUSED,
> +                                     PyObject *args) {

Indentation; also, we've lately been sticking the { of a function on
column 1:

static PyObject *
libvirt_virDomainGetNumaParameters(PyObject *self ATTRIBUTE_UNUSED,
                                   PyObject *args)
{

> +
> +    if (i_retval < 0)
> +        return VIR_PY_NONE;

I think this is okay; it tells python that the C call successfully
reported an error, and that the caller can then query for the last
libvirt error.

> +
> +    if ((params = malloc(sizeof(*params)*nparams)) == NULL)
> +        return VIR_PY_NONE;

Bad - we didn't raise any libvirt error, so the user wouldn't be able to
tell why we returned NONE.  Rather, we should really be calling return
PyErr_NoMemory() in situations where we failed to malloc(), so that
python can correctly raise a memory exception.  (You were just
copying-and-pasting; the problem is pervasive throughout this file).

> +
> +    LIBVIRT_BEGIN_ALLOW_THREADS;
> +    i_retval = virDomainGetNumaParameters(domain, params, &nparams, flags);
> +    LIBVIRT_END_ALLOW_THREADS;
> +
> +    if (i_retval < 0) {
> +        free(params);
> +        return VIR_PY_NONE;
> +    }

Okay.

> +
> +    /* convert to a Python tuple of long objects */
> +    if ((info = PyDict_New()) == NULL) {
> +        free(params);

Memory leak - params might include VIR_TYPED_PARAM_STRING contents, so
we need to call virTypedParameterArrayClear before freeing params.

> +        return VIR_PY_NONE;

Bad - PyDict_New already raised the python exception for no memory, but
we silently discarded it by returning NONE instead of NULL.  We should
really be propagating any python errors back up the call chain.

> +    }
> +
> +    for (i = 0 ; i < nparams ; i++) {
> +        PyObject *key, *val;
> +
> +        switch (params[i].type) {
> +        case VIR_TYPED_PARAM_INT:
> +            val = PyInt_FromLong((long)params[i].value.i);
> +            break;

Again, worth refactoring code to share this loop.

> +
> +        default:
> +            free(params);

Another memory leak if params had any string contents.

> +            Py_DECREF(info);
> +            return VIR_PY_NONE;
> +        }
> +
> +        key = libvirt_constcharPtrWrap(params[i].field);
> +        PyDict_SetItem(info, key, val);

Bad - we should be checking for failure of PyDict_SetItem, and
propagating that failure back to the caller.

> +    }
> +    free(params);

Another memory leak.

> +    return(info);
> +}
> +

-- 
Eric Blake   eblake at redhat.com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org




More information about the libvir-list mailing list