Changes since v1: - Interpret keyword arguments in initializers: eg. xl.device_pci(bus=1, dev=2, fn=3) - Implement domain pause/unpause/rename/pci_add/pci_del and pci_parse - Proper type-checking in all (I hope) code-paths - Improve API for accessing auto-generated code and types Changes since RFC: - split auto-generated code in to c and h files - un-break the build system - fix ocaml binding due to libxl API change - lot''s of tidy-ups too numerous to mention -----8<--------------------------------------------------------------- Introduce python binding for libxl. The binding is not yet complete but serveral methods are implemented and tested. Those which are implemented provide examples of the two or three basic patterns that most future methods should follow. Over 5,000 lines of boilerplate is automatically generated to wrap and export all relevant libxl structure definitions. There are a few places where such code cannot be fully auto-generated and special hooks are declared and stubbed where, for example, conversion between libxl_file_reference and a python file object is required. Signed-off-by: Gianni Tedesco <gianni.tedesco@citrix.com> -- tools/python/genwrap.py | 375 ++++++++++++++++++++++++++ tools/python/xen/lowlevel/xl/xl.c | 512 ++++++++++++++++++++++++++++++++++++ tools/python/Makefile | 9 tools/python/setup.py | 19 + 4 files changed, 912 insertions(+), 3 deletions(-) -- diff -r b8c925673644 tools/python/Makefile --- a/tools/python/Makefile Fri Sep 10 14:07:27 2010 +0100 +++ b/tools/python/Makefile Fri Sep 10 14:36:57 2010 +0100 @@ -19,7 +19,12 @@ genpath-target = $(call buildmakevars2fi $(eval $(genpath-target)) .PHONY: build buildpy -buildpy: genpath +buildpy: genpath genwrap.py $(XEN_ROOT)/tools/libxl/libxl.idl \ + $(XEN_ROOT)/tools/libxl/libxltypes.py + PYTHONPATH=$(XEN_ROOT)/tools/libxl $(PYTHON) genwrap.py \ + $(XEN_ROOT)/tools/libxl/libxl.idl \ + xen/lowlevel/xl/_pyxl_types.h \ + xen/lowlevel/xl/_pyxl_types.c CC="$(CC)" CFLAGS="$(CFLAGS)" $(PYTHON) setup.py build build: buildpy refresh-pot refresh-po $(CATALOGS) @@ -85,6 +90,8 @@ test: clean: rm -f $(XENPATH) rm -rf build *.pyc *.pyo *.o *.a *~ $(CATALOGS) xen/util/auxbin.pyc + rm -f xen/lowlevel/xl/_pyxl_types.h + rm -f xen/lowlevel/xl/_pyxl_types.c rm -f $(DEPS) -include $(DEPS) diff -r b8c925673644 tools/python/genwrap.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/genwrap.py Fri Sep 10 14:36:57 2010 +0100 @@ -0,0 +1,375 @@ +#!/usr/bin/python + +import sys,os + +import libxltypes + +def py_type(ty): + if ty == libxltypes.bool or isinstance(ty, libxltypes.BitField) and ty.width == 1: + return "Bool" + if isinstance(ty, libxltypes.Number): + if ty.signed: + return "Int" + else: + return "Uint" + if ty == libxltypes.string: + return "String" + return None + +def py_wrapstruct(ty): + l = [] + l.append("typedef struct {") + l.append(" PyObject_HEAD;") + l.append(" %s obj;"%ty.typename); + l.append("}Py_%s;"%ty.rawname) + l.append("") + return "\n".join(l) + "\n" + +def fsanitize(name): + "Sanitise a function name given a C type" + ret = ''_''.join(name.split()) + return ret.replace(''*'', ''ptr'') + +def py_decls(ty): + l = [] + l.append("_hidden Py_%s *Py%s_New(void);\n"%(ty.rawname, ty.rawname)) + l.append("_hidden int Py%s_Check(PyObject *self);\n"%ty.rawname) + for f in ty.fields: + if py_type(f.type) is not None: + continue + l.append("_hidden PyObject *attrib__%s_get(%s *%s);"%(\ + fsanitize(f.type.typename), f.type.typename, f.name)) + l.append("_hidden int attrib__%s_set(PyObject *v, %s *%s);"%(\ + fsanitize(f.type.typename), f.type.typename, f.name)) + return ''\n''.join(l) + "\n" + +def py_attrib_get(ty, f): + t = py_type(f.type) + l = [] + l.append("static PyObject *py_%s_%s_get(Py_%s *self, void *priv)"%(ty.rawname, f.name, ty.rawname)) + l.append("{") + if t == "Bool": + l.append(" return (self->obj.%s) ? Py_True : Py_False;"%f.name) + elif t == "Int": + l.append(" return genwrap__ll_get(self->obj.%s);"%f.name) + elif t == "Uint": + l.append(" return genwrap__ull_get(self->obj.%s);"%f.name) + elif t == "String": + l.append(" return genwrap__string_get(&self->obj.%s);"%f.name) + else: + tn = f.type.typename + l.append(" return attrib__%s_get((%s *)&self->obj.%s);"%(fsanitize(tn), tn, f.name)) + l.append("}") + return ''\n''.join(l) + "\n\n" + +def py_attrib_set(ty, f): + t = py_type(f.type) + l = [] + l.append("static int py_%s_%s_set(Py_%s *self, PyObject *v, void *priv)"%(ty.rawname, f.name, ty.rawname)) + l.append("{") + if t == "Bool": + l.append(" self->obj.%s = (NULL == v || Py_None == v || Py_False == v) ? 0 : 1;"%f.name) + l.append(" return 0;") + elif t == "Uint" or t == "Int": + l.append(" %slong long tmp;"%(t == "Uint" and "unsigned " or "")) + l.append(" int ret;") + if t == "Uint": + l.append(" ret = genwrap__ull_set(v, &tmp, (%s)~0);"%f.type.typename) + else: + l.append(" ret = genwrap__ll_set(v, &tmp, (%s)~0);"%f.type.typename) + l.append(" if ( ret >= 0 )") + l.append(" self->obj.%s = tmp;"%f.name) + l.append(" return ret;") + elif t == "String": + l.append(" return genwrap__string_set(v, &self->obj.%s);"%f.name) + else: + tn = f.type.typename + l.append(" return attrib__%s_set(v, (%s *)&self->obj.%s);"%(fsanitize(tn), tn, f.name)) + l.append("}") + return ''\n''.join(l) + "\n\n" + +def py_object_def(ty): + l = [] + if ty.destructor_fn is not None: + dtor = " %s(&self->obj);\n"%ty.destructor_fn + else: + dtor = "" + + funcs="""static void Py%s_dealloc(Py_%s *self) +{ +%s self->ob_type->tp_free((PyObject *)self); +} + +static int Py%s_init(Py_%s *self, PyObject *args, PyObject *kwds) +{ + memset(&self->obj, 0, sizeof(self->obj)); + return genwrap__obj_init((PyObject *)self, args, kwds); +} + +static PyObject *Py%s_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + Py_%s *self = (Py_%s *)type->tp_alloc(type, 0); + if (self == NULL) + return NULL; + memset(&self->obj, 0, sizeof(self->obj)); + return (PyObject *)self; +} + +"""%((ty.rawname, ty.rawname, dtor) + tuple(ty.rawname for x in range(5))) + + l.append("static PyGetSetDef Py%s_getset[] = {"%ty.rawname) + for f in ty.fields: + l.append(" { .name = \"%s\", "%f.name) + l.append(" .get = (getter)py_%s_%s_get, "%(ty.rawname, f.name)) + l.append(" .set = (setter)py_%s_%s_set },"%(ty.rawname, f.name)) + l.append(" { .name = NULL }") + l.append("};") + struct=""" +static PyTypeObject Py%s_Type= { + PyObject_HEAD_INIT(NULL) + 0, + PKG ".%s", + sizeof(Py_%s), + 0, + (destructor)Py%s_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL, /* tp_hash */ + NULL, /* tp_call */ + NULL, /* tp_str */ + NULL, /* tp_getattro */ + NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "%s", /* tp_doc */ + NULL, /* tp_traverse */ + NULL, /* tp_clear */ + NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + NULL, /* tp_methods */ + NULL, /* tp_members */ + Py%s_getset, /* tp_getset */ + NULL, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Py%s_init, /* tp_init */ + NULL, /* tp_alloc */ + Py%s_new, /* tp_new */ +}; + +Py_%s *Py%s_New(void) +{ + return (Py_%s *)Py%s_new(&Py%s_Type, NULL, NULL); +} + +int Py%s_Check(PyObject *self) +{ + return (self->ob_type == &Py%s_Type); +} +"""%tuple(ty.rawname for x in range(15)) + return funcs + ''\n''.join(l) + "\n" + struct + +def py_initfuncs(types): + l = [] + l.append("void genwrap__init(PyObject *m)") + l.append("{") + for ty in types: + l.append(" if (PyType_Ready(&Py%s_Type) >= 0) {"%ty.rawname) + l.append(" Py_INCREF(&Py%s_Type);"%ty.rawname) + l.append(" PyModule_AddObject(m, \"%s\", (PyObject *)&Py%s_Type);"%(ty.rawname, ty.rawname)) + l.append(" }") + l.append("}") + return ''\n''.join(l) + "\n\n" + +def tree_frob(types): + ret = filter(lambda x:True, types) # deep copy + for ty in ret: + ty.fields = filter(lambda f:f.name is not None and f.type.typename is not None, ty.fields) + return ret + +if __name__ == ''__main__'': + if len(sys.argv) < 4: + print >>sys.stderr, "Usage: genwrap.py <idl> <decls> <defns>" + sys.exit(1) + + idl = sys.argv[1] + (_,types) = libxltypes.parse(idl) + + types = tree_frob(types) + + decls = sys.argv[2] + f = open(decls, "w") + f.write("""#ifndef __PYXL_TYPES_H +#define __PYXL_TYPES_H + +/* + * DO NOT EDIT. + * + * This file is autogenerated by + * "%s" + */ + +#define PKG "xen.lowlevel.xl" + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +#define _hidden __attribute__((visibility("hidden"))) +#define _protected __attribute__((visibility("protected"))) +#else +#define _hidden +#define _protected +#endif + +/* Initialise all types */ +_hidden void genwrap__init(PyObject *m); + +/* Auto-generated get/set functions for simple data-types */ +_hidden int genwrap__string_set(PyObject *v, char **str); +_hidden PyObject *genwrap__string_get(char **str); +_hidden PyObject *genwrap__ull_get(unsigned long long val); +_hidden int genwrap__ull_set(PyObject *v, unsigned long long *val, unsigned long long mask); +_hidden PyObject *genwrap__ll_get(long long val); +_hidden int genwrap__ll_set(PyObject *v, long long *val, long long mask); + +""" % " ".join(sys.argv)) + for ty in types: + f.write("/* Internal APU for %s wrapper */\n"%ty.typename) + f.write(py_wrapstruct(ty)) + f.write(py_decls(ty)) + f.write("\n") + f.write("""#endif /* __PYXL_TYPES_H */\n""") + f.close() + + defns = sys.argv[3] + f = open(defns, "w") + f.write("""/* + * DO NOT EDIT. + * + * This file is autogenerated by + * "%s" + */ + +#include <Python.h> +#include <string.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include "libxl.h" /* gah */ +#include "%s" + +static int genwrap__obj_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *key, *value; + Py_ssize_t pos = 0; + + if ( NULL == kwds ) + return 0; + + while (PyDict_Next(kwds, &pos, &key, &value)) { + if ( PyObject_SetAttr(self, key, value) < 0 ) + return -1; + } + + return 0; +} + +int genwrap__string_set(PyObject *v, char **str) +{ + char *tmp; + if ( NULL == v ) { + free(*str); + *str = NULL; + return 0; + } + if ( !PyString_Check(v) ) { + PyErr_SetString(PyExc_TypeError, "Attribute expected string"); + return -1; + } + tmp = strdup(PyString_AsString(v)); + if ( NULL == tmp ) { + PyErr_SetString(PyExc_MemoryError, "Allocating string attribute"); + return -1; + } + free(*str); + *str = tmp; + return 0; +} + +PyObject *genwrap__string_get(char **str) +{ + if ( NULL == *str ) + return Py_None; + return PyString_FromString(*str); +} + +PyObject *genwrap__ull_get(unsigned long long val) +{ + return PyLong_FromUnsignedLongLong(val); +} + +int genwrap__ull_set(PyObject *v, unsigned long long *val, unsigned long long mask) +{ + unsigned long long tmp; + if ( NULL == v ) { + *val = 0; + return 0; + } + if ( PyLong_Check(v) ) { + tmp = PyLong_AsUnsignedLongLong(v); + }else if ( PyInt_Check(v) ) { + tmp = (unsigned long long)PyInt_AsLong(v); + }else{ + PyErr_SetString(PyExc_TypeError, "Attribute expected int or long"); + return -1; + } + if ( tmp & ~mask ) { + PyErr_SetString(PyExc_ValueError, "Integer overflow"); + return -1; + } + *val = tmp; + return 0; +} + +PyObject *genwrap__ll_get(long long val) +{ + return PyLong_FromLongLong(val); +} + +int genwrap__ll_set(PyObject *v, long long *val, long long mask) +{ + long long tmp; + if ( NULL == v ) { + *val = 0; + return 0; + } + if ( PyLong_Check(v) ) { + tmp = PyLong_AsLongLong(v); + }else{ + tmp = (long long)PyInt_AsLong(v); + } + if ( tmp & ~mask ) { + PyErr_SetString(PyExc_ValueError, "Integer overflow"); + return -1; + } + *val = tmp; + return 0; +} + +""" % tuple((" ".join(sys.argv),) + (os.path.split(decls)[-1:]),)) + for ty in types: + f.write("/* Attribute get/set functions for %s */\n"%ty.typename) + for a in ty.fields: + f.write(py_attrib_get(ty,a)) + f.write(py_attrib_set(ty,a)) + f.write(py_object_def(ty)) + f.write(py_initfuncs(types)) + f.close() diff -r b8c925673644 tools/python/setup.py --- a/tools/python/setup.py Fri Sep 10 14:07:27 2010 +0100 +++ b/tools/python/setup.py Fri Sep 10 14:36:57 2010 +0100 @@ -9,14 +9,23 @@ extra_compile_args = [ "-fno-strict-ali include_dirs = [ XEN_ROOT + "/tools/libxc", XEN_ROOT + "/tools/xenstore", XEN_ROOT + "/tools/include", + XEN_ROOT + "/tools/libxl", ] library_dirs = [ XEN_ROOT + "/tools/libxc", XEN_ROOT + "/tools/xenstore", + XEN_ROOT + "/tools/libxl", + XEN_ROOT + "/tools/blktap2/control", ] libraries = [ "xenctrl", "xenguest", "xenstore" ] +plat = os.uname()[0] +if plat == ''Linux'': + uuid_libs = ["uuid"] +else: + uuid_libs = [] + xc = Extension("xc", extra_compile_args = extra_compile_args, include_dirs = include_dirs + [ "xen/lowlevel/xc" ], @@ -83,8 +92,14 @@ netlink = Extension("netlink", sources = [ "xen/lowlevel/netlink/netlink.c", "xen/lowlevel/netlink/libnetlink.c"]) -modules = [ xc, xs, ptsname, acm, flask ] -plat = os.uname()[0] +xl = Extension("xl", + extra_compile_args = extra_compile_args, + include_dirs = include_dirs + [ "xen/lowlevel/xl" ], + library_dirs = library_dirs, + libraries = libraries + ["xenlight", "blktapctl" ] + uuid_libs, + sources = [ "xen/lowlevel/xl/xl.c", "xen/lowlevel/xl/_pyxl_types.c" ]) + +modules = [ xc, xs, ptsname, acm, flask, xl ] if plat == ''SunOS'': modules.extend([ scf, process ]) if plat == ''Linux'': diff -r b8c925673644 tools/python/xen/lowlevel/xl/xl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/lowlevel/xl/xl.c Fri Sep 10 14:36:57 2010 +0100 @@ -0,0 +1,512 @@ +/****************************************************************************** + * xl.c + * + * Copyright (c) 2010 Citrix Ltd. + * Author: Gianni Tedesco + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General Public + * License as published by the Free Software Foundation. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <Python.h> +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <getopt.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <arpa/inet.h> +#include <xenctrl.h> +#include <ctype.h> +#include <inttypes.h> + + +#include <libxl.h> +#include <libxl_utils.h> + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/* Needed for Python versions earlier than 2.3. */ +#ifndef PyMODINIT_FUNC +#define PyMODINIT_FUNC DL_EXPORT(void) +#endif + +#define CLS "ctx" + +static PyObject *xl_error_obj; + +static int fixed_bytearray_set(PyObject *v, uint8_t *ptr, size_t len) +{ + char *tmp; + size_t sz; + + if ( NULL == v ) { + memset(ptr, 0, len); + return 0; + } + + if ( PyByteArray_Check(v) ) { + sz = PyByteArray_Size(v); + tmp = PyByteArray_AsString(v); + }else if ( PyString_Check(v) ) { + Py_ssize_t ssz; + if ( PyString_AsStringAndSize(v, &tmp, &ssz) ) + return -1; + if ( ssz < 0 ) + tmp = NULL; + sz = ssz; + }else{ + PyErr_SetString(PyExc_TypeError, "Attribute expected bytearray or string"); + return -1; + } + + if ( NULL == tmp ) { + memset(ptr, 0, len); + return 0; + } + if ( sz != len ) { + PyErr_SetString(PyExc_ValueError, + (sz < len) ? "Buffer underflow" : "Buffer overflow"); + return -1; + } + + memcpy(ptr, tmp, sz); + return 0; +} + +static PyObject *fixed_bytearray_get(const uint8_t *ptr, size_t len) +{ + return PyByteArray_FromStringAndSize((const char *)ptr, len); +} + +#include "_pyxl_types.h" + +int attrib__libxl_cpumap_set(PyObject *v, libxl_cpumap *pptr) +{ + return -1; +} + +int attrib__libxl_domain_build_state_ptr_set(PyObject *v, libxl_domain_build_state **pptr) +{ + return -1; +} + +int attrib__libxl_file_reference_set(PyObject *v, libxl_file_reference *pptr) +{ + return -1; +} + +int attrib__libxl_hwcap_set(PyObject *v, libxl_hwcap *pptr) +{ + return -1; +} + +int attrib__libxl_key_value_list_set(PyObject *v, libxl_key_value_list *pptr) +{ + return -1; +} + +int attrib__libxl_mac_set(PyObject *v, libxl_mac *pptr) +{ + return fixed_bytearray_set(v, *pptr, 6); +} + +int attrib__libxl_string_list_set(PyObject *v, libxl_string_list *pptr) +{ + return -1; +} + +int attrib__libxl_uuid_set(PyObject *v, libxl_uuid *pptr) +{ + return fixed_bytearray_set(v, libxl_uuid_bytearray(pptr), 16); +} + +int attrib__struct_in_addr_set(PyObject *v, struct in_addr *pptr) +{ + return -1; +} + +PyObject *attrib__libxl_cpumap_get(libxl_cpumap *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_domain_build_state_ptr_get(libxl_domain_build_state **pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_file_reference_get(libxl_file_reference *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_hwcap_get(libxl_hwcap *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_key_value_list_get(libxl_key_value_list *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_mac_get(libxl_mac *pptr) +{ + return fixed_bytearray_get(*pptr, 6); +} + +PyObject *attrib__libxl_string_list_get(libxl_string_list *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_uuid_get(libxl_uuid *pptr) +{ + return fixed_bytearray_get(libxl_uuid_bytearray(pptr), 16); +} + +PyObject *attrib__struct_in_addr_get(struct in_addr *pptr) +{ + return NULL; +} + +typedef struct { + PyObject_HEAD; + libxl_ctx ctx; + xentoollog_logger_stdiostream *logger; + xentoollog_level minmsglevel; +} XlObject; + +static PyObject *pyxl_list_domains(XlObject *self) +{ + libxl_dominfo *cur, *info; + PyObject *list; + int nr_dom, i; + + info = libxl_list_domain(&self->ctx, &nr_dom); + if ( NULL == info ) + return PyList_New(0); + + list = PyList_New(nr_dom); + if ( NULL == list ) + goto err_mem; + + for(i = 0, cur = info; i < nr_dom; i++, cur++) { + Py_dominfo *di; + di = Pydominfo_New(); + if ( NULL == di ) + goto err_mem; + memcpy(&di->obj, cur, sizeof(di->obj)); + PyList_SetItem(list, i, (PyObject *)di); + } + + free(info); + return list; +err_mem: + Py_DECREF(list); + PyErr_SetString(PyExc_MemoryError, "Allocating domain list"); + return NULL; +} + +static PyObject *pyxl_domid_to_name(XlObject *self, PyObject *args) +{ + char *domname; + int domid; + PyObject *ret; + + if ( !PyArg_ParseTuple(args, "i", &domid) ) + return NULL; + + domname = libxl_domid_to_name(&self->ctx, domid); + ret = PyString_FromString(domname); + free(domname); + + return ret; +} + +static PyObject *pyxl_domain_shutdown(XlObject *self, PyObject *args) +{ + int domid, req = 0; + if ( !PyArg_ParseTuple(args, "i|i", &domid, &req) ) + return NULL; + if ( libxl_domain_shutdown(&self->ctx, domid, req) ) { + PyErr_SetString(xl_error_obj, "cannot shutdown domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_domain_destroy(XlObject *self, PyObject *args) +{ + int domid, force = 1; + if ( !PyArg_ParseTuple(args, "i|i", &domid, &force) ) + return NULL; + if ( libxl_domain_destroy(&self->ctx, domid, force) ) { + PyErr_SetString(xl_error_obj, "cannot destroy domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_domain_pause(XlObject *self, PyObject *args) +{ + int domid; + if ( !PyArg_ParseTuple(args, "i", &domid) ) + return NULL; + if ( libxl_domain_pause(&self->ctx, domid) ) { + PyErr_SetString(xl_error_obj, "cannot pause domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_domain_unpause(XlObject *self, PyObject *args) +{ + int domid; + if ( !PyArg_ParseTuple(args, "i", &domid) ) + return NULL; + if ( libxl_domain_unpause(&self->ctx, domid) ) { + PyErr_SetString(xl_error_obj, "cannot unpause domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_domain_rename(XlObject *self, PyObject *args) +{ + char *old_name = NULL, *new_name; + int domid; + if ( !PyArg_ParseTuple(args, "is|s", &domid, &new_name, &old_name) ) + return NULL; + if ( libxl_domain_rename(&self->ctx, domid, old_name, new_name, 0) ) { + PyErr_SetString(xl_error_obj, "cannot rename domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_pci_add(XlObject *self, PyObject *args) +{ + Py_device_pci *pci; + PyObject *obj; + int domid; + if ( !PyArg_ParseTuple(args, "iO", &domid, &obj) ) + return NULL; + if ( !Pydevice_pci_Check(obj) ) { + PyErr_SetString(PyExc_TypeError, "Xxpected xl.device_pci"); + return NULL; + } + pci = (Py_device_pci *)obj; + if ( libxl_device_pci_add(&self->ctx, domid, &pci->obj) ) { + PyErr_SetString(xl_error_obj, "cannot add pci device"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_pci_del(XlObject *self, PyObject *args) +{ + Py_device_pci *pci; + PyObject *obj; + int domid; + if ( !PyArg_ParseTuple(args, "iO", &domid, &obj) ) + return NULL; + if ( !Pydevice_pci_Check(obj) ) { + PyErr_SetString(PyExc_TypeError, "Xxpected xl.device_pci"); + return NULL; + } + pci = (Py_device_pci *)obj; + if ( libxl_device_pci_remove(&self->ctx, domid, &pci->obj) ) { + PyErr_SetString(xl_error_obj, "cannot remove pci device"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_pci_parse(XlObject *self, PyObject *args) +{ + Py_device_pci *pci; + char *str; + + if ( !PyArg_ParseTuple(args, "s", &str) ) + return NULL; + + pci = Pydevice_pci_New(); + if ( NULL == pci ) { + PyErr_SetString(PyExc_MemoryError, "Allocating domain list"); + return NULL; + } + + if ( libxl_device_pci_parse_bdf(&self->ctx, &pci->obj, str) ) { + PyErr_SetString(xl_error_obj, "cannot parse pci device spec (BDF)"); + Py_DECREF(pci); + return NULL; + } + + return (PyObject *)pci; +} + +static PyMethodDef pyxl_methods[] = { + {"list_domains", (PyCFunction)pyxl_list_domains, METH_NOARGS, + "List domains"}, + {"domid_to_name", (PyCFunction)pyxl_domid_to_name, METH_VARARGS, + "Retrieve name from domain-id"}, + {"domain_shutdown", (PyCFunction)pyxl_domain_shutdown, METH_VARARGS, + "Shutdown a domain"}, + {"domain_destroy", (PyCFunction)pyxl_domain_destroy, METH_VARARGS, + "Destroy a domain"}, + {"domain_pause", (PyCFunction)pyxl_domain_unpause, METH_VARARGS, + "Pause a domain"}, + {"domain_unpause", (PyCFunction)pyxl_domain_pause, METH_VARARGS, + "Unpause a domain"}, + {"domain_rename", (PyCFunction)pyxl_domain_rename, METH_VARARGS, + "Rename a domain"}, + {"device_pci_add", (PyCFunction)pyxl_pci_add, METH_VARARGS, + "Insert a pass-through PCI device"}, + {"device_pci_del", (PyCFunction)pyxl_pci_del, METH_VARARGS, + "Remove a pass-through PCI device"}, + {"device_pci_parse_bdf", (PyCFunction)pyxl_pci_parse, METH_VARARGS, + "Parse pass-through PCI device spec (BDF)"}, + { NULL, NULL, 0, NULL } +}; + +static PyObject *PyXl_getattr(PyObject *obj, char *name) +{ + return Py_FindMethod(pyxl_methods, obj, name); +} + +static PyObject *PyXl_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + XlObject *self = (XlObject *)type->tp_alloc(type, 0); + + if (self == NULL) + return NULL; + + memset(&self->ctx, 0, sizeof(self->ctx)); + self->logger = NULL; + self->minmsglevel = XTL_PROGRESS; + + return (PyObject *)self; +} + +static int +PyXl_init(XlObject *self, PyObject *args, PyObject *kwds) +{ + self->logger = xtl_createlogger_stdiostream(stderr, self->minmsglevel, 0); + if (!self->logger) { + PyErr_SetString(xl_error_obj, "cannot init xl logger"); + return -1; + } + + if ( libxl_ctx_init(&self->ctx, LIBXL_VERSION, + (xentoollog_logger*)self->logger) ) { + PyErr_SetString(xl_error_obj, "cannot init xl context"); + return -1; + } + + return 0; +} + +static void PyXl_dealloc(XlObject *self) +{ + libxl_ctx_free(&self->ctx); + if ( self->logger ) + xtl_logger_destroy((xentoollog_logger*)self->logger); + + self->ob_type->tp_free((PyObject *)self); +} + +static PyTypeObject PyXlType = { + PyObject_HEAD_INIT(NULL) + 0, + PKG "." CLS, + sizeof(XlObject), + 0, + (destructor)PyXl_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + PyXl_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL, /* tp_hash */ + NULL, /* tp_call */ + NULL, /* tp_str */ + NULL, /* tp_getattro */ + NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "libxenlight connection", /* tp_doc */ + NULL, /* tp_traverse */ + NULL, /* tp_clear */ + NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + pyxl_methods, /* tp_methods */ + NULL, /* tp_members */ + NULL, /* tp_getset */ + NULL, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PyXl_init, /* tp_init */ + NULL, /* tp_alloc */ + PyXl_new, /* tp_new */ +}; + +static PyMethodDef xl_methods[] = { { NULL } }; + +PyMODINIT_FUNC initxl(void) +{ + PyObject *m; + + if (PyType_Ready(&PyXlType) < 0) + return; + + m = Py_InitModule(PKG, xl_methods); + + if (m == NULL) + return; + + xl_error_obj = PyErr_NewException(PKG ".Error", PyExc_RuntimeError, NULL); + + Py_INCREF(&PyXlType); + PyModule_AddObject(m, CLS, (PyObject *)&PyXlType); + + Py_INCREF(xl_error_obj); + PyModule_AddObject(m, "Error", xl_error_obj); + + genwrap__init(m); +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + */ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
On Fri, 2010-09-10 at 16:49 +0100, Gianni Tedesco wrote:> Changes since v1: > - Interpret keyword arguments in initializers: eg. xl.device_pci(bus=1, dev=2, fn=3) > - Implement domain pause/unpause/rename/pci_add/pci_del and pci_parse > - Proper type-checking in all (I hope) code-paths > - Improve API for accessing auto-generated code and types > Changes since RFC: > - split auto-generated code in to c and h files > - un-break the build system > - fix ocaml binding due to libxl API change > - lot''s of tidy-ups too numerous to mention > > -----8<--------------------------------------------------------------- > Introduce python binding for libxl. The binding is not yet complete but > serveral methods are implemented and tested. Those which are implemented > provide examples of the two or three basic patterns that most future > methods should follow. > > Over 5,000 lines of boilerplate is automatically generated to wrap and > export all relevant libxl structure definitions. There are a few places > where such code cannot be fully auto-generated and special hooks are > declared and stubbed where, for example, conversion between > libxl_file_reference and a python file object is required.I''m not qualified to comment on the actual generated bindings themselves but the tiny bit which remains looks good to me. One perhaps interesting tip:> + funcs="""static void Py%s_dealloc(Py_%s *self) > +{ > +%s self->ob_type->tp_free((PyObject *)self);[...etc...]> +} > +"""%((ty.rawname, ty.rawname, dtor) + tuple(ty.rawname for x in range(5)))String formatting in python can take a dictionary and then %(foo)s will expand by looking for the key ''foo'' in the dict which would likely simplify (and help self-document) stuff with this pattern and get rid of the "x in range 5" stuff. I bet you had a hell of a job lining up all the %s''s with their arguments correctly ;-) e.g. """static void Py%(rawname)s_dealloc(Py_%(rawname)s... etc """ % {''rawname'': ty.rawname, ''dtor'': dtor... etc} etc I also think you could get rid of the long """ string containing hand written helpers by putting all that stuff in a pyxl.h and/or xl.c. I''d much prefer to edit the hand-written C code in a .h file where syntax highlighting will work properly etc. If you generate the relevant prototypes correctly then declaration shouldn''t be too much of an issue. Ian. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
On Fri, 2010-09-10 at 17:45 +0100, Ian Campbell wrote:> On Fri, 2010-09-10 at 16:49 +0100, Gianni Tedesco wrote: > > Changes since v1: > > - Interpret keyword arguments in initializers: eg. xl.device_pci(bus=1, dev=2, fn=3) > > - Implement domain pause/unpause/rename/pci_add/pci_del and pci_parse > > - Proper type-checking in all (I hope) code-paths > > - Improve API for accessing auto-generated code and types > > Changes since RFC: > > - split auto-generated code in to c and h files > > - un-break the build system > > - fix ocaml binding due to libxl API change > > - lot''s of tidy-ups too numerous to mention > > > > -----8<--------------------------------------------------------------- > > Introduce python binding for libxl. The binding is not yet complete but > > serveral methods are implemented and tested. Those which are implemented > > provide examples of the two or three basic patterns that most future > > methods should follow. > > > > Over 5,000 lines of boilerplate is automatically generated to wrap and > > export all relevant libxl structure definitions. There are a few places > > where such code cannot be fully auto-generated and special hooks are > > declared and stubbed where, for example, conversion between > > libxl_file_reference and a python file object is required. > > I''m not qualified to comment on the actual generated bindings themselves > but the tiny bit which remains looks good to me. > > One perhaps interesting tip: > > + funcs="""static void Py%s_dealloc(Py_%s *self) > > +{ > > +%s self->ob_type->tp_free((PyObject *)self); > [...etc...] > > +} > > +"""%((ty.rawname, ty.rawname, dtor) + tuple(ty.rawname for x in range(5))) > > String formatting in python can take a dictionary and then %(foo)s will > expand by looking for the key ''foo'' in the dict which would likely > simplify (and help self-document) stuff with this pattern and get rid of > the "x in range 5" stuff. I bet you had a hell of a job lining up all > the %s''s with their arguments correctly ;-)Yeah, well, apart from the one case where it was the same thing 15 times. But yes, I was aware of that usage but never used it before and tbh I hacked this up real quick so there''s a few warts like that.> e.g. > """static void Py%(rawname)s_dealloc(Py_%(rawname)s... etc > """ % {''rawname'': ty.rawname, ''dtor'': dtor... etc} > > etc > > I also think you could get rid of the long """ string containing hand > written helpers by putting all that stuff in a pyxl.h and/or xl.c. I''d > much prefer to edit the hand-written C code in a .h file where syntax > highlighting will work properly etc. If you generate the relevant > prototypes correctly then declaration shouldn''t be too much of an issue.Yeah, the definitions of the genwrap__*_(get|set) funcs can move to xl.c which makes it a lot tidier. With that bit of code motion done (see patch below) it could make sense to add a few python_* attributes in libxltypes.c so that we could, for example, say x = Type(..., python_methods=PyFoo_Methods, python_init=Foobar_Init) which would allow, eg: pci = xl.device_pci(); pci.parse("00:11.2") or allow a non keyword initialiser, eg: pci = xl.device_pci("00:11.2") Anyway, I don''t think this stops us getting the code in the tree cos such things can be done in a future patch. -----8<--------------------------------------------------------------- Introduce python binding for libxl. The binding is not yet complete but serveral methods are implemented and tested. Those which are implemented provide examples of the two or three basic patterns that most future methods should follow. Over 5,000 lines of boilerplate is automatically generated to wrap and export all relevant libxl structure definitions. There are a few places where such code cannot be fully auto-generated and special hooks are declared and stubbed where, for example, conversion between libxl_file_reference and a python file object is required. Signed-off-by: Gianni Tedesco <gianni.tedesco@citrix.com> -- diff -r 57eaf7872ad9 tools/python/Makefile --- a/tools/python/Makefile Fri Sep 10 16:31:07 2010 +0100 +++ b/tools/python/Makefile Fri Sep 10 17:59:37 2010 +0100 @@ -19,7 +19,12 @@ genpath-target = $(call buildmakevars2fi $(eval $(genpath-target)) .PHONY: build buildpy -buildpy: genpath +buildpy: genpath genwrap.py $(XEN_ROOT)/tools/libxl/libxl.idl \ + $(XEN_ROOT)/tools/libxl/libxltypes.py + PYTHONPATH=$(XEN_ROOT)/tools/libxl $(PYTHON) genwrap.py \ + $(XEN_ROOT)/tools/libxl/libxl.idl \ + xen/lowlevel/xl/_pyxl_types.h \ + xen/lowlevel/xl/_pyxl_types.c CC="$(CC)" CFLAGS="$(CFLAGS)" $(PYTHON) setup.py build build: buildpy refresh-pot refresh-po $(CATALOGS) @@ -85,6 +90,8 @@ test: clean: rm -f $(XENPATH) rm -rf build *.pyc *.pyo *.o *.a *~ $(CATALOGS) xen/util/auxbin.pyc + rm -f xen/lowlevel/xl/_pyxl_types.h + rm -f xen/lowlevel/xl/_pyxl_types.c rm -f $(DEPS) -include $(DEPS) diff -r 57eaf7872ad9 tools/python/genwrap.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/genwrap.py Fri Sep 10 17:59:37 2010 +0100 @@ -0,0 +1,280 @@ +#!/usr/bin/python + +import sys,os + +import libxltypes + +def py_type(ty): + if ty == libxltypes.bool or isinstance(ty, libxltypes.BitField) and ty.width == 1: + return "Bool" + if isinstance(ty, libxltypes.Number): + if ty.signed: + return "Int" + else: + return "Uint" + if ty == libxltypes.string: + return "String" + return None + +def py_wrapstruct(ty): + l = [] + l.append("typedef struct {") + l.append(" PyObject_HEAD;") + l.append(" %s obj;"%ty.typename); + l.append("}Py_%s;"%ty.rawname) + l.append("") + return "\n".join(l) + "\n" + +def fsanitize(name): + "Sanitise a function name given a C type" + ret = ''_''.join(name.split()) + return ret.replace(''*'', ''ptr'') + +def py_decls(ty): + l = [] + l.append("_hidden Py_%s *Py%s_New(void);\n"%(ty.rawname, ty.rawname)) + l.append("_hidden int Py%s_Check(PyObject *self);\n"%ty.rawname) + for f in ty.fields: + if py_type(f.type) is not None: + continue + l.append("_hidden PyObject *attrib__%s_get(%s *%s);"%(\ + fsanitize(f.type.typename), f.type.typename, f.name)) + l.append("_hidden int attrib__%s_set(PyObject *v, %s *%s);"%(\ + fsanitize(f.type.typename), f.type.typename, f.name)) + return ''\n''.join(l) + "\n" + +def py_attrib_get(ty, f): + t = py_type(f.type) + l = [] + l.append("static PyObject *py_%s_%s_get(Py_%s *self, void *priv)"%(ty.rawname, f.name, ty.rawname)) + l.append("{") + if t == "Bool": + l.append(" return (self->obj.%s) ? Py_True : Py_False;"%f.name) + elif t == "Int": + l.append(" return genwrap__ll_get(self->obj.%s);"%f.name) + elif t == "Uint": + l.append(" return genwrap__ull_get(self->obj.%s);"%f.name) + elif t == "String": + l.append(" return genwrap__string_get(&self->obj.%s);"%f.name) + else: + tn = f.type.typename + l.append(" return attrib__%s_get((%s *)&self->obj.%s);"%(fsanitize(tn), tn, f.name)) + l.append("}") + return ''\n''.join(l) + "\n\n" + +def py_attrib_set(ty, f): + t = py_type(f.type) + l = [] + l.append("static int py_%s_%s_set(Py_%s *self, PyObject *v, void *priv)"%(ty.rawname, f.name, ty.rawname)) + l.append("{") + if t == "Bool": + l.append(" self->obj.%s = (NULL == v || Py_None == v || Py_False == v) ? 0 : 1;"%f.name) + l.append(" return 0;") + elif t == "Uint" or t == "Int": + l.append(" %slong long tmp;"%(t == "Uint" and "unsigned " or "")) + l.append(" int ret;") + if t == "Uint": + l.append(" ret = genwrap__ull_set(v, &tmp, (%s)~0);"%f.type.typename) + else: + l.append(" ret = genwrap__ll_set(v, &tmp, (%s)~0);"%f.type.typename) + l.append(" if ( ret >= 0 )") + l.append(" self->obj.%s = tmp;"%f.name) + l.append(" return ret;") + elif t == "String": + l.append(" return genwrap__string_set(v, &self->obj.%s);"%f.name) + else: + tn = f.type.typename + l.append(" return attrib__%s_set(v, (%s *)&self->obj.%s);"%(fsanitize(tn), tn, f.name)) + l.append("}") + return ''\n''.join(l) + "\n\n" + +def py_object_def(ty): + l = [] + if ty.destructor_fn is not None: + dtor = " %s(&self->obj);\n"%ty.destructor_fn + else: + dtor = "" + + funcs="""static void Py%s_dealloc(Py_%s *self) +{ +%s self->ob_type->tp_free((PyObject *)self); +} + +static int Py%s_init(Py_%s *self, PyObject *args, PyObject *kwds) +{ + memset(&self->obj, 0, sizeof(self->obj)); + return genwrap__obj_init((PyObject *)self, args, kwds); +} + +static PyObject *Py%s_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + Py_%s *self = (Py_%s *)type->tp_alloc(type, 0); + if (self == NULL) + return NULL; + memset(&self->obj, 0, sizeof(self->obj)); + return (PyObject *)self; +} + +"""%((ty.rawname, ty.rawname, dtor) + tuple(ty.rawname for x in range(5))) + + l.append("static PyGetSetDef Py%s_getset[] = {"%ty.rawname) + for f in ty.fields: + l.append(" { .name = \"%s\", "%f.name) + l.append(" .get = (getter)py_%s_%s_get, "%(ty.rawname, f.name)) + l.append(" .set = (setter)py_%s_%s_set },"%(ty.rawname, f.name)) + l.append(" { .name = NULL }") + l.append("};") + struct=""" +static PyTypeObject Py%s_Type= { + PyObject_HEAD_INIT(NULL) + 0, + PKG ".%s", + sizeof(Py_%s), + 0, + (destructor)Py%s_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL, /* tp_hash */ + NULL, /* tp_call */ + NULL, /* tp_str */ + NULL, /* tp_getattro */ + NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "%s", /* tp_doc */ + NULL, /* tp_traverse */ + NULL, /* tp_clear */ + NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + NULL, /* tp_methods */ + NULL, /* tp_members */ + Py%s_getset, /* tp_getset */ + NULL, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Py%s_init, /* tp_init */ + NULL, /* tp_alloc */ + Py%s_new, /* tp_new */ +}; + +Py_%s *Py%s_New(void) +{ + return (Py_%s *)Py%s_new(&Py%s_Type, NULL, NULL); +} + +int Py%s_Check(PyObject *self) +{ + return (self->ob_type == &Py%s_Type); +} +"""%tuple(ty.rawname for x in range(15)) + return funcs + ''\n''.join(l) + "\n" + struct + +def py_initfuncs(types): + l = [] + l.append("void genwrap__init(PyObject *m)") + l.append("{") + for ty in types: + l.append(" if (PyType_Ready(&Py%s_Type) >= 0) {"%ty.rawname) + l.append(" Py_INCREF(&Py%s_Type);"%ty.rawname) + l.append(" PyModule_AddObject(m, \"%s\", (PyObject *)&Py%s_Type);"%(ty.rawname, ty.rawname)) + l.append(" }") + l.append("}") + return ''\n''.join(l) + "\n\n" + +def tree_frob(types): + ret = filter(lambda x:True, types) # deep copy + for ty in ret: + ty.fields = filter(lambda f:f.name is not None and f.type.typename is not None, ty.fields) + return ret + +if __name__ == ''__main__'': + if len(sys.argv) < 4: + print >>sys.stderr, "Usage: genwrap.py <idl> <decls> <defns>" + sys.exit(1) + + idl = sys.argv[1] + (_,types) = libxltypes.parse(idl) + + types = tree_frob(types) + + decls = sys.argv[2] + f = open(decls, "w") + f.write("""#ifndef __PYXL_TYPES_H +#define __PYXL_TYPES_H + +/* + * DO NOT EDIT. + * + * This file is autogenerated by + * "%s" + */ + +#define PKG "xen.lowlevel.xl" + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +#define _hidden __attribute__((visibility("hidden"))) +#define _protected __attribute__((visibility("protected"))) +#else +#define _hidden +#define _protected +#endif + +/* Initialise all types */ +_hidden void genwrap__init(PyObject *m); + +/* Generic type initialiser */ +_hidden int genwrap__obj_init(PyObject *self, PyObject *args, PyObject *kwds); + +/* Auto-generated get/set functions for simple data-types */ +_hidden int genwrap__string_set(PyObject *v, char **str); +_hidden PyObject *genwrap__string_get(char **str); +_hidden PyObject *genwrap__ull_get(unsigned long long val); +_hidden int genwrap__ull_set(PyObject *v, unsigned long long *val, unsigned long long mask); +_hidden PyObject *genwrap__ll_get(long long val); +_hidden int genwrap__ll_set(PyObject *v, long long *val, long long mask); + +""" % " ".join(sys.argv)) + for ty in types: + f.write("/* Internal APU for %s wrapper */\n"%ty.typename) + f.write(py_wrapstruct(ty)) + f.write(py_decls(ty)) + f.write("\n") + f.write("""#endif /* __PYXL_TYPES_H */\n""") + f.close() + + defns = sys.argv[3] + f = open(defns, "w") + f.write("""/* + * DO NOT EDIT. + * + * This file is autogenerated by + * "%s" + */ + +#include <Python.h> +#include <string.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include "libxl.h" /* gah */ +#include "%s" + +""" % tuple((" ".join(sys.argv),) + (os.path.split(decls)[-1:]),)) + for ty in types: + f.write("/* Attribute get/set functions for %s */\n"%ty.typename) + for a in ty.fields: + f.write(py_attrib_get(ty,a)) + f.write(py_attrib_set(ty,a)) + f.write(py_object_def(ty)) + f.write(py_initfuncs(types)) + f.close() diff -r 57eaf7872ad9 tools/python/setup.py --- a/tools/python/setup.py Fri Sep 10 16:31:07 2010 +0100 +++ b/tools/python/setup.py Fri Sep 10 17:59:37 2010 +0100 @@ -9,14 +9,23 @@ extra_compile_args = [ "-fno-strict-ali include_dirs = [ XEN_ROOT + "/tools/libxc", XEN_ROOT + "/tools/xenstore", XEN_ROOT + "/tools/include", + XEN_ROOT + "/tools/libxl", ] library_dirs = [ XEN_ROOT + "/tools/libxc", XEN_ROOT + "/tools/xenstore", + XEN_ROOT + "/tools/libxl", + XEN_ROOT + "/tools/blktap2/control", ] libraries = [ "xenctrl", "xenguest", "xenstore" ] +plat = os.uname()[0] +if plat == ''Linux'': + uuid_libs = ["uuid"] +else: + uuid_libs = [] + xc = Extension("xc", extra_compile_args = extra_compile_args, include_dirs = include_dirs + [ "xen/lowlevel/xc" ], @@ -83,8 +92,14 @@ netlink = Extension("netlink", sources = [ "xen/lowlevel/netlink/netlink.c", "xen/lowlevel/netlink/libnetlink.c"]) -modules = [ xc, xs, ptsname, acm, flask ] -plat = os.uname()[0] +xl = Extension("xl", + extra_compile_args = extra_compile_args, + include_dirs = include_dirs + [ "xen/lowlevel/xl" ], + library_dirs = library_dirs, + libraries = libraries + ["xenlight", "blktapctl" ] + uuid_libs, + sources = [ "xen/lowlevel/xl/xl.c", "xen/lowlevel/xl/_pyxl_types.c" ]) + +modules = [ xc, xs, ptsname, acm, flask, xl ] if plat == ''SunOS'': modules.extend([ scf, process ]) if plat == ''Linux'': diff -r 57eaf7872ad9 tools/python/xen/lowlevel/xl/xl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/lowlevel/xl/xl.c Fri Sep 10 17:59:37 2010 +0100 @@ -0,0 +1,609 @@ +/****************************************************************************** + * xl.c + * + * Copyright (c) 2010 Citrix Ltd. + * Author: Gianni Tedesco + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General Public + * License as published by the Free Software Foundation. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <Python.h> +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <getopt.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <arpa/inet.h> +#include <xenctrl.h> +#include <ctype.h> +#include <inttypes.h> + + +#include <libxl.h> +#include <libxl_utils.h> + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/* Needed for Python versions earlier than 2.3. */ +#ifndef PyMODINIT_FUNC +#define PyMODINIT_FUNC DL_EXPORT(void) +#endif + +#define CLS "ctx" + +static PyObject *xl_error_obj; + +int genwrap__obj_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *key, *value; + Py_ssize_t pos = 0; + + if ( NULL == kwds ) + return 0; + + while (PyDict_Next(kwds, &pos, &key, &value)) { + if ( PyObject_SetAttr(self, key, value) < 0 ) + return -1; + } + + return 0; +} + +int genwrap__string_set(PyObject *v, char **str) +{ + char *tmp; + if ( NULL == v ) { + free(*str); + *str = NULL; + return 0; + } + if ( !PyString_Check(v) ) { + PyErr_SetString(PyExc_TypeError, "Attribute expected string"); + return -1; + } + tmp = strdup(PyString_AsString(v)); + if ( NULL == tmp ) { + PyErr_SetString(PyExc_MemoryError, "Allocating string attribute"); + return -1; + } + free(*str); + *str = tmp; + return 0; +} + +PyObject *genwrap__string_get(char **str) +{ + if ( NULL == *str ) + return Py_None; + return PyString_FromString(*str); +} + +PyObject *genwrap__ull_get(unsigned long long val) +{ + return PyLong_FromUnsignedLongLong(val); +} + +int genwrap__ull_set(PyObject *v, unsigned long long *val, unsigned long long mask) +{ + unsigned long long tmp; + if ( NULL == v ) { + *val = 0; + return 0; + } + if ( PyLong_Check(v) ) { + tmp = PyLong_AsUnsignedLongLong(v); + }else if ( PyInt_Check(v) ) { + tmp = (unsigned long long)PyInt_AsLong(v); + }else{ + PyErr_SetString(PyExc_TypeError, "Attribute expected int or long"); + return -1; + } + if ( tmp & ~mask ) { + PyErr_SetString(PyExc_ValueError, "Integer overflow"); + return -1; + } + *val = tmp; + return 0; +} + +PyObject *genwrap__ll_get(long long val) +{ + return PyLong_FromLongLong(val); +} + +int genwrap__ll_set(PyObject *v, long long *val, long long mask) +{ + long long tmp; + if ( NULL == v ) { + *val = 0; + return 0; + } + if ( PyLong_Check(v) ) { + tmp = PyLong_AsLongLong(v); + }else{ + tmp = (long long)PyInt_AsLong(v); + } + if ( tmp & ~mask ) { + PyErr_SetString(PyExc_ValueError, "Integer overflow"); + return -1; + } + *val = tmp; + return 0; +} +static int fixed_bytearray_set(PyObject *v, uint8_t *ptr, size_t len) +{ + char *tmp; + size_t sz; + + if ( NULL == v ) { + memset(ptr, 0, len); + return 0; + } + + if ( PyByteArray_Check(v) ) { + sz = PyByteArray_Size(v); + tmp = PyByteArray_AsString(v); + }else if ( PyString_Check(v) ) { + Py_ssize_t ssz; + if ( PyString_AsStringAndSize(v, &tmp, &ssz) ) + return -1; + if ( ssz < 0 ) + tmp = NULL; + sz = ssz; + }else{ + PyErr_SetString(PyExc_TypeError, "Attribute expected bytearray or string"); + return -1; + } + + if ( NULL == tmp ) { + memset(ptr, 0, len); + return 0; + } + if ( sz != len ) { + PyErr_SetString(PyExc_ValueError, + (sz < len) ? "Buffer underflow" : "Buffer overflow"); + return -1; + } + + memcpy(ptr, tmp, sz); + return 0; +} + +static PyObject *fixed_bytearray_get(const uint8_t *ptr, size_t len) +{ + return PyByteArray_FromStringAndSize((const char *)ptr, len); +} + +#include "_pyxl_types.h" + +int attrib__libxl_cpumap_set(PyObject *v, libxl_cpumap *pptr) +{ + return -1; +} + +int attrib__libxl_domain_build_state_ptr_set(PyObject *v, libxl_domain_build_state **pptr) +{ + return -1; +} + +int attrib__libxl_file_reference_set(PyObject *v, libxl_file_reference *pptr) +{ + return -1; +} + +int attrib__libxl_hwcap_set(PyObject *v, libxl_hwcap *pptr) +{ + return -1; +} + +int attrib__libxl_key_value_list_set(PyObject *v, libxl_key_value_list *pptr) +{ + return -1; +} + +int attrib__libxl_mac_set(PyObject *v, libxl_mac *pptr) +{ + return fixed_bytearray_set(v, *pptr, 6); +} + +int attrib__libxl_string_list_set(PyObject *v, libxl_string_list *pptr) +{ + return -1; +} + +int attrib__libxl_uuid_set(PyObject *v, libxl_uuid *pptr) +{ + return fixed_bytearray_set(v, libxl_uuid_bytearray(pptr), 16); +} + +int attrib__struct_in_addr_set(PyObject *v, struct in_addr *pptr) +{ + return -1; +} + +PyObject *attrib__libxl_cpumap_get(libxl_cpumap *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_domain_build_state_ptr_get(libxl_domain_build_state **pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_file_reference_get(libxl_file_reference *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_hwcap_get(libxl_hwcap *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_key_value_list_get(libxl_key_value_list *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_mac_get(libxl_mac *pptr) +{ + return fixed_bytearray_get(*pptr, 6); +} + +PyObject *attrib__libxl_string_list_get(libxl_string_list *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_uuid_get(libxl_uuid *pptr) +{ + return fixed_bytearray_get(libxl_uuid_bytearray(pptr), 16); +} + +PyObject *attrib__struct_in_addr_get(struct in_addr *pptr) +{ + return NULL; +} + +typedef struct { + PyObject_HEAD; + libxl_ctx ctx; + xentoollog_logger_stdiostream *logger; + xentoollog_level minmsglevel; +} XlObject; + +static PyObject *pyxl_list_domains(XlObject *self) +{ + libxl_dominfo *cur, *info; + PyObject *list; + int nr_dom, i; + + info = libxl_list_domain(&self->ctx, &nr_dom); + if ( NULL == info ) + return PyList_New(0); + + list = PyList_New(nr_dom); + if ( NULL == list ) + goto err_mem; + + for(i = 0, cur = info; i < nr_dom; i++, cur++) { + Py_dominfo *di; + di = Pydominfo_New(); + if ( NULL == di ) + goto err_mem; + memcpy(&di->obj, cur, sizeof(di->obj)); + PyList_SetItem(list, i, (PyObject *)di); + } + + free(info); + return list; +err_mem: + Py_DECREF(list); + PyErr_SetString(PyExc_MemoryError, "Allocating domain list"); + return NULL; +} + +static PyObject *pyxl_domid_to_name(XlObject *self, PyObject *args) +{ + char *domname; + int domid; + PyObject *ret; + + if ( !PyArg_ParseTuple(args, "i", &domid) ) + return NULL; + + domname = libxl_domid_to_name(&self->ctx, domid); + ret = PyString_FromString(domname); + free(domname); + + return ret; +} + +static PyObject *pyxl_domain_shutdown(XlObject *self, PyObject *args) +{ + int domid, req = 0; + if ( !PyArg_ParseTuple(args, "i|i", &domid, &req) ) + return NULL; + if ( libxl_domain_shutdown(&self->ctx, domid, req) ) { + PyErr_SetString(xl_error_obj, "cannot shutdown domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_domain_destroy(XlObject *self, PyObject *args) +{ + int domid, force = 1; + if ( !PyArg_ParseTuple(args, "i|i", &domid, &force) ) + return NULL; + if ( libxl_domain_destroy(&self->ctx, domid, force) ) { + PyErr_SetString(xl_error_obj, "cannot destroy domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_domain_pause(XlObject *self, PyObject *args) +{ + int domid; + if ( !PyArg_ParseTuple(args, "i", &domid) ) + return NULL; + if ( libxl_domain_pause(&self->ctx, domid) ) { + PyErr_SetString(xl_error_obj, "cannot pause domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_domain_unpause(XlObject *self, PyObject *args) +{ + int domid; + if ( !PyArg_ParseTuple(args, "i", &domid) ) + return NULL; + if ( libxl_domain_unpause(&self->ctx, domid) ) { + PyErr_SetString(xl_error_obj, "cannot unpause domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_domain_rename(XlObject *self, PyObject *args) +{ + char *old_name = NULL, *new_name; + int domid; + if ( !PyArg_ParseTuple(args, "is|s", &domid, &new_name, &old_name) ) + return NULL; + if ( libxl_domain_rename(&self->ctx, domid, old_name, new_name, 0) ) { + PyErr_SetString(xl_error_obj, "cannot rename domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_pci_add(XlObject *self, PyObject *args) +{ + Py_device_pci *pci; + PyObject *obj; + int domid; + if ( !PyArg_ParseTuple(args, "iO", &domid, &obj) ) + return NULL; + if ( !Pydevice_pci_Check(obj) ) { + PyErr_SetString(PyExc_TypeError, "Xxpected xl.device_pci"); + return NULL; + } + pci = (Py_device_pci *)obj; + if ( libxl_device_pci_add(&self->ctx, domid, &pci->obj) ) { + PyErr_SetString(xl_error_obj, "cannot add pci device"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_pci_del(XlObject *self, PyObject *args) +{ + Py_device_pci *pci; + PyObject *obj; + int domid; + if ( !PyArg_ParseTuple(args, "iO", &domid, &obj) ) + return NULL; + if ( !Pydevice_pci_Check(obj) ) { + PyErr_SetString(PyExc_TypeError, "Xxpected xl.device_pci"); + return NULL; + } + pci = (Py_device_pci *)obj; + if ( libxl_device_pci_remove(&self->ctx, domid, &pci->obj) ) { + PyErr_SetString(xl_error_obj, "cannot remove pci device"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_pci_parse(XlObject *self, PyObject *args) +{ + Py_device_pci *pci; + char *str; + + if ( !PyArg_ParseTuple(args, "s", &str) ) + return NULL; + + pci = Pydevice_pci_New(); + if ( NULL == pci ) { + PyErr_SetString(PyExc_MemoryError, "Allocating domain list"); + return NULL; + } + + if ( libxl_device_pci_parse_bdf(&self->ctx, &pci->obj, str) ) { + PyErr_SetString(xl_error_obj, "cannot parse pci device spec (BDF)"); + Py_DECREF(pci); + return NULL; + } + + return (PyObject *)pci; +} + +static PyMethodDef pyxl_methods[] = { + {"list_domains", (PyCFunction)pyxl_list_domains, METH_NOARGS, + "List domains"}, + {"domid_to_name", (PyCFunction)pyxl_domid_to_name, METH_VARARGS, + "Retrieve name from domain-id"}, + {"domain_shutdown", (PyCFunction)pyxl_domain_shutdown, METH_VARARGS, + "Shutdown a domain"}, + {"domain_destroy", (PyCFunction)pyxl_domain_destroy, METH_VARARGS, + "Destroy a domain"}, + {"domain_pause", (PyCFunction)pyxl_domain_unpause, METH_VARARGS, + "Pause a domain"}, + {"domain_unpause", (PyCFunction)pyxl_domain_pause, METH_VARARGS, + "Unpause a domain"}, + {"domain_rename", (PyCFunction)pyxl_domain_rename, METH_VARARGS, + "Rename a domain"}, + {"device_pci_add", (PyCFunction)pyxl_pci_add, METH_VARARGS, + "Insert a pass-through PCI device"}, + {"device_pci_del", (PyCFunction)pyxl_pci_del, METH_VARARGS, + "Remove a pass-through PCI device"}, + {"device_pci_parse_bdf", (PyCFunction)pyxl_pci_parse, METH_VARARGS, + "Parse pass-through PCI device spec (BDF)"}, + { NULL, NULL, 0, NULL } +}; + +static PyObject *PyXl_getattr(PyObject *obj, char *name) +{ + return Py_FindMethod(pyxl_methods, obj, name); +} + +static PyObject *PyXl_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + XlObject *self = (XlObject *)type->tp_alloc(type, 0); + + if (self == NULL) + return NULL; + + memset(&self->ctx, 0, sizeof(self->ctx)); + self->logger = NULL; + self->minmsglevel = XTL_PROGRESS; + + return (PyObject *)self; +} + +static int +PyXl_init(XlObject *self, PyObject *args, PyObject *kwds) +{ + self->logger = xtl_createlogger_stdiostream(stderr, self->minmsglevel, 0); + if (!self->logger) { + PyErr_SetString(xl_error_obj, "cannot init xl logger"); + return -1; + } + + if ( libxl_ctx_init(&self->ctx, LIBXL_VERSION, + (xentoollog_logger*)self->logger) ) { + PyErr_SetString(xl_error_obj, "cannot init xl context"); + return -1; + } + + return 0; +} + +static void PyXl_dealloc(XlObject *self) +{ + libxl_ctx_free(&self->ctx); + if ( self->logger ) + xtl_logger_destroy((xentoollog_logger*)self->logger); + + self->ob_type->tp_free((PyObject *)self); +} + +static PyTypeObject PyXlType = { + PyObject_HEAD_INIT(NULL) + 0, + PKG "." CLS, + sizeof(XlObject), + 0, + (destructor)PyXl_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + PyXl_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL, /* tp_hash */ + NULL, /* tp_call */ + NULL, /* tp_str */ + NULL, /* tp_getattro */ + NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "libxenlight connection", /* tp_doc */ + NULL, /* tp_traverse */ + NULL, /* tp_clear */ + NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + pyxl_methods, /* tp_methods */ + NULL, /* tp_members */ + NULL, /* tp_getset */ + NULL, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PyXl_init, /* tp_init */ + NULL, /* tp_alloc */ + PyXl_new, /* tp_new */ +}; + +static PyMethodDef xl_methods[] = { { NULL } }; + +PyMODINIT_FUNC initxl(void) +{ + PyObject *m; + + if (PyType_Ready(&PyXlType) < 0) + return; + + m = Py_InitModule(PKG, xl_methods); + + if (m == NULL) + return; + + xl_error_obj = PyErr_NewException(PKG ".Error", PyExc_RuntimeError, NULL); + + Py_INCREF(&PyXlType); + PyModule_AddObject(m, CLS, (PyObject *)&PyXlType); + + Py_INCREF(xl_error_obj); + PyModule_AddObject(m, "Error", xl_error_obj); + + genwrap__init(m); +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + */ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
On Fri, 2010-09-10 at 18:03 +0100, Gianni Tedesco wrote:> On Fri, 2010-09-10 at 17:45 +0100, Ian Campbell wrote: > > On Fri, 2010-09-10 at 16:49 +0100, Gianni Tedesco wrote: > > > Changes since v1: > > > - Interpret keyword arguments in initializers: eg. xl.device_pci(bus=1, dev=2, fn=3) > > > - Implement domain pause/unpause/rename/pci_add/pci_del and pci_parse > > > - Proper type-checking in all (I hope) code-paths > > > - Improve API for accessing auto-generated code and types > > > Changes since RFC: > > > - split auto-generated code in to c and h files > > > - un-break the build system > > > - fix ocaml binding due to libxl API change > > > - lot''s of tidy-ups too numerous to mention > > > > > > -----8<--------------------------------------------------------------- > > > Introduce python binding for libxl. The binding is not yet complete but > > > serveral methods are implemented and tested. Those which are implemented > > > provide examples of the two or three basic patterns that most future > > > methods should follow. > > > > > > Over 5,000 lines of boilerplate is automatically generated to wrap and > > > export all relevant libxl structure definitions. There are a few places > > > where such code cannot be fully auto-generated and special hooks are > > > declared and stubbed where, for example, conversion between > > > libxl_file_reference and a python file object is required. > > > > I''m not qualified to comment on the actual generated bindings themselves > > but the tiny bit which remains looks good to me. > > > > One perhaps interesting tip: > > > + funcs="""static void Py%s_dealloc(Py_%s *self) > > > +{ > > > +%s self->ob_type->tp_free((PyObject *)self); > > [...etc...] > > > +} > > > +"""%((ty.rawname, ty.rawname, dtor) + tuple(ty.rawname for x in range(5))) > > > > String formatting in python can take a dictionary and then %(foo)s will > > expand by looking for the key ''foo'' in the dict which would likely > > simplify (and help self-document) stuff with this pattern and get rid of > > the "x in range 5" stuff. I bet you had a hell of a job lining up all > > the %s''s with their arguments correctly ;-) > > Yeah, well, apart from the one case where it was the same thing 15 > times. But yes, I was aware of that usage but never used it before and > tbh I hacked this up real quick so there''s a few warts like that. > > > e.g. > > """static void Py%(rawname)s_dealloc(Py_%(rawname)s... etc > > """ % {''rawname'': ty.rawname, ''dtor'': dtor... etc} > > > > etc > > > > I also think you could get rid of the long """ string containing hand > > written helpers by putting all that stuff in a pyxl.h and/or xl.c. I''d > > much prefer to edit the hand-written C code in a .h file where syntax > > highlighting will work properly etc. If you generate the relevant > > prototypes correctly then declaration shouldn''t be too much of an issue. > > Yeah, the definitions of the genwrap__*_(get|set) funcs can move to xl.c > which makes it a lot tidier. > > With that bit of code motion done (see patch below) it could make sense > to add a few python_* attributes in libxltypes.c so that we could, for > example, say > > x = Type(..., python_methods=PyFoo_Methods, python_init=Foobar_Init) > > which would allow, eg: pci = xl.device_pci(); pci.parse("00:11.2") or > allow a non keyword initialiser, eg: pci = xl.device_pci("00:11.2")I don''t know that adding language specific stuff to the IDL is any better than just recognising specific type names which would like special handling in the generator.> Anyway, I don''t think this stops us getting the code in the tree cos > such things can be done in a future patch.Agreed. Two things though, firstly the patch to Makefile didn''t apply for me in any version you''ve sent because tabs have become spaces. Might be an issue on my end though. Secondly: xen/lowlevel/xl/xl.c: In function ''fixed_bytearray_set'': xen/lowlevel/xl/xl.c:164: error: implicit declaration of function ''PyByteArray_Check'' xen/lowlevel/xl/xl.c:165: error: implicit declaration of function ''PyByteArray_Size'' xen/lowlevel/xl/xl.c:166: error: implicit declaration of function ''PyByteArray_AsString'' xen/lowlevel/xl/xl.c:166: error: assignment makes pointer from integer without a cast xen/lowlevel/xl/xl.c: In function ''fixed_bytearray_get'': xen/lowlevel/xl/xl.c:195: error: implicit declaration of function ''PyByteArray_FromStringAndSize'' xen/lowlevel/xl/xl.c:195: error: return makes pointer from integer without a cast error: command ''gcc'' failed with exit status 1 This is with Python 2.5 (default on Debian Lenny so, unfortunately, still worth supporting). I guess PyByteArray is new in >2.5? I don''t see a cunning way around it other than making MAC and UUID first class objects instead of wrappers around byte array -- does that make the syntax in the user icky? Oh, and I think you want to add the new generated files to .hgignore. Ian. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
On Sat, 2010-09-11 at 12:27 +0100, Ian Campbell wrote:> > Anyway, I don''t think this stops us getting the code in the tree cos > > such things can be done in a future patch. > > Agreed. > > Two things though, firstly the patch to Makefile didn''t apply for me in > any version you''ve sent because tabs have become spaces. Might be an > issue on my end though.Hmm, not sure what the culprit is but it''s happened to me before, could be evolution or could be xclip... I should probably hg mail more often but find it a bit cumbersome tbh. Wierd because the ocaml stuff is tabs and I assume that worked fine. It may even be vim come to think of it.> Secondly: > xen/lowlevel/xl/xl.c: In function ''fixed_bytearray_set'': > xen/lowlevel/xl/xl.c:164: error: implicit declaration of function ''PyByteArray_Check'' > xen/lowlevel/xl/xl.c:165: error: implicit declaration of function ''PyByteArray_Size'' > xen/lowlevel/xl/xl.c:166: error: implicit declaration of function ''PyByteArray_AsString'' > xen/lowlevel/xl/xl.c:166: error: assignment makes pointer from integer without a cast > xen/lowlevel/xl/xl.c: In function ''fixed_bytearray_get'': > xen/lowlevel/xl/xl.c:195: error: implicit declaration of function ''PyByteArray_FromStringAndSize'' > xen/lowlevel/xl/xl.c:195: error: return makes pointer from integer without a cast > error: command ''gcc'' failed with exit status 1 > > This is with Python 2.5 (default on Debian Lenny so, unfortunately, > still worth supporting). I guess PyByteArray is new in >2.5? I don''t see > a cunning way around it other than making MAC and UUID first class > objects instead of wrappers around byte array -- does that make the > syntax in the user icky?Well, a binary string will work just as well, making these a first class object just means adding a parse and unparse method which will be doing the same thing anyway. I''m pretty sure there''ll be a define to check availability.> Oh, and I think you want to add the new generated files to .hgignore.Ah yes, of course _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
On Sat, 2010-09-11 at 15:48 +0100, Ian Campbell wrote:> On Fri, 2010-09-10 at 18:03 +0100, Gianni Tedesco wrote: > > > > + ret = filter(lambda x:True, types) # deep copy > > I think this is more normally written "ret = list(types)", "ret > types[:]", or: > from copy import copy > ret = copy(types)I think i prefer types[:] (forgot about that) - copy module is a nightmare and IMO nastiest part of python language is semantics viz deep vs shallow copies. Does list() even do deep copy?? (I had no idea)> Although given that the caller does: > types = tree_frob(types) > why is the deep copy necessary? tree_frob could work in-place.Well, it''s going to end up doing the tree flattening for the keyed union type that needs to be handled. Just makes it simpler than keeping around an original list that may or may not contain what you think it does at that point. _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Changes since v2: - Incorporated Ian Campbells suggestions viz python coding style and: - Added autogenerated files to .hgignore - Build-time support for python2.5 Changes since v1: - Interpret keyword arguments in initializers: eg. xl.device_pci(bus=1, dev=2, fn=3) - Implement domain pause/unpause/rename/pci_add/pci_del and pci_parse - Proper type-checking in all (I hope) code-paths - Improve API for accessing auto-generated code and types Changes since RFC: - split auto-generated code in to c and h files - un-break the build system - fix ocaml binding due to libxl API change - lot''s of tidy-ups too numerous to mention -----8<--------------------------------------------------------------- Introduce python binding for libxl. The binding is not yet complete but serveral methods are implemented and tested. Those which are implemented provide examples of the two or three basic patterns that most future methods should follow. Over 5,000 lines of boilerplate is automatically generated to wrap and export all relevant libxl structure definitions. There are a few places where such code cannot be fully auto-generated and special hooks are declared and stubbed where, for example, conversion between libxl_file_reference and a python file object is required. Signed-off-by: Gianni Tedesco <gianni.tedesco@citrix.com> -- .hgignore | 2 tools/python/genwrap.py | 282 ++++++++++++++++ tools/python/xen/lowlevel/xl/xl.c | 615 ++++++++++++++++++++++++++++++++++++ tools/python/Makefile | 9 tools/python/setup.py | 19 - 5 files changed, 924 insertions(+), 3 deletions(-) -- diff -r d018ca309700 .hgignore --- a/.hgignore Mon Sep 13 14:20:39 2010 +0100 +++ b/.hgignore Mon Sep 13 14:47:28 2010 +0100 @@ -211,6 +211,8 @@ ^tools/pygrub/build/.*$ ^tools/python/build/.*$ ^tools/python/xen/util/path\.py$ +^tools/python/xen/lowlevel/xl/_pyxl_types.c +^tools/python/xen/lowlevel/xl/_pyxl_types.h ^tools/remus/imqebt/imqebt$ ^tools/remus/kmod/.*(\.cmd|\.mod|\.ko|\.mod\.c|\.symvers|\.xen)$ ^tools/security/secpol_tool$ diff -r d018ca309700 tools/python/Makefile --- a/tools/python/Makefile Mon Sep 13 14:20:39 2010 +0100 +++ b/tools/python/Makefile Mon Sep 13 14:47:28 2010 +0100 @@ -19,7 +19,12 @@ genpath-target = $(call buildmakevars2fi $(eval $(genpath-target)) .PHONY: build buildpy -buildpy: genpath +buildpy: genpath genwrap.py $(XEN_ROOT)/tools/libxl/libxl.idl \ + $(XEN_ROOT)/tools/libxl/libxltypes.py + PYTHONPATH=$(XEN_ROOT)/tools/libxl $(PYTHON) genwrap.py \ + $(XEN_ROOT)/tools/libxl/libxl.idl \ + xen/lowlevel/xl/_pyxl_types.h \ + xen/lowlevel/xl/_pyxl_types.c CC="$(CC)" CFLAGS="$(CFLAGS)" $(PYTHON) setup.py build build: buildpy refresh-pot refresh-po $(CATALOGS) @@ -85,6 +90,8 @@ test: clean: rm -f $(XENPATH) rm -rf build *.pyc *.pyo *.o *.a *~ $(CATALOGS) xen/util/auxbin.pyc + rm -f xen/lowlevel/xl/_pyxl_types.h + rm -f xen/lowlevel/xl/_pyxl_types.c rm -f $(DEPS) -include $(DEPS) diff -r d018ca309700 tools/python/genwrap.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/genwrap.py Mon Sep 13 14:47:28 2010 +0100 @@ -0,0 +1,282 @@ +#!/usr/bin/python + +import sys,os + +import libxltypes + +(TYPE_BOOL, TYPE_INT, TYPE_UINT, TYPE_STRING) = range(4) + +def py_type(ty): + if ty == libxltypes.bool or isinstance(ty, libxltypes.BitField) and ty.width == 1: + return TYPE_BOOL + if isinstance(ty, libxltypes.Number): + if ty.signed: + return TYPE_INT + else: + return TYPE_UINT + if ty == libxltypes.string: + return TYPE_STRING + return None + +def py_wrapstruct(ty): + l = [] + l.append(''typedef struct {'') + l.append('' PyObject_HEAD;'') + l.append('' %s obj;''%ty.typename); + l.append(''}Py_%s;''%ty.rawname) + l.append('''') + return "\n".join(l) + "\n" + +def fsanitize(name): + "Sanitise a function name given a C type" + ret = ''_''.join(name.split()) + return ret.replace(''*'', ''ptr'') + +def py_decls(ty): + l = [] + l.append(''_hidden Py_%s *Py%s_New(void);\n''%(ty.rawname, ty.rawname)) + l.append(''_hidden int Py%s_Check(PyObject *self);\n''%ty.rawname) + for f in ty.fields: + if py_type(f.type) is not None: + continue + l.append(''_hidden PyObject *attrib__%s_get(%s *%s);''%(\ + fsanitize(f.type.typename), f.type.typename, f.name)) + l.append(''_hidden int attrib__%s_set(PyObject *v, %s *%s);''%(\ + fsanitize(f.type.typename), f.type.typename, f.name)) + return ''\n''.join(l) + "\n" + +def py_attrib_get(ty, f): + t = py_type(f.type) + l = [] + l.append(''static PyObject *py_%s_%s_get(Py_%s *self, void *priv)''%(ty.rawname, f.name, ty.rawname)) + l.append(''{'') + if t == TYPE_BOOL: + l.append('' return (self->obj.%s) ? Py_True : Py_False;''%f.name) + elif t == TYPE_INT: + l.append('' return genwrap__ll_get(self->obj.%s);''%f.name) + elif t == TYPE_UINT: + l.append('' return genwrap__ull_get(self->obj.%s);''%f.name) + elif t == TYPE_STRING: + l.append('' return genwrap__string_get(&self->obj.%s);''%f.name) + else: + tn = f.type.typename + l.append('' return attrib__%s_get((%s *)&self->obj.%s);''%(fsanitize(tn), tn, f.name)) + l.append(''}'') + return ''\n''.join(l) + "\n\n" + +def py_attrib_set(ty, f): + t = py_type(f.type) + l = [] + l.append(''static int py_%s_%s_set(Py_%s *self, PyObject *v, void *priv)''%(ty.rawname, f.name, ty.rawname)) + l.append(''{'') + if t == TYPE_BOOL: + l.append('' self->obj.%s = (NULL == v || Py_None == v || Py_False == v) ? 0 : 1;''%f.name) + l.append('' return 0;'') + elif t == TYPE_UINT or t == TYPE_INT: + l.append('' %slong long tmp;''%(t == TYPE_UINT and ''unsigned '' or '''')) + l.append('' int ret;'') + if t == TYPE_UINT: + l.append('' ret = genwrap__ull_set(v, &tmp, (%s)~0);''%f.type.typename) + else: + l.append('' ret = genwrap__ll_set(v, &tmp, (%s)~0);''%f.type.typename) + l.append('' if ( ret >= 0 )'') + l.append('' self->obj.%s = tmp;''%f.name) + l.append('' return ret;'') + elif t == TYPE_STRING: + l.append('' return genwrap__string_set(v, &self->obj.%s);''%f.name) + else: + tn = f.type.typename + l.append('' return attrib__%s_set(v, (%s *)&self->obj.%s);''%(fsanitize(tn), tn, f.name)) + l.append(''}'') + return ''\n''.join(l) + "\n\n" + +def py_object_def(ty): + l = [] + if ty.destructor_fn is not None: + dtor = '' %s(&self->obj);\n''%ty.destructor_fn + else: + dtor = '''' + + funcs="""static void Py%(rawname)s_dealloc(Py_%(rawname)s *self) +{ +%(dtor)s self->ob_type->tp_free((PyObject *)self); +} + +static int Py%(rawname)s_init(Py_%(rawname)s *self, PyObject *args, PyObject *kwds) +{ + memset(&self->obj, 0, sizeof(self->obj)); + return genwrap__obj_init((PyObject *)self, args, kwds); +} + +static PyObject *Py%(rawname)s_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + Py_%(rawname)s *self = (Py_%(rawname)s *)type->tp_alloc(type, 0); + if (self == NULL) + return NULL; + memset(&self->obj, 0, sizeof(self->obj)); + return (PyObject *)self; +} + +"""%{''rawname'': ty.rawname, ''dtor'': dtor} + + l.append(''static PyGetSetDef Py%s_getset[] = {''%ty.rawname) + for f in ty.fields: + l.append('' { .name = "%s", ''%f.name) + l.append('' .get = (getter)py_%s_%s_get, ''%(ty.rawname, f.name)) + l.append('' .set = (setter)py_%s_%s_set },''%(ty.rawname, f.name)) + l.append('' { .name = NULL }'') + l.append(''};'') + struct=""" +static PyTypeObject Py%s_Type= { + PyObject_HEAD_INIT(NULL) + 0, + PKG ".%s", + sizeof(Py_%s), + 0, + (destructor)Py%s_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + NULL, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL, /* tp_hash */ + NULL, /* tp_call */ + NULL, /* tp_str */ + NULL, /* tp_getattro */ + NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "%s", /* tp_doc */ + NULL, /* tp_traverse */ + NULL, /* tp_clear */ + NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + NULL, /* tp_methods */ + NULL, /* tp_members */ + Py%s_getset, /* tp_getset */ + NULL, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)Py%s_init, /* tp_init */ + NULL, /* tp_alloc */ + Py%s_new, /* tp_new */ +}; + +Py_%s *Py%s_New(void) +{ + return (Py_%s *)Py%s_new(&Py%s_Type, NULL, NULL); +} + +int Py%s_Check(PyObject *self) +{ + return (self->ob_type == &Py%s_Type); +} +"""%tuple(ty.rawname for x in range(15)) + return funcs + ''\n''.join(l) + "\n" + struct + +def py_initfuncs(types): + l = [] + l.append(''void genwrap__init(PyObject *m)'') + l.append(''{'') + for ty in types: + l.append('' if (PyType_Ready(&Py%s_Type) >= 0) {''%ty.rawname) + l.append('' Py_INCREF(&Py%s_Type);''%ty.rawname) + l.append('' PyModule_AddObject(m, "%s", (PyObject *)&Py%s_Type);''%(ty.rawname, ty.rawname)) + l.append('' }'') + l.append(''}'') + return ''\n''.join(l) + "\n\n" + +def tree_frob(types): + ret = types[:] + for ty in ret: + ty.fields = filter(lambda f:f.name is not None and f.type.typename is not None, ty.fields) + return ret + +if __name__ == ''__main__'': + if len(sys.argv) < 4: + print >>sys.stderr, "Usage: genwrap.py <idl> <decls> <defns>" + sys.exit(1) + + idl = sys.argv[1] + (_,types) = libxltypes.parse(idl) + + types = tree_frob(types) + + decls = sys.argv[2] + f = open(decls, ''w'') + f.write("""#ifndef __PYXL_TYPES_H +#define __PYXL_TYPES_H + +/* + * DO NOT EDIT. + * + * This file is autogenerated by + * "%s" + */ + +#define PKG "xen.lowlevel.xl" + +#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1) +#define _hidden __attribute__((visibility("hidden"))) +#define _protected __attribute__((visibility("protected"))) +#else +#define _hidden +#define _protected +#endif + +/* Initialise all types */ +_hidden void genwrap__init(PyObject *m); + +/* Generic type initialiser */ +_hidden int genwrap__obj_init(PyObject *self, PyObject *args, PyObject *kwds); + +/* Auto-generated get/set functions for simple data-types */ +_hidden int genwrap__string_set(PyObject *v, char **str); +_hidden PyObject *genwrap__string_get(char **str); +_hidden PyObject *genwrap__ull_get(unsigned long long val); +_hidden int genwrap__ull_set(PyObject *v, unsigned long long *val, unsigned long long mask); +_hidden PyObject *genwrap__ll_get(long long val); +_hidden int genwrap__ll_set(PyObject *v, long long *val, long long mask); + +""" % " ".join(sys.argv)) + for ty in types: + f.write(''/* Internal APU for %s wrapper */\n''%ty.typename) + f.write(py_wrapstruct(ty)) + f.write(py_decls(ty)) + f.write(''\n'') + f.write(''#endif /* __PYXL_TYPES_H */\n'') + f.close() + + defns = sys.argv[3] + f = open(defns, ''w'') + f.write("""/* + * DO NOT EDIT. + * + * This file is autogenerated by + * "%s" + */ + +#include <Python.h> +#include <string.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include "libxl.h" /* gah */ +#include "%s" + +""" % tuple(('' ''.join(sys.argv),) + (os.path.split(decls)[-1:]),)) + for ty in types: + f.write(''/* Attribute get/set functions for %s */\n''%ty.typename) + for a in ty.fields: + f.write(py_attrib_get(ty,a)) + f.write(py_attrib_set(ty,a)) + f.write(py_object_def(ty)) + f.write(py_initfuncs(types)) + f.close() diff -r d018ca309700 tools/python/setup.py --- a/tools/python/setup.py Mon Sep 13 14:20:39 2010 +0100 +++ b/tools/python/setup.py Mon Sep 13 14:47:28 2010 +0100 @@ -9,14 +9,23 @@ extra_compile_args = [ "-fno-strict-ali include_dirs = [ XEN_ROOT + "/tools/libxc", XEN_ROOT + "/tools/xenstore", XEN_ROOT + "/tools/include", + XEN_ROOT + "/tools/libxl", ] library_dirs = [ XEN_ROOT + "/tools/libxc", XEN_ROOT + "/tools/xenstore", + XEN_ROOT + "/tools/libxl", + XEN_ROOT + "/tools/blktap2/control", ] libraries = [ "xenctrl", "xenguest", "xenstore" ] +plat = os.uname()[0] +if plat == ''Linux'': + uuid_libs = ["uuid"] +else: + uuid_libs = [] + xc = Extension("xc", extra_compile_args = extra_compile_args, include_dirs = include_dirs + [ "xen/lowlevel/xc" ], @@ -83,8 +92,14 @@ netlink = Extension("netlink", sources = [ "xen/lowlevel/netlink/netlink.c", "xen/lowlevel/netlink/libnetlink.c"]) -modules = [ xc, xs, ptsname, acm, flask ] -plat = os.uname()[0] +xl = Extension("xl", + extra_compile_args = extra_compile_args, + include_dirs = include_dirs + [ "xen/lowlevel/xl" ], + library_dirs = library_dirs, + libraries = libraries + ["xenlight", "blktapctl" ] + uuid_libs, + sources = [ "xen/lowlevel/xl/xl.c", "xen/lowlevel/xl/_pyxl_types.c" ]) + +modules = [ xc, xs, ptsname, acm, flask, xl ] if plat == ''SunOS'': modules.extend([ scf, process ]) if plat == ''Linux'': diff -r d018ca309700 tools/python/xen/lowlevel/xl/xl.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tools/python/xen/lowlevel/xl/xl.c Mon Sep 13 14:47:28 2010 +0100 @@ -0,0 +1,615 @@ +/****************************************************************************** + * xl.c + * + * Copyright (c) 2010 Citrix Ltd. + * Author: Gianni Tedesco + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General Public + * License as published by the Free Software Foundation. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <Python.h> +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <time.h> +#include <getopt.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/socket.h> +#include <sys/select.h> +#include <arpa/inet.h> +#include <xenctrl.h> +#include <ctype.h> +#include <inttypes.h> + +#include <libxl.h> +#include <libxl_utils.h> + +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) + +/* Needed for Python versions earlier than 2.3. */ +#ifndef PyMODINIT_FUNC +#define PyMODINIT_FUNC DL_EXPORT(void) +#endif + +#define CLS "ctx" + +static PyObject *xl_error_obj; + +int genwrap__obj_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *key, *value; + Py_ssize_t pos = 0; + + if ( NULL == kwds ) + return 0; + + while (PyDict_Next(kwds, &pos, &key, &value)) { + if ( PyObject_SetAttr(self, key, value) < 0 ) + return -1; + } + + return 0; +} + +int genwrap__string_set(PyObject *v, char **str) +{ + char *tmp; + if ( NULL == v ) { + free(*str); + *str = NULL; + return 0; + } + if ( !PyString_Check(v) ) { + PyErr_SetString(PyExc_TypeError, "Attribute expected string"); + return -1; + } + tmp = strdup(PyString_AsString(v)); + if ( NULL == tmp ) { + PyErr_SetString(PyExc_MemoryError, "Allocating string attribute"); + return -1; + } + free(*str); + *str = tmp; + return 0; +} + +PyObject *genwrap__string_get(char **str) +{ + if ( NULL == *str ) + return Py_None; + return PyString_FromString(*str); +} + +PyObject *genwrap__ull_get(unsigned long long val) +{ + return PyLong_FromUnsignedLongLong(val); +} + +int genwrap__ull_set(PyObject *v, unsigned long long *val, unsigned long long mask) +{ + unsigned long long tmp; + if ( NULL == v ) { + *val = 0; + return 0; + } + if ( PyLong_Check(v) ) { + tmp = PyLong_AsUnsignedLongLong(v); + }else if ( PyInt_Check(v) ) { + tmp = (unsigned long long)PyInt_AsLong(v); + }else{ + PyErr_SetString(PyExc_TypeError, "Attribute expected int or long"); + return -1; + } + if ( tmp & ~mask ) { + PyErr_SetString(PyExc_ValueError, "Integer overflow"); + return -1; + } + *val = tmp; + return 0; +} + +PyObject *genwrap__ll_get(long long val) +{ + return PyLong_FromLongLong(val); +} + +int genwrap__ll_set(PyObject *v, long long *val, long long mask) +{ + long long tmp; + if ( NULL == v ) { + *val = 0; + return 0; + } + if ( PyLong_Check(v) ) { + tmp = PyLong_AsLongLong(v); + }else{ + tmp = (long long)PyInt_AsLong(v); + } + if ( tmp & ~mask ) { + PyErr_SetString(PyExc_ValueError, "Integer overflow"); + return -1; + } + *val = tmp; + return 0; +} +static int fixed_bytearray_set(PyObject *v, uint8_t *ptr, size_t len) +{ + char *tmp; + size_t sz; + + if ( NULL == v ) { + memset(ptr, 0, len); + return 0; + } + +#ifdef PyByteArray_Check + if ( PyByteArray_Check(v) ) { + sz = PyByteArray_Size(v); + tmp = PyByteArray_AsString(v); + }else +#endif + if ( PyString_Check(v) ) { + Py_ssize_t ssz; + if ( PyString_AsStringAndSize(v, &tmp, &ssz) ) + return -1; + if ( ssz < 0 ) + tmp = NULL; + sz = ssz; + }else{ + PyErr_SetString(PyExc_TypeError, "Attribute expected bytearray or string"); + return -1; + } + + if ( NULL == tmp ) { + memset(ptr, 0, len); + return 0; + } + if ( sz != len ) { + PyErr_SetString(PyExc_ValueError, + (sz < len) ? "Buffer underflow" : "Buffer overflow"); + return -1; + } + + memcpy(ptr, tmp, sz); + return 0; +} + +static PyObject *fixed_bytearray_get(const uint8_t *ptr, size_t len) +{ +#ifdef PyByteArray_Check + return PyByteArray_FromStringAndSize((const char *)ptr, len); +#else + return PyString_FromStringAndSize((const char *)ptr, len); +#endif +} + +#include "_pyxl_types.h" + +int attrib__libxl_cpumap_set(PyObject *v, libxl_cpumap *pptr) +{ + return -1; +} + +int attrib__libxl_domain_build_state_ptr_set(PyObject *v, libxl_domain_build_state **pptr) +{ + return -1; +} + +int attrib__libxl_file_reference_set(PyObject *v, libxl_file_reference *pptr) +{ + return -1; +} + +int attrib__libxl_hwcap_set(PyObject *v, libxl_hwcap *pptr) +{ + return -1; +} + +int attrib__libxl_key_value_list_set(PyObject *v, libxl_key_value_list *pptr) +{ + return -1; +} + +int attrib__libxl_mac_set(PyObject *v, libxl_mac *pptr) +{ + return fixed_bytearray_set(v, *pptr, 6); +} + +int attrib__libxl_string_list_set(PyObject *v, libxl_string_list *pptr) +{ + return -1; +} + +int attrib__libxl_uuid_set(PyObject *v, libxl_uuid *pptr) +{ + return fixed_bytearray_set(v, libxl_uuid_bytearray(pptr), 16); +} + +int attrib__struct_in_addr_set(PyObject *v, struct in_addr *pptr) +{ + return -1; +} + +PyObject *attrib__libxl_cpumap_get(libxl_cpumap *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_domain_build_state_ptr_get(libxl_domain_build_state **pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_file_reference_get(libxl_file_reference *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_hwcap_get(libxl_hwcap *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_key_value_list_get(libxl_key_value_list *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_mac_get(libxl_mac *pptr) +{ + return fixed_bytearray_get(*pptr, 6); +} + +PyObject *attrib__libxl_string_list_get(libxl_string_list *pptr) +{ + return NULL; +} + +PyObject *attrib__libxl_uuid_get(libxl_uuid *pptr) +{ + return fixed_bytearray_get(libxl_uuid_bytearray(pptr), 16); +} + +PyObject *attrib__struct_in_addr_get(struct in_addr *pptr) +{ + return NULL; +} + +typedef struct { + PyObject_HEAD; + libxl_ctx ctx; + xentoollog_logger_stdiostream *logger; + xentoollog_level minmsglevel; +} XlObject; + +static PyObject *pyxl_list_domains(XlObject *self) +{ + libxl_dominfo *cur, *info; + PyObject *list; + int nr_dom, i; + + info = libxl_list_domain(&self->ctx, &nr_dom); + if ( NULL == info ) + return PyList_New(0); + + list = PyList_New(nr_dom); + if ( NULL == list ) + goto err_mem; + + for(i = 0, cur = info; i < nr_dom; i++, cur++) { + Py_dominfo *di; + di = Pydominfo_New(); + if ( NULL == di ) + goto err_mem; + memcpy(&di->obj, cur, sizeof(di->obj)); + PyList_SetItem(list, i, (PyObject *)di); + } + + free(info); + return list; +err_mem: + Py_DECREF(list); + PyErr_SetString(PyExc_MemoryError, "Allocating domain list"); + return NULL; +} + +static PyObject *pyxl_domid_to_name(XlObject *self, PyObject *args) +{ + char *domname; + int domid; + PyObject *ret; + + if ( !PyArg_ParseTuple(args, "i", &domid) ) + return NULL; + + domname = libxl_domid_to_name(&self->ctx, domid); + ret = PyString_FromString(domname); + free(domname); + + return ret; +} + +static PyObject *pyxl_domain_shutdown(XlObject *self, PyObject *args) +{ + int domid, req = 0; + if ( !PyArg_ParseTuple(args, "i|i", &domid, &req) ) + return NULL; + if ( libxl_domain_shutdown(&self->ctx, domid, req) ) { + PyErr_SetString(xl_error_obj, "cannot shutdown domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_domain_destroy(XlObject *self, PyObject *args) +{ + int domid, force = 1; + if ( !PyArg_ParseTuple(args, "i|i", &domid, &force) ) + return NULL; + if ( libxl_domain_destroy(&self->ctx, domid, force) ) { + PyErr_SetString(xl_error_obj, "cannot destroy domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_domain_pause(XlObject *self, PyObject *args) +{ + int domid; + if ( !PyArg_ParseTuple(args, "i", &domid) ) + return NULL; + if ( libxl_domain_pause(&self->ctx, domid) ) { + PyErr_SetString(xl_error_obj, "cannot pause domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_domain_unpause(XlObject *self, PyObject *args) +{ + int domid; + if ( !PyArg_ParseTuple(args, "i", &domid) ) + return NULL; + if ( libxl_domain_unpause(&self->ctx, domid) ) { + PyErr_SetString(xl_error_obj, "cannot unpause domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_domain_rename(XlObject *self, PyObject *args) +{ + char *old_name = NULL, *new_name; + int domid; + if ( !PyArg_ParseTuple(args, "is|s", &domid, &new_name, &old_name) ) + return NULL; + if ( libxl_domain_rename(&self->ctx, domid, old_name, new_name, 0) ) { + PyErr_SetString(xl_error_obj, "cannot rename domain"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_pci_add(XlObject *self, PyObject *args) +{ + Py_device_pci *pci; + PyObject *obj; + int domid; + if ( !PyArg_ParseTuple(args, "iO", &domid, &obj) ) + return NULL; + if ( !Pydevice_pci_Check(obj) ) { + PyErr_SetString(PyExc_TypeError, "Xxpected xl.device_pci"); + return NULL; + } + pci = (Py_device_pci *)obj; + if ( libxl_device_pci_add(&self->ctx, domid, &pci->obj) ) { + PyErr_SetString(xl_error_obj, "cannot add pci device"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_pci_del(XlObject *self, PyObject *args) +{ + Py_device_pci *pci; + PyObject *obj; + int domid; + if ( !PyArg_ParseTuple(args, "iO", &domid, &obj) ) + return NULL; + if ( !Pydevice_pci_Check(obj) ) { + PyErr_SetString(PyExc_TypeError, "Xxpected xl.device_pci"); + return NULL; + } + pci = (Py_device_pci *)obj; + if ( libxl_device_pci_remove(&self->ctx, domid, &pci->obj) ) { + PyErr_SetString(xl_error_obj, "cannot remove pci device"); + return NULL; + } + return Py_None; +} + +static PyObject *pyxl_pci_parse(XlObject *self, PyObject *args) +{ + Py_device_pci *pci; + char *str; + + if ( !PyArg_ParseTuple(args, "s", &str) ) + return NULL; + + pci = Pydevice_pci_New(); + if ( NULL == pci ) { + PyErr_SetString(PyExc_MemoryError, "Allocating domain list"); + return NULL; + } + + if ( libxl_device_pci_parse_bdf(&self->ctx, &pci->obj, str) ) { + PyErr_SetString(xl_error_obj, "cannot parse pci device spec (BDF)"); + Py_DECREF(pci); + return NULL; + } + + return (PyObject *)pci; +} + +static PyMethodDef pyxl_methods[] = { + {"list_domains", (PyCFunction)pyxl_list_domains, METH_NOARGS, + "List domains"}, + {"domid_to_name", (PyCFunction)pyxl_domid_to_name, METH_VARARGS, + "Retrieve name from domain-id"}, + {"domain_shutdown", (PyCFunction)pyxl_domain_shutdown, METH_VARARGS, + "Shutdown a domain"}, + {"domain_destroy", (PyCFunction)pyxl_domain_destroy, METH_VARARGS, + "Destroy a domain"}, + {"domain_pause", (PyCFunction)pyxl_domain_unpause, METH_VARARGS, + "Pause a domain"}, + {"domain_unpause", (PyCFunction)pyxl_domain_pause, METH_VARARGS, + "Unpause a domain"}, + {"domain_rename", (PyCFunction)pyxl_domain_rename, METH_VARARGS, + "Rename a domain"}, + {"device_pci_add", (PyCFunction)pyxl_pci_add, METH_VARARGS, + "Insert a pass-through PCI device"}, + {"device_pci_del", (PyCFunction)pyxl_pci_del, METH_VARARGS, + "Remove a pass-through PCI device"}, + {"device_pci_parse_bdf", (PyCFunction)pyxl_pci_parse, METH_VARARGS, + "Parse pass-through PCI device spec (BDF)"}, + { NULL, NULL, 0, NULL } +}; + +static PyObject *PyXl_getattr(PyObject *obj, char *name) +{ + return Py_FindMethod(pyxl_methods, obj, name); +} + +static PyObject *PyXl_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + XlObject *self = (XlObject *)type->tp_alloc(type, 0); + + if (self == NULL) + return NULL; + + memset(&self->ctx, 0, sizeof(self->ctx)); + self->logger = NULL; + self->minmsglevel = XTL_PROGRESS; + + return (PyObject *)self; +} + +static int +PyXl_init(XlObject *self, PyObject *args, PyObject *kwds) +{ + self->logger = xtl_createlogger_stdiostream(stderr, self->minmsglevel, 0); + if (!self->logger) { + PyErr_SetString(xl_error_obj, "cannot init xl logger"); + return -1; + } + + if ( libxl_ctx_init(&self->ctx, LIBXL_VERSION, + (xentoollog_logger*)self->logger) ) { + PyErr_SetString(xl_error_obj, "cannot init xl context"); + return -1; + } + + return 0; +} + +static void PyXl_dealloc(XlObject *self) +{ + libxl_ctx_free(&self->ctx); + if ( self->logger ) + xtl_logger_destroy((xentoollog_logger*)self->logger); + + self->ob_type->tp_free((PyObject *)self); +} + +static PyTypeObject PyXlType = { + PyObject_HEAD_INIT(NULL) + 0, + PKG "." CLS, + sizeof(XlObject), + 0, + (destructor)PyXl_dealloc, /* tp_dealloc */ + NULL, /* tp_print */ + PyXl_getattr, /* tp_getattr */ + NULL, /* tp_setattr */ + NULL, /* tp_compare */ + NULL, /* tp_repr */ + NULL, /* tp_as_number */ + NULL, /* tp_as_sequence */ + NULL, /* tp_as_mapping */ + NULL, /* tp_hash */ + NULL, /* tp_call */ + NULL, /* tp_str */ + NULL, /* tp_getattro */ + NULL, /* tp_setattro */ + NULL, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "libxenlight connection", /* tp_doc */ + NULL, /* tp_traverse */ + NULL, /* tp_clear */ + NULL, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + NULL, /* tp_iter */ + NULL, /* tp_iternext */ + pyxl_methods, /* tp_methods */ + NULL, /* tp_members */ + NULL, /* tp_getset */ + NULL, /* tp_base */ + NULL, /* tp_dict */ + NULL, /* tp_descr_get */ + NULL, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PyXl_init, /* tp_init */ + NULL, /* tp_alloc */ + PyXl_new, /* tp_new */ +}; + +static PyMethodDef xl_methods[] = { { NULL } }; + +PyMODINIT_FUNC initxl(void) +{ + PyObject *m; + + if (PyType_Ready(&PyXlType) < 0) + return; + + m = Py_InitModule(PKG, xl_methods); + + if (m == NULL) + return; + + xl_error_obj = PyErr_NewException(PKG ".Error", PyExc_RuntimeError, NULL); + + Py_INCREF(&PyXlType); + PyModule_AddObject(m, CLS, (PyObject *)&PyXlType); + + Py_INCREF(xl_error_obj); + PyModule_AddObject(m, "Error", xl_error_obj); + + genwrap__init(m); +} + + +/* + * Local variables: + * c-indent-level: 4 + * c-basic-offset: 4 + * End: + */ _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
On Mon, 2010-09-13 at 16:33 +0100, Gianni Tedesco wrote:> Changes since v2: > - Incorporated Ian Campbells suggestions viz python coding style and: > - Added autogenerated files to .hgignore > - Build-time support for python2.5Obviously this is v3 :P _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
On Sat, 2010-09-11 at 12:27 +0100, Ian Campbell wrote:> On Fri, 2010-09-10 at 18:03 +0100, Gianni Tedesco wrote: > > On Fri, 2010-09-10 at 17:45 +0100, Ian Campbell wrote: > > > On Fri, 2010-09-10 at 16:49 +0100, Gianni Tedesco wrote: > > > > Changes since v1: > > > > - Interpret keyword arguments in initializers: eg. xl.device_pci(bus=1, dev=2, fn=3) > > > > - Implement domain pause/unpause/rename/pci_add/pci_del and pci_parse > > > > - Proper type-checking in all (I hope) code-paths > > > > - Improve API for accessing auto-generated code and types > > > > Changes since RFC: > > > > - split auto-generated code in to c and h files > > > > - un-break the build system > > > > - fix ocaml binding due to libxl API change > > > > - lot''s of tidy-ups too numerous to mention > > > > > > > > -----8<--------------------------------------------------------------- > > > > Introduce python binding for libxl. The binding is not yet complete but > > > > serveral methods are implemented and tested. Those which are implemented > > > > provide examples of the two or three basic patterns that most future > > > > methods should follow. > > > > > > > > Over 5,000 lines of boilerplate is automatically generated to wrap and > > > > export all relevant libxl structure definitions. There are a few places > > > > where such code cannot be fully auto-generated and special hooks are > > > > declared and stubbed where, for example, conversion between > > > > libxl_file_reference and a python file object is required. > > > > > > I''m not qualified to comment on the actual generated bindings themselves > > > but the tiny bit which remains looks good to me. > > > > > > One perhaps interesting tip: > > > > + funcs="""static void Py%s_dealloc(Py_%s *self) > > > > +{ > > > > +%s self->ob_type->tp_free((PyObject *)self); > > > [...etc...] > > > > +} > > > > +"""%((ty.rawname, ty.rawname, dtor) + tuple(ty.rawname for x in range(5))) > > > > > > String formatting in python can take a dictionary and then %(foo)s will > > > expand by looking for the key ''foo'' in the dict which would likely > > > simplify (and help self-document) stuff with this pattern and get rid of > > > the "x in range 5" stuff. I bet you had a hell of a job lining up all > > > the %s''s with their arguments correctly ;-) > > > > Yeah, well, apart from the one case where it was the same thing 15 > > times. But yes, I was aware of that usage but never used it before and > > tbh I hacked this up real quick so there''s a few warts like that. > > > > > e.g. > > > """static void Py%(rawname)s_dealloc(Py_%(rawname)s... etc > > > """ % {''rawname'': ty.rawname, ''dtor'': dtor... etc} > > > > > > etc > > > > > > I also think you could get rid of the long """ string containing hand > > > written helpers by putting all that stuff in a pyxl.h and/or xl.c. I''d > > > much prefer to edit the hand-written C code in a .h file where syntax > > > highlighting will work properly etc. If you generate the relevant > > > prototypes correctly then declaration shouldn''t be too much of an issue. > > > > Yeah, the definitions of the genwrap__*_(get|set) funcs can move to xl.c > > which makes it a lot tidier. > > > > With that bit of code motion done (see patch below) it could make sense > > to add a few python_* attributes in libxltypes.c so that we could, for > > example, say > > > > x = Type(..., python_methods=PyFoo_Methods, python_init=Foobar_Init) > > > > which would allow, eg: pci = xl.device_pci(); pci.parse("00:11.2") or > > allow a non keyword initialiser, eg: pci = xl.device_pci("00:11.2") > > I don''t know that adding language specific stuff to the IDL is any > better than just recognising specific type names which would like > special handling in the generator.Actually I think enabling inheritance in the generated objects is the way to do this. It just requires a bit of glue code both in the C and in any inherited python wrappers to make it all work right. Will have code for this in the next rev _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel