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(a)redhat.com +1-919-301-3266
Libvirt virtualization library
http://libvirt.org