[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [xen master] tools/libxl: move libxenlight to tools/libs/light
commit 41aea82de2b581c61482aeddab151ecf3b1bca25 Author: Juergen Gross <jgross@xxxxxxxx> AuthorDate: Wed Sep 23 06:57:20 2020 +0200 Commit: Juergen Gross <jgross@xxxxxxxx> CommitDate: Thu Oct 1 13:26:09 2020 +0200 tools/libxl: move libxenlight to tools/libs/light Carve out all libxenlight related sources and move them to tools/libs/light in order to use the generic library build environment. The closely related sources for libxl-save-helper and the libxl test environment are being moved, too. Signed-off-by: Juergen Gross <jgross@xxxxxxxx> Acked-by: Wei Liu <wl@xxxxxxx> --- .gitignore | 31 +- tools/Rules.mk | 11 +- tools/configure | 2 +- tools/configure.ac | 2 +- tools/golang/xenlight/Makefile | 2 +- tools/libs/Makefile | 1 + tools/libs/light/CODING_STYLE | 330 ++ tools/libs/light/Makefile | 277 ++ tools/libs/light/check-libxl-api-rules | 23 + tools/libs/light/flexarray.c | 124 + tools/libs/light/flexarray.h | 54 + tools/libs/light/gentest.py | 374 +++ tools/libs/light/gentypes.py | 797 +++++ tools/libs/light/idl.py | 377 +++ tools/libs/light/idl.txt | 214 ++ tools/libs/light/include/libxl.h | 2732 +++++++++++++++ tools/libs/light/include/libxl_event.h | 632 ++++ tools/libs/light/include/libxl_json.h | 96 + tools/libs/light/include/libxl_utils.h | 194 ++ tools/libs/light/include/libxl_uuid.h | 80 + tools/libs/light/libxl.c | 831 +++++ tools/libs/light/libxl_9pfs.c | 52 + tools/libs/light/libxl_aoutils.c | 667 ++++ tools/libs/light/libxl_arch.h | 96 + tools/libs/light/libxl_arm.c | 1230 +++++++ tools/libs/light/libxl_arm.h | 48 + tools/libs/light/libxl_arm_acpi.c | 413 +++ tools/libs/light/libxl_arm_no_acpi.c | 40 + tools/libs/light/libxl_bootloader.c | 680 ++++ tools/libs/light/libxl_checkpoint_device.c | 278 ++ tools/libs/light/libxl_colo.h | 148 + tools/libs/light/libxl_colo_nic.c | 316 ++ tools/libs/light/libxl_colo_proxy.c | 438 +++ tools/libs/light/libxl_colo_qdisk.c | 230 ++ tools/libs/light/libxl_colo_restore.c | 1093 ++++++ tools/libs/light/libxl_colo_save.c | 714 ++++ tools/libs/light/libxl_console.c | 802 +++++ tools/libs/light/libxl_convert_callout.c | 173 + tools/libs/light/libxl_cpuid.c | 628 ++++ tools/libs/light/libxl_cpupool.c | 452 +++ tools/libs/light/libxl_create.c | 2310 +++++++++++++ tools/libs/light/libxl_device.c | 2090 ++++++++++++ tools/libs/light/libxl_disk.c | 1390 ++++++++ tools/libs/light/libxl_dm.c | 3795 +++++++++++++++++++++ tools/libs/light/libxl_dom.c | 1469 ++++++++ tools/libs/light/libxl_dom_save.c | 564 ++++ tools/libs/light/libxl_dom_suspend.c | 677 ++++ tools/libs/light/libxl_domain.c | 2462 ++++++++++++++ tools/libs/light/libxl_event.c | 2467 ++++++++++++++ tools/libs/light/libxl_exec.c | 473 +++ tools/libs/light/libxl_flask.c | 79 + tools/libs/light/libxl_fork.c | 734 ++++ tools/libs/light/libxl_freebsd.c | 252 ++ tools/libs/light/libxl_genid.c | 117 + tools/libs/light/libxl_internal.c | 806 +++++ tools/libs/light/libxl_internal.h | 4859 +++++++++++++++++++++++++++ tools/libs/light/libxl_json.c | 1191 +++++++ tools/libs/light/libxl_libfdt_compat.c | 94 + tools/libs/light/libxl_libfdt_compat.h | 90 + tools/libs/light/libxl_linux.c | 375 +++ tools/libs/light/libxl_mem.c | 651 ++++ tools/libs/light/libxl_netbsd.c | 131 + tools/libs/light/libxl_netbuffer.c | 532 +++ tools/libs/light/libxl_nic.c | 544 +++ tools/libs/light/libxl_no_colo.c | 62 + tools/libs/light/libxl_no_convert_callout.c | 35 + tools/libs/light/libxl_nocpuid.c | 67 + tools/libs/light/libxl_nonetbuffer.c | 54 + tools/libs/light/libxl_numa.c | 535 +++ tools/libs/light/libxl_osdeps.h | 130 + tools/libs/light/libxl_paths.c | 71 + tools/libs/light/libxl_pci.c | 2508 ++++++++++++++ tools/libs/light/libxl_psr.c | 562 ++++ tools/libs/light/libxl_pvcalls.c | 37 + tools/libs/light/libxl_qmp.c | 1934 +++++++++++ tools/libs/light/libxl_remus.c | 425 +++ tools/libs/light/libxl_remus_disk_drbd.c | 232 ++ tools/libs/light/libxl_save_callout.c | 430 +++ tools/libs/light/libxl_save_helper.c | 303 ++ tools/libs/light/libxl_save_msgs_gen.pl | 396 +++ tools/libs/light/libxl_sched.c | 986 ++++++ tools/libs/light/libxl_sr_stream_format.h | 69 + tools/libs/light/libxl_stream_read.c | 977 ++++++ tools/libs/light/libxl_stream_write.c | 727 ++++ tools/libs/light/libxl_test_fdevent.c | 79 + tools/libs/light/libxl_test_fdevent.h | 12 + tools/libs/light/libxl_test_timedereg.c | 100 + tools/libs/light/libxl_test_timedereg.h | 9 + tools/libs/light/libxl_tmem.c | 76 + tools/libs/light/libxl_types.idl | 1224 +++++++ tools/libs/light/libxl_types_internal.idl | 57 + tools/libs/light/libxl_usb.c | 2158 ++++++++++++ tools/libs/light/libxl_utils.c | 1272 +++++++ tools/libs/light/libxl_uuid.c | 163 + tools/libs/light/libxl_vdispl.c | 222 ++ tools/libs/light/libxl_vkb.c | 353 ++ tools/libs/light/libxl_vnuma.c | 327 ++ tools/libs/light/libxl_vsnd.c | 686 ++++ tools/libs/light/libxl_vtpm.c | 248 ++ tools/libs/light/libxl_x86.c | 852 +++++ tools/libs/light/libxl_x86_acpi.c | 252 ++ tools/libs/light/libxl_x86_acpi.h | 35 + tools/libs/light/libxl_xshelp.c | 329 ++ tools/libs/light/osdeps.c | 76 + tools/libs/light/test_common.c | 57 + tools/libs/light/test_common.h | 29 + tools/libs/light/test_fdderegrace.c | 56 + tools/libs/light/test_timedereg.c | 11 + tools/libs/uselibs.mk | 2 + tools/libxl/Makefile | 278 +- tools/libxl/check-libxl-api-rules | 23 - tools/libxl/flexarray.c | 124 - tools/libxl/flexarray.h | 54 - tools/libxl/gentest.py | 374 --- tools/libxl/gentypes.py | 797 ----- tools/libxl/idl.py | 377 --- tools/libxl/idl.txt | 214 -- tools/libxl/libxl.c | 831 ----- tools/libxl/libxl.h | 2732 --------------- tools/libxl/libxl_9pfs.c | 52 - tools/libxl/libxl_aoutils.c | 667 ---- tools/libxl/libxl_arch.h | 96 - tools/libxl/libxl_arm.c | 1230 ------- tools/libxl/libxl_arm.h | 48 - tools/libxl/libxl_arm_acpi.c | 413 --- tools/libxl/libxl_arm_no_acpi.c | 40 - tools/libxl/libxl_bootloader.c | 680 ---- tools/libxl/libxl_checkpoint_device.c | 278 -- tools/libxl/libxl_colo.h | 148 - tools/libxl/libxl_colo_nic.c | 316 -- tools/libxl/libxl_colo_proxy.c | 438 --- tools/libxl/libxl_colo_qdisk.c | 230 -- tools/libxl/libxl_colo_restore.c | 1093 ------ tools/libxl/libxl_colo_save.c | 714 ---- tools/libxl/libxl_console.c | 802 ----- tools/libxl/libxl_convert_callout.c | 173 - tools/libxl/libxl_cpuid.c | 628 ---- tools/libxl/libxl_cpupool.c | 452 --- tools/libxl/libxl_create.c | 2310 ------------- tools/libxl/libxl_device.c | 2090 ------------ tools/libxl/libxl_disk.c | 1390 -------- tools/libxl/libxl_dm.c | 3795 --------------------- tools/libxl/libxl_dom.c | 1469 -------- tools/libxl/libxl_dom_save.c | 564 ---- tools/libxl/libxl_dom_suspend.c | 677 ---- tools/libxl/libxl_domain.c | 2462 -------------- tools/libxl/libxl_event.c | 2467 -------------- tools/libxl/libxl_event.h | 632 ---- tools/libxl/libxl_exec.c | 473 --- tools/libxl/libxl_flask.c | 79 - tools/libxl/libxl_fork.c | 734 ---- tools/libxl/libxl_freebsd.c | 252 -- tools/libxl/libxl_genid.c | 117 - tools/libxl/libxl_internal.c | 806 ----- tools/libxl/libxl_internal.h | 4859 --------------------------- tools/libxl/libxl_json.c | 1191 ------- tools/libxl/libxl_json.h | 96 - tools/libxl/libxl_libfdt_compat.c | 94 - tools/libxl/libxl_libfdt_compat.h | 90 - tools/libxl/libxl_linux.c | 375 --- tools/libxl/libxl_mem.c | 651 ---- tools/libxl/libxl_netbsd.c | 131 - tools/libxl/libxl_netbuffer.c | 532 --- tools/libxl/libxl_nic.c | 544 --- tools/libxl/libxl_no_colo.c | 62 - tools/libxl/libxl_no_convert_callout.c | 35 - tools/libxl/libxl_nocpuid.c | 67 - tools/libxl/libxl_nonetbuffer.c | 54 - tools/libxl/libxl_numa.c | 535 --- tools/libxl/libxl_osdeps.h | 130 - tools/libxl/libxl_paths.c | 71 - tools/libxl/libxl_pci.c | 2508 -------------- tools/libxl/libxl_psr.c | 562 ---- tools/libxl/libxl_pvcalls.c | 37 - tools/libxl/libxl_qmp.c | 1934 ----------- tools/libxl/libxl_remus.c | 425 --- tools/libxl/libxl_remus_disk_drbd.c | 232 -- tools/libxl/libxl_save_callout.c | 430 --- tools/libxl/libxl_save_helper.c | 303 -- tools/libxl/libxl_save_msgs_gen.pl | 396 --- tools/libxl/libxl_sched.c | 986 ------ tools/libxl/libxl_sr_stream_format.h | 69 - tools/libxl/libxl_stream_read.c | 977 ------ tools/libxl/libxl_stream_write.c | 727 ---- tools/libxl/libxl_test_fdevent.c | 79 - tools/libxl/libxl_test_fdevent.h | 12 - tools/libxl/libxl_test_timedereg.c | 100 - tools/libxl/libxl_test_timedereg.h | 9 - tools/libxl/libxl_tmem.c | 76 - tools/libxl/libxl_types.idl | 1224 ------- tools/libxl/libxl_types_internal.idl | 57 - tools/libxl/libxl_usb.c | 2158 ------------ tools/libxl/libxl_utils.c | 1272 ------- tools/libxl/libxl_utils.h | 194 -- tools/libxl/libxl_uuid.c | 163 - tools/libxl/libxl_uuid.h | 80 - tools/libxl/libxl_vdispl.c | 222 -- tools/libxl/libxl_vkb.c | 353 -- tools/libxl/libxl_vnuma.c | 327 -- tools/libxl/libxl_vsnd.c | 686 ---- tools/libxl/libxl_vtpm.c | 248 -- tools/libxl/libxl_x86.c | 852 ----- tools/libxl/libxl_x86_acpi.c | 252 -- tools/libxl/libxl_x86_acpi.h | 35 - tools/libxl/libxl_xshelp.c | 329 -- tools/libxl/osdeps.c | 76 - tools/libxl/test_common.c | 57 - tools/libxl/test_common.h | 29 - tools/libxl/test_fdderegrace.c | 56 - tools/libxl/test_timedereg.c | 11 - tools/ocaml/libs/xl/Makefile | 8 +- 211 files changed, 63046 insertions(+), 62700 deletions(-) diff --git a/.gitignore b/.gitignore index 5e8c47e2db..f30550255f 100644 --- a/.gitignore +++ b/.gitignore @@ -128,6 +128,22 @@ tools/libs/guest/xc_core.h tools/libs/guest/xc_core_arm.h tools/libs/guest/xc_core_x86.h tools/libs/guest/xc_private.h +tools/libs/light/_*.[ch] +tools/libs/light/*.pyc +tools/libs/light/_libxl.api-for-check +tools/libs/light/*.api-ok +tools/libs/light/libxenlight.map +tools/libs/light/libxl-save-helper +tools/libs/light/dsdt* +tools/libs/light/mk_dsdt +tools/libs/light/ssdt* +tools/libs/light/testidl +tools/libs/light/testidl.c +tools/libs/light/test_timedereg +tools/libs/light/test_fdderegrace +tools/libs/light/tmp.* +tools/libs/light/xenlight.pc +tools/libs/light/include/_*.h tools/libs/stat/_paths.h tools/libs/stat/headers.chk tools/libs/stat/libxenstat.map @@ -216,16 +232,8 @@ tools/include/xen/* tools/include/xen-xsm/* tools/include/xen-foreign/*.(c|h|size) tools/include/xen-foreign/checker -tools/libxl/_libxl.api-for-check -tools/libxl/*.api-ok tools/libxl/*.pc -tools/libxl/dsdt* tools/libxl/libxlu_cfg_y.output -tools/libxl/mk_dsdt -tools/libxl/ssdt* -tools/libxl/testenum -tools/libxl/testenum.c -tools/libxl/tmp.* tools/misc/cpuperf/cpuperf-perfcntr tools/misc/cpuperf/cpuperf-xen tools/misc/xc_shadow @@ -380,13 +388,6 @@ tools/include/xen-foreign/arm64.h tools/misc/xen-hptool tools/misc/xen-mfndump tools/libs/toolcore/include/_*.h -tools/libxl/_*.[ch] -tools/libxl/testidl -tools/libxl/testidl.c -tools/libxl/*.pyc -tools/libxl/libxl-save-helper -tools/libxl/test_timedereg -tools/libxl/test_fdderegrace tools/firmware/etherboot/eb-roms.h tools/firmware/etherboot/gpxe-git-snapshot.tar.gz tools/misc/xenhypfs diff --git a/tools/Rules.mk b/tools/Rules.mk index a71abb2e4f..a68dbb9de8 100644 --- a/tools/Rules.mk +++ b/tools/Rules.mk @@ -15,9 +15,7 @@ XEN_INCLUDE = $(XEN_ROOT)/tools/include include $(XEN_ROOT)/tools/libs/uselibs.mk -XEN_libxenlight = $(XEN_ROOT)/tools/libxl -# Currently libxlutil lives in the same directory as libxenlight -XEN_libxlutil = $(XEN_libxenlight) +XEN_libxlutil = $(XEN_ROOT)/tools/libxl CFLAGS_xeninclude = -I$(XEN_INCLUDE) @@ -107,6 +105,8 @@ ifeq ($(CONFIG_Linux),y) LDLIBS_libxenstore += -ldl endif +CFLAGS_libxenlight += $(CFLAGS_libxenctrl) + ifeq ($(debug),y) # Disable optimizations CFLAGS += -O0 -fno-omit-frame-pointer @@ -116,11 +116,6 @@ else CFLAGS += -O2 -fomit-frame-pointer endif -CFLAGS_libxenlight = -I$(XEN_libxenlight) $(CFLAGS_libxenctrl) $(CFLAGS_xeninclude) -SHDEPS_libxenlight = $(SHLIB_libxenctrl) $(SHLIB_libxenstore) $(SHLIB_libxenhypfs) $(SHLIB_libxenguest) -LDLIBS_libxenlight = $(SHDEPS_libxenlight) $(XEN_libxenlight)/libxenlight$(libextension) -SHLIB_libxenlight = $(SHDEPS_libxenlight) -Wl,-rpath-link=$(XEN_libxenlight) - CFLAGS_libxlutil = -I$(XEN_libxlutil) SHDEPS_libxlutil = $(SHLIB_libxenlight) LDLIBS_libxlutil = $(SHDEPS_libxlutil) $(XEN_libxlutil)/libxlutil$(libextension) diff --git a/tools/configure b/tools/configure index edcdcf4f73..8a708e9baa 100755 --- a/tools/configure +++ b/tools/configure @@ -585,7 +585,7 @@ PACKAGE_STRING='Xen Hypervisor Tools 4.15' PACKAGE_BUGREPORT='xen-devel@xxxxxxxxxxxxx' PACKAGE_URL='https://www.xen.org/' -ac_unique_file="libxl/libxl.c" +ac_unique_file="libs/light/libxl.c" # Factoring default headers for most tests. ac_includes_default="\ #include <stdio.h> diff --git a/tools/configure.ac b/tools/configure.ac index 6614a4f130..ee8ba5ff24 100644 --- a/tools/configure.ac +++ b/tools/configure.ac @@ -4,7 +4,7 @@ AC_PREREQ([2.67]) AC_INIT([Xen Hypervisor Tools], m4_esyscmd([../version.sh ../xen/Makefile]), [xen-devel@xxxxxxxxxxxxx], [xen], [https://www.xen.org/]) -AC_CONFIG_SRCDIR([libxl/libxl.c]) +AC_CONFIG_SRCDIR([libs/light/libxl.c]) AC_CONFIG_FILES([ ../config/Tools.mk hotplug/FreeBSD/rc.d/xencommons diff --git a/tools/golang/xenlight/Makefile b/tools/golang/xenlight/Makefile index b17095e64b..fd8e4893db 100644 --- a/tools/golang/xenlight/Makefile +++ b/tools/golang/xenlight/Makefile @@ -8,7 +8,7 @@ GOXL_INSTALL_DIR = $(GOCODE_DIR)/src/$(XEN_GOCODE_URL)/xenlight/ GO ?= go -LIBXL_SRC_DIR = ../../libxl +LIBXL_SRC_DIR = $(XEN_ROOT)/tools/libs/light .PHONY: all all: build diff --git a/tools/libs/Makefile b/tools/libs/Makefile index e8fcd59214..c41455c604 100644 --- a/tools/libs/Makefile +++ b/tools/libs/Makefile @@ -15,6 +15,7 @@ SUBDIRS-y += hypfs SUBDIRS-y += store SUBDIRS-y += stat SUBDIRS-$(CONFIG_Linux) += vchan +SUBDIRS-y += light ifeq ($(CONFIG_RUMP),y) SUBDIRS-y := toolcore diff --git a/tools/libs/light/CODING_STYLE b/tools/libs/light/CODING_STYLE new file mode 100644 index 0000000000..3d572f6925 --- /dev/null +++ b/tools/libs/light/CODING_STYLE @@ -0,0 +1,330 @@ +LIBXENLIGHT CODING STYLE +======================== + + +AN APOLOGY AND WARNING +---------------------- + +Much of the code in libxl does not yet follow this coding style +document in every respect. However, new code is expected to conform. + +Patches to improve the style of existing code are welcome. Please +separate these out from functional changes. + +If it is not feasible to conform fully to the style while patching old +code, without doing substantial style reengineering first, we may +accept patches which contain nonconformant elements, provided that +they don't make the coding style problem worse overall. + +In this case, the new code should conform to the prevailing style in +the area being touched. + + +MEMORY ALLOCATION +----------------- + +Memory allocation for libxl-internal purposes should normally be done +with the provided gc mechanisms; there is then no need to free. See +"libxl memory management" in libxl.h. + + +CONVENTIONAL VARIABLE NAMES +--------------------------- + +The following local variable names should be used where applicable: + + int rc; /* a libxl error code - and not anything else */ + int r; /* the return value from a system call (or libxc call) */ + bool ok; /* the success return value from a boolean function */ + + uint32_t domid; + libxl__gc *gc; + libxl__egc *egc; + libxl__ao *ao; + + libxl_foo_bar_state *fbs; /* local variable */ + libxl_foo_bar_state foo_bar; /* inside another state struct */ + + +CONVENIENCE MACROS +------------------ + +There are a number of convenience macros which shorten the program and +avoid opportunity for mistakes. In some cases non-use of the macros +produces functional bugs or incorrect error handling. Use the macros +whenever they are applicable. For example: + + Usually, don't use: Instead, use (see libxl_internal.h): + libxl__log[v] LOG, LOGE, LOGEV + libxl__sprintf GCSPRINTF + libxl__*alloc et al. GCNEW, GCNEW_ARRAY, GCREALLOC_ARRAY + isalnum etc. directly CTYPE + libxl__ctx_[un]lock CTX_LOCK, CTX_UNLOCK + gc=...; ao=...; EGC_GC, AO_GC, STATE_AO_GC + explicit gc creation GC_INIT, GC_FREE + memset(..,0,sizeof..) FILLZERO + +Instead of malloc et al one should (as an exception to the above) use +libxl__{zalloc,calloc,realloc} etc but passing NOGC. + +ERROR HANDLING +-------------- + +Unless, there are good reasons to do otherwise, the following error +handling and cleanup paradigm should be used: + + * All local variables referring to resources which might need + cleaning up are declared at the top of the function, and + initialised to a sentinel value indicating "nothing allocated". + For example, + libxl_evgen_disk_eject *evg = NULL; + int nullfd = -1; + + * If the function is to return a libxl error value, `rc' is + used to contain the error code, but it is NOT initialised: + int rc; + + * There is only one error cleanup path out of the function. It + starts with a label `out:'. That error cleanup path checks for + each allocated resource and frees it iff necessary. It then + returns rc. For example, + out: + if (evg) libxl__evdisable_disk_eject(gc, evg); + if (nullfd >= 0) close(nullfd); + return rc; + + * Function calls which might fail (ie most function calls) are + handled by putting the return/status value into a variable, and + then checking it in a separate statement: + char *dompath = libxl__xs_get_dompath(gc, bl->domid); + if (!dompath) { rc = ERROR_FAIL; goto out; } + + * If a resource is freed in the main body of the function (for + example, in a loop), the corresponding variable has to be reset to + the sentinel at the point where it's freed. + +Whether to use the `out' path for successful returns as well as error +returns is a matter of taste and convenience for the specific +function. Not reusing the out path is fine if the duplicated function +exit code is only `CTX_UNLOCK; GC_FREE;' (or similar). + +If you reuse the `out' path for successful returns, there may be +resources which are to be returned to the caller rather than freed. +In that case you have to reset the local variable to `nothing here', +to avoid the resource being freed on the out path. That resetting +should be done immediately after the resource value is stored at the +applicable _r function parameter (or equivalent). Do not test `rc' in +the out section, to discover whether to free things. + +The uses of the single-line formatting in the examples above are +permitted exceptions to the usual libxl code formatting rules. + + + +IDEMPOTENT DATA STRUCTURE CONSTRUCTION/DESTRUCTION +-------------------------------------------------- + +Nontrivial data structures (in structs) should come with an idempotent +_dispose function, which must free all resources associated with the +data structure (but not free the struct itself). + +Such a struct should also come with an _init function which +initialises the struct so that _dispose is a no-op. + + +ASYNCHRONOUS/LONG-RUNNING OPERATIONS +------------------------------------ + +All long-running operations in libxl need to use the asynchronous +operation machinery. Consult the programmer documentation in +libxl_internal.h for details - search for "Machinery for asynchronous +operations". + +The code for asynchronous operations should be laid out in +chronological order. That is, where there is a chain of callback +functions, each subsequent function should be, textually, the next +function in the file. This will normally involve predeclaring the +callback functions. Synchronous helper functions should be separated +out into a section preceding the main callback chain. + +Control flow arrangements in asynchronous operations should be made as +simple as possible, because it can otherwise be very hard to see +through the tangle. + + +When inventing a new sub-operation in asynchronous code, consider +whether to structure it formally as a sub-operation with its own state +structure. (See, for example, libxl__datacopier_*.) + +An ao-suboperation state structure should contain, in this order: + * fields that the caller must fill in, and which are, + effectively, the parameters to the operation, including: + - libxl__ao *ao + - the callback function pointer(s), which + should be named callback or callback_*. + * shared information fields or ones used for returning information + to the calling operation + * private fields +These sections should be clearly demarcated by comments. + +An asynchronous operation should normally have an idempotent stop or +cancel function. It should normally also have an _init function for +its state struct, which arranges that the stop is a no-op. + +The permitted order of calls into your ao operation's methods must be +documented in comments, if it is nontrivial. + + +When using an ao sub-operation, you should normally: + * Physically include the sub-operation state struct in your + own state struct; + * Use CONTAINER_OF to find your own state struct at the start of + your implementations of the sub-operation callback functions; + * Unconditionally initialise the sub-operation's struct (with its + _init method) in your own _init method. + * Unconditionally cancel or destroy the sub-operation in your own + cancel or destroy method. + + +FORMATTING AND NAMING +--------------------- + +Blatantly copied from qemu and linux with few modifications. + + +1. Whitespace + +Of course, the most important aspect in any coding style is whitespace. +Crusty old coders who have trouble spotting the glasses on their noses +can tell the difference between a tab and eight spaces from a distance +of approximately fifteen parsecs. Many a flamewar have been fought and +lost on this issue. + +Libxenlight indents are four spaces. Tabs are never used, except in +Makefiles where they have been irreversibly coded into the syntax. +Spaces of course are superior to tabs because: + + - You have just one way to specify whitespace, not two. Ambiguity breeds + mistakes. + - The confusion surrounding 'use tabs to indent, spaces to justify' is gone. + - Tab indents push your code to the right, making your screen seriously + unbalanced. + - Tabs will be rendered incorrectly on editors who are misconfigured not + to use tab stops of eight positions. + - Tabs are rendered badly in patches, causing off-by-one errors in almost + every line. + - It is the libxenlight coding style. + +Do not leave whitespace dangling off the ends of lines. + + +2. Line width + +Lines are limited to 75 characters. + +Rationale: + - Some people like to tile their 24" screens with a 6x4 matrix of 80x24 + xterms and use vi in all of them. The best way to punish them is to + let them keep doing it. + - In an 80 column terminal, some room needs to be left for > quoting + characters, +/- diff characters, and so on, in emails. + - Code and especially patches is much more readable if limited to a sane + line length. Eighty is traditional. + - It is the libxenlight coding style. + + +3. Naming + +C is a Spartan language, and so should your naming be. Unlike Modula-2 +and Pascal programmers, C programmers do not use cute names like +ThisVariableIsATemporaryCounter. A C programmer would call that +variable "tmp", which is much easier to write, and not the least more +difficult to understand. + +HOWEVER, while mixed-case names are frowned upon, descriptive names for +global variables are a must. To call a global function "foo" is a +shooting offense. + +GLOBAL variables (to be used only if you _really_ need them) need to +have descriptive names, as do global functions. If you have a function +that counts the number of active users, you should call that +"count_active_users()" or similar, you should _not_ call it "cntusr()". + +Encoding the type of a function into the name (so-called Hungarian +notation) is brain damaged - the compiler knows the types anyway and can +check those, and it only confuses the programmer. + +LOCAL variable names should be short, and to the point. If you have +some random integer loop counter, it should probably be called "i". +Calling it "loop_counter" is non-productive, if there is no chance of it +being mis-understood. Similarly, "tmp" can be just about any type of +variable that is used to hold a temporary value. + +Local variables used to store return values should have descriptive name +like "rc" or "ret". Following the same reasoning the label used as exit +path should be called "out". + +Function arguments which are used to return values to the caller +should be suffixed `_r' or `_out'. + +Variables, type names and function names are +lower_case_with_underscores. +Type names and function names use the prefix libxl__ when internal to +libxenlight and libxl_ when exported in libxl.h. +Xl should avoid using libxl_ and libxl__ as prefix for its own function +names. + +When wrapping standard library functions, use the prefix libxl_ to alert +readers that they are seeing a wrapped version; otherwise avoid this prefix. + +Typedefs are used to eliminate the redundant 'struct' keyword. +It is the libxenlight coding style. + + +4. Statements + +Don't put multiple statements on a single line. +Don't put multiple assignments on a single line either. +Error code paths with an if statement and a goto or a return on the same +line are allowed. Examples: + + if (rc) goto out; + if (rc < 0) return; + +Libxenlight coding style is super simple. Avoid tricky expressions. + + +5. Block structure + +Every indented statement is braced, but blocks that contain just one +statement may have the braces omitted. To avoid confusion, either all +the blocks in an if...else chain have braces, or none of them do. + +The opening brace is on the line that contains the control flow +statement that introduces the new block; the closing brace is on the +same line as the else keyword, or on a line by itself if there is no +else keyword. Examples: + + if (a == 5) { + printf("a was 5.\n"); + } else if (a == 6) { + printf("a was 6.\n"); + } else { + printf("a was something else entirely.\n"); + } + + if (a == 5) + printf("a was 5.\n"); + +An exception is the opening brace for a function; for reasons of tradition +and clarity it comes on a line by itself: + + void a_function(void) + { + do_something(); + } + +Rationale: a consistent (except for functions...) bracing style reduces +ambiguity and avoids needless churn when lines are added or removed. +Furthermore, it is the libxenlight coding style. + diff --git a/tools/libs/light/Makefile b/tools/libs/light/Makefile new file mode 100644 index 0000000000..f58a3214e5 --- /dev/null +++ b/tools/libs/light/Makefile @@ -0,0 +1,277 @@ +XEN_ROOT = $(CURDIR)/../../.. +include $(XEN_ROOT)/tools/Rules.mk + +SRCS-y += osdeps.c +SRCS-y += libxl_paths.c +SRCS-y += libxl_bootloader.c +SRCS-y += flexarray.c +ifeq ($(CONFIG_LIBNL),y) +SRCS-y += libxl_netbuffer.c +else +SRCS-y += libxl_nonetbuffer.c +endif +ifeq ($(CONFIG_X86),y) +SRCS-y += libxl_convert_callout.c +else +SRCS-y += libxl_no_convert_callout.c +endif +SRCS-y += libxl_remus.c +SRCS-y += libxl_checkpoint_device.c +SRCS-y += libxl_remus_disk_drbd.c +ifeq ($(CONFIG_LIBNL),y) +SRCS-y += libxl_colo_restore.c +SRCS-y += libxl_colo_save.c +SRCS-y += libxl_colo_qdisk.c +SRCS-y += libxl_colo_proxy.c +SRCS-y += libxl_colo_nic.c +else +SRCS-y += libxl_no_colo.c +endif + +ACPI_PATH = $(XEN_ROOT)/tools/libacpi +DSDT_FILES-$(CONFIG_X86) = dsdt_pvh.c +ACPI_OBJS = $(patsubst %.c,%.o,$(DSDT_FILES-y)) build.o static_tables.o +ACPI_PIC_OBJS = $(patsubst %.o,%.opic,$(ACPI_OBJS)) +$(DSDT_FILES-y): acpi +vpath build.c $(ACPI_PATH)/ +vpath static_tables.c $(ACPI_PATH)/ + +.PHONY: acpi +acpi: + $(MAKE) -C $(ACPI_PATH) ACPI_BUILD_DIR=$(CURDIR) DSDT_FILES="$(DSDT_FILES-y)" + +SRCS-$(CONFIG_X86) += $(ACPI_OBJS:.o=.c) + +CFLAGS += -Wno-format-zero-length -Wmissing-declarations \ + -Wno-declaration-after-statement -Wformat-nonliteral +CFLAGS += -I. + +SRCS-$(CONFIG_X86) += libxl_cpuid.c +SRCS-$(CONFIG_X86) += libxl_x86.c +SRCS-$(CONFIG_X86) += libxl_psr.c +SRCS-$(CONFIG_X86) += libxl_x86_acpi.c +SRCS-$(CONFIG_ARM) += libxl_nocpuid.c +SRCS-$(CONFIG_ARM) += libxl_arm.c +SRCS-$(CONFIG_ARM) += libxl_libfdt_compat.c +ifeq ($(CONFIG_ARM_64),y) +DSDT_FILES-y = dsdt_anycpu_arm.c +SRCS-y += libxl_arm_acpi.c +SRCS-y += $(DSDT_FILES-y) +dsdt_anycpu_arm.c: + $(MAKE) -C $(ACPI_PATH) ACPI_BUILD_DIR=$(CURDIR) DSDT_FILES="$(DSDT_FILES-y)" +else +SRCS-$(CONFIG_ARM) += libxl_arm_no_acpi.c +endif + +SRCS-OS-$(CONFIG_NetBSD) = libxl_netbsd.c +SRCS-OS-$(CONFIG_Linux) = libxl_linux.c +SRCS-OS-$(CONFIG_FreeBSD) = libxl_freebsd.c +ifeq ($(SRCS-OS-y),) +$(error Your Operating System is not supported by libxenlight, \ +please check libxl_linux.c and libxl_netbsd.c to see how to get it ported) +endif +SRCS-y += $(SRCS-OS-y) + +SRCS-y += libxl.c +SRCS-y += libxl_create.c +SRCS-y += libxl_dm.c +SRCS-y += libxl_pci.c +SRCS-y += libxl_dom.c +SRCS-y += libxl_exec.c +SRCS-y += libxl_xshelp.c +SRCS-y += libxl_device.c +SRCS-y += libxl_internal.c +SRCS-y += libxl_utils.c +SRCS-y += libxl_uuid.c +SRCS-y += libxl_json.c +SRCS-y += libxl_aoutils.c +SRCS-y += libxl_numa.c +SRCS-y += libxl_vnuma.c +SRCS-y += libxl_stream_read.c +SRCS-y += libxl_stream_write.c +SRCS-y += libxl_save_callout.c +SRCS-y += _libxl_save_msgs_callout.c +SRCS-y += libxl_qmp.c +SRCS-y += libxl_event.c +SRCS-y += libxl_fork.c +SRCS-y += libxl_dom_suspend.c +SRCS-y += libxl_dom_save.c +SRCS-y += libxl_usb.c +SRCS-y += libxl_vtpm.c +SRCS-y += libxl_nic.c +SRCS-y += libxl_disk.c +SRCS-y += libxl_console.c +SRCS-y += libxl_cpupool.c +SRCS-y += libxl_mem.c +SRCS-y += libxl_sched.c +SRCS-y += libxl_tmem.c +SRCS-y += libxl_9pfs.c +SRCS-y += libxl_domain.c +SRCS-y += libxl_vdispl.c +SRCS-y += libxl_pvcalls.c +SRCS-y += libxl_vsnd.c +SRCS-y += libxl_vkb.c +SRCS-y += libxl_genid.c +SRCS-y += _libxl_types.c +SRCS-y += libxl_flask.c +SRCS-y += _libxl_types_internal.c + +ifeq ($(CONFIG_LIBNL),y) +CFLAGS_LIBXL += $(LIBNL3_CFLAGS) +endif +CFLAGS_LIBXL += -Wshadow +ifeq ($(debug),y) +CFLAGS_LIBXL += -DCONFIG_DEBUG +endif + +CFLAGS += $(PTHREAD_CFLAGS) +LDFLAGS += $(PTHREAD_LDFLAGS) + +LIBXL_TESTS += timedereg +LIBXL_TESTS_PROGS = $(LIBXL_TESTS) fdderegrace +LIBXL_TESTS_INSIDE = $(LIBXL_TESTS) fdevent + +# Each entry FOO in LIBXL_TESTS has two main .c files: +# libxl_test_FOO.c "inside libxl" code to support the test case +# test_FOO.c "outside libxl" code to exercise the test case +# Conventionally there will also be: +# libxl_test_FOO.h interface between the "inside" and "outside" parts +# The "inside libxl" file is compiled exactly like a piece of libxl, and the +# "outside libxl" file is compiled exactly like a piece of application +# code. They must share information via explicit libxl entrypoints. +# Unlike proper parts of libxl, it is permissible for libxl_test_FOO.c +# to use private global variables for its state. Note that all the +# "inside" parts are compiled into a single test library, so their +# symbol names must be unique. +# +# To run these tests, either use LD_PRELOAD to get libxenlight_test.so +# loaded, or rename it to libxenlight.so so it is the target of the +# appropriate symlinks. + +LIBXL_TEST_OBJS += $(foreach t, $(LIBXL_TESTS_INSIDE),libxl_test_$t.opic) +TEST_PROG_OBJS += $(foreach t, $(LIBXL_TESTS_PROGS),test_$t.o) test_common.o +TEST_PROGS += $(foreach t, $(LIBXL_TESTS_PROGS),test_$t) + +AUTOINCS = _libxl_list.h _paths.h _libxl_save_msgs_callout.h _libxl_save_msgs_helper.h +AUTOSRCS = _libxl_save_msgs_callout.c _libxl_save_msgs_helper.c + +CLIENTS = testidl libxl-save-helper + +SAVE_HELPER_OBJS = libxl_save_helper.o _libxl_save_msgs_helper.o + +LIBHEADER := libxl.h libxl_event.h libxl_json.h _libxl_types.h _libxl_types_json.h _libxl_list.h libxl_utils.h libxl_uuid.h + +NO_HEADERS_CHK := y + +include $(XEN_ROOT)/tools/libs/libs.mk + +$(PKG_CONFIG_LOCAL): PKG_CONFIG_INCDIR = $(CURDIR) +$(PKG_CONFIG_LOCAL): PKG_CONFIG_CFLAGS_LOCAL = $(CFLAGS_xeninclude) + +LDUSELIBS-y += $(PTYFUNCS_LIBS) +LDUSELIBS-$(CONFIG_LIBNL) += $(LIBNL3_LIBS) +LDUSELIBS-$(CONFIG_Linux) += -luuid +LDUSELIBS-$(CONFIG_Linux) += -lrt +LDUSELIBS-$(CONFIG_ARM) += -lfdt +LDUSELIBS-y += $(PTHREAD_LIBS) +LDUSELIBS-y += -lyajl +LDUSELIBS += $(LDUSELIBS-y) + +$(LIB_OBJS) $(PIC_OBJS) $(LIBXL_TEST_OBJS): CFLAGS += $(CFLAGS_LIBXL) -include $(XEN_ROOT)/tools/config.h +$(ACPI_OBJS) $(ACPI_PIC_OBJS): CFLAGS += -I. -DLIBACPI_STDUTILS=\"$(CURDIR)/libxl_x86_acpi.h\" +$(TEST_PROG_OBJS) _libxl.api-for-check: CFLAGS += $(CFLAGS_libxentoollog) $(CFLAGS_libxentoolcore) +libxl_dom.o libxl_dom.opic: CFLAGS += -I$(XEN_ROOT)/tools # include libacpi/x86.h +libxl_x86_acpi.o libxl_x86_acpi.opic: CFLAGS += -I$(XEN_ROOT)/tools +$(SAVE_HELPER_OBJS): CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenevtchn) $(CFLAGS_libxenguest) + +testidl.o: CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenlight) +testidl.c: libxl_types.idl gentest.py include/libxl.h $(AUTOINCS) + $(PYTHON) gentest.py libxl_types.idl testidl.c.new + mv testidl.c.new testidl.c + +build: $(CLIENTS) $(TEST_PROGS) $(AUTOSRCS) $(AUTOINCS) + +$(LIB_OBJS) $(PIC_OBJS) $(SAVE_HELPER_OBJS) $(LIBXL_TEST_OBJS) $(TEST_PROG_OBJS): $(AUTOINCS) libxl.api-ok + +genpath-target = $(call buildmakevars2header,_paths.h) +$(eval $(genpath-target)) + +libxl.api-ok: check-libxl-api-rules _libxl.api-for-check + $(PERL) $^ + touch $@ + +_%.api-for-check: include/%.h $(AUTOINCS) + $(CC) $(CPPFLAGS) $(CFLAGS) $(CFLAGS_$*.o) -c -E $< $(APPEND_CFLAGS) \ + -DLIBXL_EXTERNAL_CALLERS_ONLY=LIBXL_EXTERNAL_CALLERS_ONLY \ + >$@.new + mv -f $@.new $@ + +_libxl_list.h: $(XEN_INCLUDE)/xen-external/bsd-sys-queue-h-seddery $(XEN_INCLUDE)/xen-external/bsd-sys-queue.h + $(PERL) $^ --prefix=libxl >$@.new + $(call move-if-changed,$@.new,$@) + +_libxl_save_msgs_helper.c _libxl_save_msgs_callout.c \ +_libxl_save_msgs_helper.h _libxl_save_msgs_callout.h: \ + libxl_save_msgs_gen.pl + $(PERL) -w $< $@ >$@.new + $(call move-if-changed,$@.new,$@) + +include/libxl.h: _libxl_types.h _libxl_list.h +include/libxl_json.h: _libxl_types_json.h +libxl_internal.h: _libxl_types_internal.h _libxl_types_private.h _libxl_types_internal_private.h _paths.h +libxl_internal_json.h: _libxl_types_internal_json.h +xl.h: _paths.h + +$(LIB_OBJS) $(PIC_OBJS) $(LIBXL_TEST_OBJS) $(TEST_PROG_OBJS) $(SAVE_HELPER_OBJS): include/libxl.h +$(LIB_OBJS) $(PIC_OBJS) $(LIBXL_TEST_OBJS): libxl_internal.h + +_libxl_type%.h _libxl_type%_json.h _libxl_type%_private.h _libxl_type%.c: libxl_type%.idl gentypes.py idl.py + $(eval stem = $(notdir $*)) + $(PYTHON) gentypes.py libxl_type$(stem).idl __libxl_type$(stem).h __libxl_type$(stem)_private.h \ + __libxl_type$(stem)_json.h __libxl_type$(stem).c + $(call move-if-changed,__libxl_type$(stem).h,_libxl_type$(stem).h) + $(call move-if-changed,__libxl_type$(stem)_private.h,_libxl_type$(stem)_private.h) + $(call move-if-changed,__libxl_type$(stem)_json.h,_libxl_type$(stem)_json.h) + $(call move-if-changed,__libxl_type$(stem).c,_libxl_type$(stem).c) + +include/_%.h: _%.h + cp $< $@ + +libxenlight_test.so: $(PIC_OBJS) $(LIBXL_TEST_OBJS) + $(CC) $(LDFLAGS) -Wl,$(SONAME_LDFLAG) -Wl,libxenlight.so.$(MAJOR) $(SHLIB_LDFLAGS) -o $@ $^ $(LDUSELIBS) $(APPEND_LDFLAGS) + +test_%: test_%.o test_common.o libxenlight_test.so + $(CC) $(LDFLAGS) -o $@ $^ $(filter-out %libxenlight.so, $(LDLIBS_libxenlight)) $(LDLIBS_libxentoollog) $(LDLIBS_libxentoolcore) -lyajl $(APPEND_LDFLAGS) + +libxl-save-helper: $(SAVE_HELPER_OBJS) libxenlight.so + $(CC) $(LDFLAGS) -o $@ $(SAVE_HELPER_OBJS) $(LDLIBS_libxentoollog) $(LDLIBS_libxenctrl) $(LDLIBS_libxenguest) $(LDLIBS_libxentoolcore) $(APPEND_LDFLAGS) + +testidl: testidl.o libxenlight.so + $(CC) $(LDFLAGS) -o $@ testidl.o $(LDLIBS_libxenlight) $(LDLIBS_libxentoollog) $(LDLIBS_libxentoolcore) $(APPEND_LDFLAGS) + +install: installlocal $(LIBHEADERS) + +.PHONY: installlocal +installlocal: libxl-save-helper + $(INSTALL_DIR) $(DESTDIR)$(LIBEXEC_BIN) + $(INSTALL_PROG) libxl-save-helper $(DESTDIR)$(LIBEXEC_BIN) + +uninstall: uninstalllocal + +.PHONY: uninstalllocal +uninstalllocal: + rm -f $(DESTDIR)$(LIBEXEC_BIN)/libxl-save-helper + +clean: cleanlocal + +.PHONY: cleanlocal +cleanlocal: + $(RM) -f _*.h *.o $(CLIENTS) + $(RM) -f _*.c *.pyc _paths.*.tmp _*.api-for-check + $(RM) -f testidl.c.new testidl.c *.api-ok + $(RM) -f $(TEST_PROGS) + $(RM) -rf __pycache__ + $(RM) -f include/_*.h + $(RM) -f libxenlight.map + $(RM) -f $(AUTOSRCS) $(AUTOINCS) + $(MAKE) -C $(ACPI_PATH) ACPI_BUILD_DIR=$(CURDIR) clean diff --git a/tools/libs/light/check-libxl-api-rules b/tools/libs/light/check-libxl-api-rules new file mode 100755 index 0000000000..18ff39ca5f --- /dev/null +++ b/tools/libs/light/check-libxl-api-rules @@ -0,0 +1,23 @@ +#!/usr/bin/perl -w +use strict; +our $needed=0; +our $speclineoffset=0; +our $specfile; +while (<>) { + if (m/^\# (\d+) \"(.*)\"$/) { + $speclineoffset = $1 - $. -1; + $specfile = $2; + } + my $file = defined($specfile) ? $specfile : $ARGV; + my $line = $speclineoffset + $.; + if (m/libxl_asyncop_how[^;]/) { + $needed=1; + } + if (m/LIBXL_EXTERNAL_CALLERS_ONLY/) { + $needed=0; + } + next unless $needed; + if (m/\;/) { + die "$file:$line:missing LIBXL_EXTERNAL_CALLERS_ONLY"; + } +} diff --git a/tools/libs/light/flexarray.c b/tools/libs/light/flexarray.c new file mode 100644 index 0000000000..fe40e762e4 --- /dev/null +++ b/tools/libs/light/flexarray.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2009 Citrix Ltd. + * Author Vincent Hanquez <vincent.hanquez@xxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; version 2.1 only. with the special + * exception on linking described in file LICENSE. + * + * This program 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. + */ + +#include "libxl_internal.h" +#include <stdarg.h> + +/* + * It is safe to store gc in the struct because: + * - If it an actual gc, then the flexarray should not be used after the gc + * have been freed. + * - If it is a NOGC, then this point to a structure embedded in libxl_ctx, + * therefore will survive across several libxl calls. + */ + +flexarray_t *flexarray_make(libxl__gc *gc, int size, int autogrow) +{ + flexarray_t *array; + + GCNEW(array); + array->size = size; + array->autogrow = autogrow; + array->count = 0; + array->gc = gc; + GCNEW_ARRAY(array->data, size); + + return array; +} + +void flexarray_free(flexarray_t *array) +{ + assert(!libxl__gc_is_real(array->gc)); + free(array->data); + free(array); +} + +void flexarray_grow(flexarray_t *array, int extents) +{ + int newsize; + libxl__gc *gc = array->gc; + + newsize = array->size + extents; + GCREALLOC_ARRAY(array->data, newsize); + array->size += extents; +} + +int flexarray_set(flexarray_t *array, unsigned int idx, void *ptr) +{ + if (idx >= array->size) { + int newsize; + if (!array->autogrow) + return 1; + newsize = (array->size * 2 < idx) ? idx + 1 : array->size * 2; + flexarray_grow(array, newsize - array->size); + } + if ( idx + 1 > array->count ) + array->count = idx + 1; + array->data[idx] = ptr; + return 0; +} + +int flexarray_append(flexarray_t *array, void *ptr) +{ + return flexarray_set(array, array->count, ptr); +} + +int flexarray_append_pair(flexarray_t *array, void *ptr1, void *ptr2) +{ + int rc = flexarray_append(array, ptr1); + if (!rc) + rc = flexarray_append(array, ptr2); + return rc; +} + +int flexarray_vappend(flexarray_t *array, ...) +{ + va_list va; + void *ptr; + int ret; + + va_start(va, array); + for(ret = 0; (ptr = va_arg(va, void *)); ret++) { + if ( flexarray_append(array, ptr) ) + break; + } + va_end(va); + return ret; +} + +int flexarray_get(flexarray_t *array, int idx, void **ptr) +{ + if (idx >= array->size) + return 1; + *ptr = array->data[idx]; + return 0; +} + +void **flexarray_contents(flexarray_t *array) +{ + void **data; + data = array->data; + if (!libxl__gc_is_real(array->gc)) + free(array); + return data; +} + +/* + * Local variables: + * mode: C + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tools/libs/light/flexarray.h b/tools/libs/light/flexarray.h new file mode 100644 index 0000000000..a1e86475c4 --- /dev/null +++ b/tools/libs/light/flexarray.h @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2009 Citrix Ltd. + * Author Vincent Hanquez <vincent.hanquez@xxxxxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published + * by the Free Software Foundation; version 2.1 only. with the special + * exception on linking described in file LICENSE. + * + * This program 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. + */ + +#ifndef FLEXARRAY_H +#define FLEXARRAY_H + +struct libxl__gc; + +typedef struct flexarray { + int size; + int autogrow; + unsigned int count; + void **data; /* array of pointer */ + struct libxl__gc *gc; +} flexarray_t; + +/* + * NOGC can be used with flexarrays, but flexarray_free will need to be called + * to free the struct. The content of the flexarray will not be freed through + * flexarray_free. + */ +_hidden flexarray_t *flexarray_make(struct libxl__gc *gc_opt, + int size, int autogrow); +_hidden void flexarray_free(flexarray_t *array); +_hidden void flexarray_grow(flexarray_t *array, int extents); +_hidden int flexarray_set(flexarray_t *array, unsigned int index, void *ptr); +_hidden int flexarray_append(flexarray_t *array, void *ptr); +_hidden int flexarray_append_pair(flexarray_t *array, void *ptr1, void *ptr2); +_hidden int flexarray_vappend(flexarray_t *array, ...); +_hidden int flexarray_get(flexarray_t *array, int index, void **ptr); + +_hidden void **flexarray_contents(flexarray_t *array); + +#endif + +/* + * Local variables: + * mode: C + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/tools/libs/light/gentest.py b/tools/libs/light/gentest.py new file mode 100644 index 0000000000..1cc7eebc82 --- /dev/null +++ b/tools/libs/light/gentest.py @@ -0,0 +1,374 @@ +#!/usr/bin/python + +from __future__ import print_function + +import os +import sys +import re +import random + +import idl + +def randomize_char(c): + if random.random() < 0.5: + return str.lower(c) + else: + return str.upper(c) + +def randomize_case(s): + r = [randomize_char(c) for c in s] + return "".join(r) + +def randomize_enum(e): + return random.choice([v.name for v in e.values]) + +handcoded = ["libxl_bitmap", "libxl_key_value_list", + "libxl_cpuid_policy_list", "libxl_string_list"] + +def gen_rand_init(ty, v, indent = " ", parent = None): + s = "" + if isinstance(ty, idl.Enumeration): + s += "%s = %s;\n" % (ty.pass_arg(v, parent is None), randomize_enum(ty)) + elif isinstance(ty, idl.Array): + if parent is None: + raise Exception("Array type must have a parent") + s += "%s = test_rand(8);\n" % (parent + ty.lenvar.name) + s += "%s = calloc(%s, sizeof(*%s));\n" % \ + (v, parent + ty.lenvar.name, v) + s += "assert(%s);\n" % (v, ) + s += "{\n" + s += " int i;\n" + s += " for (i=0; i<%s; i++)\n" % (parent + ty.lenvar.name) + s += gen_rand_init(ty.elem_type, v+"[i]", + indent + " ", parent) + s += "}\n" + elif isinstance(ty, idl.KeyedUnion): + if parent is None: + raise Exception("KeyedUnion type must have a parent") + s += gen_rand_init(ty.keyvar.type, parent + ty.keyvar.name, indent, parent) + s += "switch (%s) {\n" % (parent + ty.keyvar.name) + for f in ty.fields: + (nparent,fexpr) = ty.member(v, f, parent is None) + s += "case %s:\n" % f.enumname + if f.type is not None: + s += gen_rand_init(f.type, fexpr, indent + " ", nparent) + s += " break;\n" + s += "}\n" + elif isinstance(ty, idl.Struct) \ + and (parent is None or ty.json_gen_fn is None): + for f in [f for f in ty.fields if not f.const]: + (nparent,fexpr) = ty.member(v, f, parent is None) + s += gen_rand_init(f.type, fexpr, "", nparent) + elif hasattr(ty, "rand_init") and ty.rand_init is not None: + s += "%s(%s);\n" % (ty.rand_init, + ty.pass_arg(v, isref=parent is None, + passby=idl.PASS_BY_REFERENCE)) + elif ty.typename in ["libxl_uuid", "libxl_mac", "libxl_hwcap", "libxl_ms_vm_genid"]: + s += "rand_bytes((uint8_t *)%s, sizeof(*%s));\n" % (v,v) + elif ty.typename in ["libxl_domid", "libxl_devid"] or isinstance(ty, idl.Number): + s += "%s = test_rand(sizeof(%s) * 8);\n" % \ + (ty.pass_arg(v, parent is None), + ty.pass_arg(v, parent is None)) + elif ty.typename in ["bool"]: + s += "%s = test_rand(2);\n" % v + elif ty.typename in ["libxl_defbool"]: + s += "libxl_defbool_set(%s, test_rand(2));\n" % v + elif ty.typename in ["char *"]: + s += "%s = rand_str();\n" % v + elif ty.private: + pass + elif ty.typename in handcoded: + raise Exception("Gen for handcoded %s" % ty.typename) + else: + raise Exception("Cannot randomly init %s" % ty.typename) + + if s != "": + s = indent + s + return s.replace("\n", "\n%s" % indent).rstrip(indent) + +if __name__ == '__main__': + if len(sys.argv) < 3: + print("Usage: gentest.py <idl> <implementation>", file=sys.stderr) + sys.exit(1) + + random.seed(os.getenv('LIBXL_TESTIDL_SEED')) + + (builtins,types) = idl.parse(sys.argv[1]) + + impl = sys.argv[2] + f = open(impl, "w") + f.write(""" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include "libxl.h" +#include "libxl_utils.h" + +static int test_rand(unsigned max) +{ + /* We are not using rand() for its cryptographic properies. */ + return rand() % max; +} + +static char *rand_str(void) +{ + int i, sz = test_rand(32); + char *s = malloc(sz+1); + assert(s); + for (i=0; i<sz; i++) + s[i] = 'a' + test_rand(26); + s[i] = '\\0'; + return s; +} + +static void rand_bytes(uint8_t *p, size_t sz) +{ + int i; + for (i=0; i<sz; i++) + p[i] = test_rand(256); +} + +static void libxl_bitmap_rand_init(libxl_bitmap *bitmap) +{ + int i; + bitmap->size = test_rand(16); + bitmap->map = calloc(bitmap->size, sizeof(*bitmap->map)); + assert(bitmap->map); + libxl_for_each_bit(i, *bitmap) { + if (test_rand(2)) + libxl_bitmap_set(bitmap, i); + else + libxl_bitmap_reset(bitmap, i); + } +} + +static void libxl_key_value_list_rand_init(libxl_key_value_list *pkvl) +{ + int i, nr_kvp = test_rand(16); + libxl_key_value_list kvl = calloc(nr_kvp+1, 2*sizeof(char *)); + assert(kvl); + + for (i = 0; i<2*nr_kvp; i += 2) { + kvl[i] = rand_str(); + if (test_rand(8)) + kvl[i+1] = rand_str(); + else + kvl[i+1] = NULL; + } + kvl[i] = NULL; + kvl[i+1] = NULL; + *pkvl = kvl; +} + +static void libxl_cpuid_policy_list_rand_init(libxl_cpuid_policy_list *pp) +{ + int i, nr_policies = test_rand(16); + struct { + const char *n; + int w; + } options[] = { + /* A random selection from libxl_cpuid_parse_config */ + {"maxleaf", 32}, + {"family", 8}, + {"model", 8}, + {"stepping", 4}, + {"localapicid", 8}, + {"proccount", 8}, + {"clflush", 8}, + {"brandid", 8}, + {"f16c", 1}, + {"avx", 1}, + {"osxsave", 1}, + {"xsave", 1}, + {"aes", 1}, + {"popcnt", 1}, + {"movbe", 1}, + {"x2apic", 1}, + {"sse4.2", 1}, + {"sse4.1", 1}, + {"dca", 1}, + {"pdcm", 1}, + {"procpkg", 6}, + }; + const int nr_options = sizeof(options)/sizeof(options[0]); + char buf[64]; + libxl_cpuid_policy_list p = NULL; + + for (i = 0; i < nr_policies; i++) { + int opt = test_rand(nr_options); + int val = test_rand(1<<options[opt].w); + snprintf(buf, 64, \"%s=%#x\", options[opt].n, val); + libxl_cpuid_parse_config(&p, buf); + } + *pp = p; +} + +static void libxl_string_list_rand_init(libxl_string_list *p) +{ + int i, nr = test_rand(16); + libxl_string_list l = calloc(nr+1, sizeof(char *)); + assert(l); + + for (i = 0; i<nr; i++) { + l[i] = rand_str(); + } + l[i] = NULL; + *p = l; +} +""") + for ty in builtins + types: + if isinstance(ty, idl.Number): continue + if ty.typename not in handcoded: + f.write("static void %s_rand_init(%s);\n" % \ + (ty.typename, + ty.make_arg("p", passby=idl.PASS_BY_REFERENCE))) + f.write("static void %s_rand_init(%s)\n" % \ + (ty.typename, + ty.make_arg("p", passby=idl.PASS_BY_REFERENCE))) + f.write("{\n") + f.write(gen_rand_init(ty, "p")) + f.write("}\n") + f.write("\n") + ty.rand_init = "%s_rand_init" % ty.typename + + f.write(""" +int main(int argc, char **argv) +{ +""") + + for ty in types: + f.write(" %s %s_val, %s_val_new;\n" % \ + (ty.typename, ty.typename, ty.typename)) + f.write(""" + int rc; + char *s, *new_s, *json_string; + xentoollog_logger_stdiostream *logger; + libxl_ctx *ctx; + + logger = xtl_createlogger_stdiostream(stderr, XTL_DETAIL, 0); + if (!logger) exit(1); + + if (libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, (xentoollog_logger*)logger)) { + fprintf(stderr, "cannot init xl context\\n"); + exit(1); + } +""") + f.write(" printf(\"Testing TYPE_to/from_json()\\n\");\n") + f.write(" printf(\"----------------------\\n\");\n") + f.write(" printf(\"\\n\");\n") + for ty in [t for t in types if t.json_gen_fn is not None]: + arg = ty.typename + "_val" + f.write(" %s_rand_init(%s);\n" % (ty.typename, \ + ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE))) + if not isinstance(ty, idl.Enumeration): + iters = random.randrange(1,10) + while iters > 0: + f.write(" %s_init(%s_new);\n" % (ty.typename, \ + ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE))) + iters -= 1 + f.write(" s = %s_to_json(ctx, %s);\n" % \ + (ty.typename, ty.pass_arg(arg, isref=False))) + f.write(" printf(\"%%s: %%s\\n\", \"%s\", s);\n" % ty.typename) + f.write(" if (s == NULL) abort();\n") + f.write(" rc = %s_from_json(ctx, &%s_val_new, s);\n" % \ + (ty.typename, ty.typename)) + f.write(" if (rc) abort();\n") + f.write(" new_s = %s_to_json(ctx, %s_new);\n" % \ + (ty.typename, ty.pass_arg(arg, isref=False))) + f.write(" if (new_s == NULL) abort();\n") + f.write(" if (strcmp(s, new_s)) {\n") + f.write(" printf(\"Huh? Regenerated string different from original string.\\n\");\n") + f.write(" printf(\"Regenerated string: %s\\n\", new_s);\n") + f.write(" abort();\n") + f.write(" }\n") + f.write(" free(s);\n") + f.write(" free(new_s);\n") + if ty.dispose_fn is not None: + iters = random.randrange(1,10) + f.write(" %s(&%s_val);\n" % (ty.dispose_fn, ty.typename)) + while iters > 0: + f.write(" %s(&%s_val_new);\n" % (ty.dispose_fn, ty.typename)) + iters -= 1 + f.write("\n") + + f.write(" printf(\"Testing TYPE_copy()\\n\");\n") + f.write(" printf(\"----------------------\\n\");\n") + f.write(" printf(\"\\n\");\n") + for ty in [t for t in types if t.copy_fn is not None]: + f.write(" printf(\"Testing %s_copy, \");\n" % ty.typename) + arg = ty.typename + "_val" + f.write(" %s_init(%s);\n" % (ty.typename, \ + ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE))) + f.write(" %s_rand_init(%s);\n" % (ty.typename, \ + ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE))) + f.write(" %s_init(%s_new);\n" % (ty.typename, \ + ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE))) + f.write(" %s_copy(ctx, %s_new, %s);\n" % (ty.typename, \ + ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE), \ + ty.pass_arg(arg, isref=False, passby=idl.PASS_BY_REFERENCE))) + f.write(" s = %s_to_json(ctx, %s);\n" % \ + (ty.typename, ty.pass_arg(arg, isref=False))) + f.write(" if (s == NULL) abort();\n") + f.write(" new_s = %s_to_json(ctx, %s_new);\n" % \ + (ty.typename, ty.pass_arg(arg, isref=False))) + f.write(" if (new_s == NULL) abort();\n") + f.write(" if (strcmp(s, new_s)) {\n") + f.write(" printf(\"Huh? Deep copy for %s failed. Regenerated string different from original string.\\n\");\n" \ + % ty.typename) + f.write(" printf(\"Original string: %s\\n\", s);\n") + f.write(" printf(\"Regenerated string: %s\\n\", new_s);\n") + f.write(" abort();\n") + f.write(" }\n") + f.write(" free(s);\n") + f.write(" free(new_s);\n") + if ty.dispose_fn is not None: + f.write(" %s(&%s_val);\n" % (ty.dispose_fn, ty.typename)) + f.write(" %s(&%s_val_new);\n" % (ty.dispose_fn, ty.typename)) + f.write(" printf(\"done\\n\");\n") + f.write("\n") + + f.write(" printf(\"\\n\");\n") + f.write(" printf(\"Testing Enumerations\\n\");\n") + f.write(" printf(\"--------------------\\n\");\n") + f.write(" printf(\"\\n\");\n") + for ty in [t for t in types if isinstance(t,idl.Enumeration)]: + f.write(" printf(\"%s -- to string:\\n\");\n" % (ty.typename)) + for v in ty.values: + f.write(" printf(\"\\t%s = %%d = \\\"%%s\\\"\\n\", " \ + "%s, %s_to_string(%s));\n" % \ + (v.valuename, v.name, ty.typename, v.name)) + f.write("\n") + + f.write(" printf(\"%s -- to JSON:\\n\");\n" % (ty.typename)) + for v in ty.values: + f.write(" json_string = %s_to_json(ctx, %s);\n" % \ + (ty.typename, v.name)) + f.write(" printf(\"\\t%s = %%d = %%s\", " \ + "%s, json_string);\n" %\ + (v.valuename, v.name)) + f.write(" free(json_string);\n"); + f.write(" json_string = NULL;\n"); + f.write("\n") + + f.write(" printf(\"%s -- from string:\\n\");\n" % (ty.typename)) + for v in [v.valuename for v in ty.values] + ["AN INVALID VALUE"]: + n = randomize_case(v) + f.write(" %s_val = -1;\n" % (ty.typename)) + f.write(" rc = %s_from_string(\"%s\", &%s_val);\n" %\ + (ty.typename, n, ty.typename)) + + f.write(" printf(\"\\t%s = \\\"%%s\\\" = %%d (rc %%d)\\n\", " \ + "\"%s\", %s_val, rc);\n" %\ + (v, n, ty.typename)) + f.write("\n") + + f.write(""" + + libxl_ctx_free(ctx); + xtl_logger_destroy((xentoollog_logger*)logger); + + return 0; +} +""") diff --git a/tools/libs/light/gentypes.py b/tools/libs/light/gentypes.py new file mode 100644 index 0000000000..9a45e45acc --- /dev/null +++ b/tools/libs/light/gentypes.py @@ -0,0 +1,797 @@ +#!/usr/bin/python + +from __future__ import print_function + +import sys +import re + +import idl + +def libxl_C_instance_of(ty, instancename): + if isinstance(ty, idl.Aggregate) and ty.typename is None: + if instancename is None: + return libxl_C_type_define(ty) + else: + return libxl_C_type_define(ty) + " " + instancename + + s = "" + if isinstance(ty, idl.Array): + s += libxl_C_instance_of(ty.lenvar.type, ty.lenvar.name) + ";\n" + + return s + ty.typename + " " + instancename + +def libxl_C_type_define(ty, indent = ""): + s = "" + if isinstance(ty, idl.Enumeration): + if ty.typename is None: + s += "enum {\n" + else: + s += "typedef enum %s {\n" % ty.typename + + for v in ty.values: + x = "%s = %d" % (v.name, v.value) + x = x.replace("\n", "\n ") + s += " " + x + ",\n" + if ty.typename is None: + s += "}" + else: + s += "} %s" % ty.typename + + elif isinstance(ty, idl.Aggregate): + if isinstance(ty, idl.KeyedUnion): + s += libxl_C_instance_of(ty.keyvar.type, ty.keyvar.name) + ";\n" + + if ty.typename is None: + s += "%s {\n" % ty.kind + else: + s += "typedef %s %s {\n" % (ty.kind, ty.typename) + + for f in ty.fields: + if isinstance(ty, idl.KeyedUnion) and f.type is None: continue + + x = libxl_C_instance_of(f.type, f.name) + if f.const: + x = "const " + x + x = x.replace("\n", "\n ") + s += " " + x + ";\n" + if ty.typename is None: + s += "}" + else: + s += "} %s" % ty.typename + else: + raise NotImplementedError("%s" % type(ty)) + return s.replace("\n", "\n%s" % indent) + +def libxl_C_type_dispose(ty, v, indent = " ", parent = None): + s = "" + if isinstance(ty, idl.KeyedUnion): + if parent is None: + raise Exception("KeyedUnion type must have a parent") + s += "switch (%s) {\n" % (parent + ty.keyvar.name) + for f in ty.fields: + (nparent,fexpr) = ty.member(v, f, parent is None) + s += "case %s:\n" % f.enumname + if f.type is not None: + s += libxl_C_type_dispose(f.type, fexpr, indent + " ", nparent) + s += " break;\n" + s += "}\n" + elif isinstance(ty, idl.Array): + if parent is None: + raise Exception("Array type must have a parent") + if ty.elem_type.dispose_fn is not None: + s += "{\n" + s += " int i;\n" + s += " for (i=0; i<%s; i++)\n" % (parent + ty.lenvar.name) + s += libxl_C_type_dispose(ty.elem_type, v+"[i]", + indent + " ", parent) + if ty.dispose_fn is not None: + if ty.elem_type.dispose_fn is not None: + s += " " + s += "%s(%s);\n" % (ty.dispose_fn, ty.pass_arg(v, parent is None)) + if ty.elem_type.dispose_fn is not None: + s += "}\n" + elif isinstance(ty, idl.Struct) and (parent is None or ty.dispose_fn is None): + for f in [f for f in ty.fields if not f.const]: + (nparent,fexpr) = ty.member(v, f, parent is None) + s += libxl_C_type_dispose(f.type, fexpr, "", nparent) + else: + if ty.dispose_fn is not None: + s += "%s(%s);\n" % (ty.dispose_fn, ty.pass_arg(v, parent is None)) + + if s != "": + s = indent + s + return s.replace("\n", "\n%s" % indent).rstrip(indent) + +def libxl_C_type_copy(ty, v, w, indent = " ", vparent = None, wparent = None): + s = "" + + if vparent is None: + s += "GC_INIT(ctx);\n"; + + if isinstance(ty, idl.KeyedUnion): + if vparent is None or wparent is None: + raise Exception("KeyedUnion type must have a parent") + s += "%s = %s;\n" % ((vparent + ty.keyvar.name), (wparent + ty.keyvar.name)) + s += "switch (%s) {\n" % (wparent + ty.keyvar.name) + for f in ty.fields: + (vnparent,vfexpr) = ty.member(v, f, vparent is None) + (wnparent,wfexpr) = ty.member(w, f, wparent is None) + s += "case %s:\n" % f.enumname + if f.type is not None: + s += libxl_C_type_copy(f.type, vfexpr, wfexpr, indent + " ", + vnparent, wnparent) + s += " break;\n" + s += "}\n" + elif isinstance(ty, idl.Array): + if vparent is None or wparent is None: + raise Exception("Array type must have a parent") + s += "%s = libxl__calloc(NOGC, %s, sizeof(*%s));\n" % (ty.pass_arg(v, vparent is None), + (wparent + ty.lenvar.name), + ty.pass_arg(w, wparent is None)) + s += "%s = %s;\n" % ((vparent + ty.lenvar.name), (wparent + ty.lenvar.name)) + s += "{\n" + s += " int i;\n" + s += " for (i=0; i<%s; i++)\n" % (wparent + ty.lenvar.name) + s += libxl_C_type_copy(ty.elem_type, v+"[i]", w+"[i]", + indent + " ", vparent, wparent) + s += "}\n" + elif isinstance(ty, idl.Struct) and ((vparent is None and wparent is None) or ty.copy_fn is None): + for f in [f for f in ty.fields if not f.const and not f.type.private]: + (vnparent,vfexpr) = ty.member(v, f, vparent is None) + (wnparent,wfexpr) = ty.member(w, f, wparent is None) + s += libxl_C_type_copy(f.type, vfexpr, wfexpr, "", vnparent, wnparent) + else: + if ty.copy_fn is not None: + s += "%s(ctx, %s, %s);\n" % (ty.copy_fn, + ty.pass_arg(v, vparent is None, passby=idl.PASS_BY_REFERENCE), + ty.pass_arg(w, wparent is None, passby=idl.PASS_BY_REFERENCE)) + + else: + s += "%s = %s;\n" % (ty.pass_arg(v, vparent is None, passby=idl.PASS_BY_VALUE), + ty.pass_arg(w, wparent is None, passby=idl.PASS_BY_VALUE)) + + if vparent is None: + s += "GC_FREE;\n" + + if s != "": + s = indent + s + return s.replace("\n", "\n%s" % indent).rstrip(indent) + +def libxl_init_members(ty, nesting = 0): + """Returns a list of members of ty which require a separate init""" + + if isinstance(ty, idl.Aggregate): + return [f for f in ty.fields if not f.const and isinstance(f.type,idl.KeyedUnion)] + else: + return [] + +def libxl_C_type_do_init(ty, pass_arg, need_zero=True, indent=" "): + s=indent + if ty.init_val is not None: + s+= "%s = %s;\n" % (pass_arg(idl.PASS_BY_VALUE), ty.init_val) + elif ty.init_fn is not None: + s+= "%s(%s);\n" % (ty.init_fn, pass_arg(idl.PASS_BY_REFERENCE)) + elif need_zero: + ptr = pass_arg(idl.PASS_BY_REFERENCE) + s+= "memset(%s, 0, sizeof(*%s));\n" % (ptr, ptr) + else: + s="" + return s + +def _libxl_C_type_init(ty, v, indent = " ", parent = None, subinit=False): + s = "" + if isinstance(ty, idl.KeyedUnion): + if parent is None: + raise Exception("KeyedUnion type must have a parent") + if subinit: + s += "switch (%s) {\n" % (parent + ty.keyvar.name) + for f in ty.fields: + (nparent,fexpr) = ty.member(v, f, parent is None) + s += "case %s:\n" % f.enumname + if f.type is not None: + s += _libxl_C_type_init(f.type, fexpr, " ", nparent) + s += " break;\n" + s += "}\n" + else: + if ty.keyvar.init_val: + s += "%s = %s;\n" % (parent + ty.keyvar.name, ty.keyvar.init_val) + elif ty.keyvar.type.init_val: + s += "%s = %s;\n" % (parent + ty.keyvar.name, ty.keyvar.type.init_val) + elif isinstance(ty, idl.Struct) and (parent is None or ty.init_fn is None): + for f in [f for f in ty.fields if not f.const]: + (nparent,fexpr) = ty.member(v, f, parent is None) + if f.init_val is not None: + s += "%s = %s;\n" % (fexpr, f.init_val) + else: + s += _libxl_C_type_init(f.type, fexpr, "", nparent) + else: + if ty.init_val is not None: + s += "%s = %s;\n" % (ty.pass_arg(v, parent is None), ty.init_val) + elif ty.init_fn is not None: + s += "%s(%s);\n" % (ty.init_fn, ty.pass_arg(v, parent is None)) + + if s != "": + s = indent + s + return s.replace("\n", "\n%s" % indent).rstrip(indent) + +def libxl_C_type_init(ty): + s = "" + s += "void %s(%s)\n" % (ty.init_fn, ty.make_arg("p", passby=idl.PASS_BY_REFERENCE)) + s += "{\n" + s += " memset(p, '\\0', sizeof(*p));\n" + s += _libxl_C_type_init(ty, "p") + s += "}\n" + s += "\n" + return s + +def libxl_C_type_member_init(ty, field): + if not isinstance(field.type, idl.KeyedUnion): + raise Exception("Only KeyedUnion is supported for member init") + + ku = field.type + + s = "" + s += "void %s(%s, %s)\n" % (ty.init_fn + "_" + ku.keyvar.name, + ty.make_arg("p", passby=idl.PASS_BY_REFERENCE), + ku.keyvar.type.make_arg(ku.keyvar.name)) + s += "{\n" + + if ku.keyvar.init_val is not None: + init_val = ku.keyvar.init_val + elif ku.keyvar.type.init_val is not None: + init_val = ku.keyvar.type.init_val + else: + init_val = None + + (nparent,fexpr) = ty.member(ty.pass_arg("p"), ku.keyvar, isref=True) + if init_val is not None: + s += " assert(%s == %s);\n" % (fexpr, init_val) + else: + s += " assert(!%s);\n" % (fexpr) + s += " %s = %s;\n" % (fexpr, ku.keyvar.name) + + (nparent,fexpr) = ty.member(ty.pass_arg("p"), field, isref=True) + s += _libxl_C_type_init(ku, fexpr, parent=nparent, subinit=True) + s += "}\n" + s += "\n" + return s + +def libxl_C_type_gen_map_key(f, parent, indent = ""): + s = "" + if isinstance(f.type, idl.KeyedUnion): + s += "switch (%s) {\n" % (parent + f.type.keyvar.name) + for x in f.type.fields: + v = f.type.keyvar.name + "." + x.name + s += "case %s:\n" % x.enumname + s += " s = yajl_gen_string(hand, (const unsigned char *)\"%s\", sizeof(\"%s\")-1);\n" % (v, v) + s += " if (s != yajl_gen_status_ok)\n" + s += " goto out;\n" + s += " break;\n" + s += "}\n" + else: + s += "s = yajl_gen_string(hand, (const unsigned char *)\"%s\", sizeof(\"%s\")-1);\n" % (f.name, f.name) + s += "if (s != yajl_gen_status_ok)\n" + s += " goto out;\n" + if s != "": + s = indent + s + return s.replace("\n", "\n%s" % indent).rstrip(indent) + +def libxl_C_type_copy_deprecated(field, v, indent = " ", vparent = None): + s = "" + + if isinstance(field.type, idl.KeyedUnion): + if vparent is None: + raise Exception("KeyedUnion type must have a parent") + s += "switch (%s) {\n" % (vparent + field.type.keyvar.name) + for f in [f for f in field.type.fields if not f.const]: + (vnparent,vfexpr) = ty.member(v, f, vparent is None) + s += "case %s:\n" % f.enumname + if f.type is not None: + s += libxl_C_type_copy_deprecated(f, vfexpr, indent, vnparent) + s+= " break;\n" + s+="}\n"; + elif isinstance(field.type, idl.Array) and field.deprecated_by: + raise Exception("Array type is not supported for deprecation") + elif isinstance(field.type, idl.Struct) and field.type.copy_fn is None: + for f in [f for f in field.type.fields if not f.const]: + (vnparent,vfexpr) = ty.member(v, f, vparent is None) + s += libxl_C_type_copy_deprecated(f, vfexpr, "", vnparent) + elif field.deprecated_by is not None: + if field.type.check_default_fn is None: + raise Exception( +"Deprecated field %s type doesn't have a default value checker" % field.name) + field_pass = lambda by: field.type.pass_arg(v, vparent is None, + passby=by) + field_val = field_pass(idl.PASS_BY_VALUE) + field_ptr = field_pass(idl.PASS_BY_REFERENCE) + s+= "if (!%s(&p->%s) && !%s(%s))\n" % (field.type.check_default_fn, + field.deprecated_by, + field.type.check_default_fn, + field_ptr) + s+= " return -EINVAL;\n" + s+="(void) (&p->%s == %s);\n" % (field.deprecated_by, field_ptr) + s+= "if (%s(&p->%s)) {\n" % (field.type.check_default_fn, + field.deprecated_by) + s+= " " + if field.type.copy_fn is not None: + s+= "%s(ctx, &p->%s, %s);\n" % (field.type.copy_fn, + field.deprecated_by, field_ptr) + else: + s+= "p->%s = %s;\n" % (field.deprecated_by, field_val) + + if field.type.dispose_fn is not None: + s+= " %s(%s);\n" % (field.type.dispose_fn, + field.type.pass_arg(v, vparent is None)) + s+=libxl_C_type_do_init(field.type, field_pass) + s+= "}\n" + + if s != "": + s = indent + s + return s.replace("\n", "\n%s" % indent).rstrip(indent) + +def get_init_val(f): + if f.init_val is not None: + return f.init_val + elif f.type.init_val is not None: + return f.type.init_val + return None + +def get_default_expr(f, nparent, fexpr): + if isinstance(f.type, idl.Aggregate): + return "1 /* always generate JSON output for aggregate type */" + + if isinstance(f.type, idl.Array): + return "%s && %s" % (fexpr, nparent + f.type.lenvar.name) + + init_val = get_init_val(f) + if init_val is not None: + return "%s != %s" % (fexpr, init_val) + + if f.type.check_default_fn: + return "!%s(&%s)" % (f.type.check_default_fn, fexpr) + + return "%s" % fexpr + +def libxl_C_type_gen_json(ty, v, indent = " ", parent = None): + s = "" + if parent is None: + s += "yajl_gen_status s;\n" + + if isinstance(ty, idl.Array): + if parent is None: + raise Exception("Array type must have a parent") + s += "{\n" + s += " int i;\n" + s += " s = yajl_gen_array_open(hand);\n" + s += " if (s != yajl_gen_status_ok)\n" + s += " goto out;\n" + s += " for (i=0; i<%s; i++) {\n" % (parent + ty.lenvar.name) + s += libxl_C_type_gen_json(ty.elem_type, v+"[i]", + indent + " ", parent) + s += " }\n" + s += " s = yajl_gen_array_close(hand);\n" + s += " if (s != yajl_gen_status_ok)\n" + s += " goto out;\n" + s += "}\n" + elif isinstance(ty, idl.Enumeration): + s += "s = libxl__yajl_gen_enum(hand, %s_to_string(%s));\n" % (ty.typename, ty.pass_arg(v, parent is None)) + s += "if (s != yajl_gen_status_ok)\n" + s += " goto out;\n" + elif isinstance(ty, idl.KeyedUnion): + if parent is None: + raise Exception("KeyedUnion type must have a parent") + s += "switch (%s) {\n" % (parent + ty.keyvar.name) + for f in ty.fields: + (nparent,fexpr) = ty.member(v, f, parent is None) + s += "case %s:\n" % f.enumname + if f.type is not None: + s += libxl_C_type_gen_json(f.type, fexpr, indent + " ", nparent) + else: + s += " s = yajl_gen_map_open(hand);\n" + s += " if (s != yajl_gen_status_ok)\n" + s += " goto out;\n" + s += " s = yajl_gen_map_close(hand);\n" + s += " if (s != yajl_gen_status_ok)\n" + s += " goto out;\n" + s += " break;\n" + s += "}\n" + elif isinstance(ty, idl.Struct) and (parent is None or ty.json_gen_fn is None): + s += "s = yajl_gen_map_open(hand);\n" + s += "if (s != yajl_gen_status_ok)\n" + s += " goto out;\n" + for f in [f for f in ty.fields if not f.const and not f.type.private]: + (nparent,fexpr) = ty.member(v, f, parent is None) + default_expr = get_default_expr(f, nparent, fexpr) + s += "if (%s) {\n" % default_expr + + s += libxl_C_type_gen_map_key(f, nparent, " ") + s += libxl_C_type_gen_json(f.type, fexpr, " ", nparent) + + s += "}\n" + + s += "s = yajl_gen_map_close(hand);\n" + s += "if (s != yajl_gen_status_ok)\n" + s += " goto out;\n" + else: + if ty.json_gen_fn is not None: + s += "s = %s(hand, %s);\n" % (ty.json_gen_fn, ty.pass_arg(v, parent is None)) + s += "if (s != yajl_gen_status_ok)\n" + s += " goto out;\n" + + if parent is None: + s += "out:\n" + s += "return s;\n" + + if s != "": + s = indent + s + return s.replace("\n", "\n%s" % indent).rstrip(indent) + +def libxl_C_type_to_json(ty, v, indent = " "): + s = "" + gen = "(libxl__gen_json_callback)&%s_gen_json" % ty.typename + s += "return libxl__object_to_json(ctx, \"%s\", %s, (void *)%s);\n" % (ty.typename, gen, ty.pass_arg(v, passby=idl.PASS_BY_REFERENCE)) + + if s != "": + s = indent + s + return s.replace("\n", "\n%s" % indent).rstrip(indent) + +def libxl_C_type_parse_json(ty, w, v, indent = " ", parent = None, discriminator = None): + s = "" + if parent is None: + s += "int rc = 0;\n" + s += "const libxl__json_object *x __attribute__((__unused__)) = o;\n" + + if isinstance(ty, idl.Array): + if parent is None: + raise Exception("Array type must have a parent") + if discriminator is not None: + raise Exception("Only KeyedUnion can have discriminator") + lenvar = parent + ty.lenvar.name + s += "{\n" + s += " libxl__json_object *t;\n" + s += " int i;\n" + s += " if (!libxl__json_object_is_array(x)) {\n" + s += " rc = -1;\n" + s += " goto out;\n" + s += " }\n" + s += " %s = x->u.array->count;\n" % lenvar + s += " %s = libxl__calloc(NOGC, %s, sizeof(*%s));\n" % (v, lenvar, v) + s += " if (!%s && %s != 0) {\n" % (v, lenvar) + s += " rc = -1;\n" + s += " goto out;\n" + s += " }\n" + s += " for (i=0; (t=libxl__json_array_get(x,i)); i++) {\n" + s += libxl_C_type_do_init(ty.elem_type, + lambda by: ("&" if by == idl.PASS_BY_REFERENCE else "")+ + ("%s[i]" % v), + need_zero=False, indent=indent+" ") + s += libxl_C_type_parse_json(ty.elem_type, "t", v+"[i]", + indent + " ", parent) + s += " }\n" + s += " if (i != %s) {\n" % lenvar + s += " rc = -1;\n" + s += " goto out;\n" + s += " }\n" + s += "}\n" + elif isinstance(ty, idl.Enumeration): + if discriminator is not None: + raise Exception("Only KeyedUnion can have discriminator") + s += "{\n" + s += " const char *enum_str;\n" + s += " if (!libxl__json_object_is_string(%s)) {\n" % w + s += " rc = -1;\n" + s += " goto out;\n" + s += " }\n" + s += " enum_str = libxl__json_object_get_string(%s);\n" % w + s += " rc = %s_from_string(enum_str, %s);\n" % (ty.typename, ty.pass_arg(v, parent is None, idl.PASS_BY_REFERENCE)) + s += " if (rc)\n" + s += " goto out;\n" + s += "}\n" + elif isinstance(ty, idl.KeyedUnion): + if parent is None: + raise Exception("KeyedUnion type must have a parent") + if discriminator is None: + raise Excpetion("KeyedUnion type must have a discriminator") + for f in ty.fields: + if f.enumname != discriminator: + continue + (nparent,fexpr) = ty.member(v, f, parent is None) + if f.type is not None: + s += libxl_C_type_parse_json(f.type, w, fexpr, indent + " ", nparent) + elif isinstance(ty, idl.Struct) and (parent is None or ty.json_parse_fn is None): + if discriminator is not None: + raise Exception("Only KeyedUnion can have discriminator") + for f in [f for f in ty.fields if not f.const and not f.type.private]: + saved_var_name = "saved_%s" % f.name + s += "{\n" + s += " const libxl__json_object *%s = x;\n" % saved_var_name + if isinstance(f.type, idl.KeyedUnion): + for x in f.type.fields: + s += " x = libxl__json_map_get(\"%s\", %s, JSON_MAP);\n" % \ + (f.type.keyvar.name + "." + x.name, w) + s += " if (x) {\n" + (nparent, fexpr) = ty.member(v, f.type.keyvar, parent is None) + s += " %s_init_%s(%s, %s);\n" % (ty.typename, f.type.keyvar.name, v, x.enumname) + (nparent,fexpr) = ty.member(v, f, parent is None) + s += libxl_C_type_parse_json(f.type, "x", fexpr, " ", nparent, x.enumname) + s += " }\n" + else: + s += " x = libxl__json_map_get(\"%s\", %s, %s);\n" % (f.name, w, f.type.json_parse_type) + s += " if (x) {\n" + (nparent,fexpr) = ty.member(v, f, parent is None) + s += libxl_C_type_parse_json(f.type, "x", fexpr, " ", nparent) + s += " }\n" + s += " x = %s;\n" % saved_var_name + s += "}\n" + else: + if discriminator is not None: + raise Exception("Only KeyedUnion can have discriminator") + if ty.json_parse_fn is not None: + s += "rc = %s(gc, %s, &%s);\n" % (ty.json_parse_fn, w, v) + s += "if (rc)\n" + s += " goto out;\n" + + if parent is None: + s += "out:\n" + s += "return rc;\n" + + if s != "": + s = indent +s + return s.replace("\n", "\n%s" % indent).rstrip(indent) + +def libxl_C_type_from_json(ty, v, w, indent = " "): + s = "" + parse = "(libxl__json_parse_callback)&%s_parse_json" % (ty.namespace + "_" + ty.rawname) + s += "return libxl__object_from_json(ctx, \"%s\", %s, %s, %s);\n" % (ty.typename, parse, v, w) + + if s != "": + s = indent + s + return s.replace("\n", "\n%s" % indent).rstrip(indent) + +def libxl_C_enum_to_string(ty, e, indent = " "): + s = "" + s += "switch(%s) {\n" % e + for v in ty.values: + s += " case %s:\n" % (v.name) + s += " return \"%s\";\n" % (v.valuename.lower()) + s += " default:\n " + s += " return NULL;\n" + s += "}\n" + + if s != "": + s = indent + s + return s.replace("\n", "\n%s" % indent).rstrip(indent) + +def libxl_C_enum_strings(ty, indent=""): + s = "" + s += "libxl_enum_string_table %s_string_table[] = {\n" % (ty.typename) + for v in ty.values: + s += " { .s = \"%s\", .v = %s },\n" % (v.valuename.lower(), v.name) + s += " { NULL, -1 },\n" + s += "};\n" + s += "\n" + + if s != "": + s = indent + s + return s.replace("\n", "\n%s" % indent).rstrip(indent) + +def libxl_C_enum_from_string(ty, str, e, indent = " "): + s = "" + s += "return libxl__enum_from_string(%s_string_table,\n" % ty.typename + s += " %s, (int *)%s);\n" % (str, e) + + if s != "": + s = indent + s + return s.replace("\n", "\n%s" % indent).rstrip(indent) + + +if __name__ == '__main__': + if len(sys.argv) != 6: + print("Usage: gentypes.py <idl> <header> <header-private> <header-json> <implementation>", file=sys.stderr) + sys.exit(1) + + (_, idlname, header, header_private, header_json, impl) = sys.argv + + (builtins,types) = idl.parse(idlname) + + print("outputting libxl type definitions to %s" % header) + + f = open(header, "w") + + header_define = header.upper().replace('.','_') + f.write("""#ifndef %s +#define %s + +/* + * DO NOT EDIT. + * + * This file is autogenerated by + * "%s" + */ + +""" % (header_define, header_define, " ".join(sys.argv))) + + for ty in types: + f.write(libxl_C_type_define(ty) + ";\n") + if ty.dispose_fn is not None: + f.write("%svoid %s(%s);\n" % (ty.hidden(), ty.dispose_fn, ty.make_arg("p"))) + if ty.copy_deprecated_fn is not None: + f.write("%sint %s(libxl_ctx *ctx, %s);\n" % (ty.hidden(), + ty.copy_deprecated_fn, + ty.make_arg("p"))) + if ty.copy_fn is not None: + f.write("%svoid %s(libxl_ctx *ctx, %s, const %s);\n" % (ty.hidden(), ty.copy_fn, + ty.make_arg("dst"), ty.make_arg("src"))) + if ty.init_fn is not None: + f.write("%svoid %s(%s);\n" % (ty.hidden(), ty.init_fn, ty.make_arg("p"))) + for field in libxl_init_members(ty): + if not isinstance(field.type, idl.KeyedUnion): + raise Exception("Only KeyedUnion is supported for member init") + ku = field.type + f.write("%svoid %s(%s, %s);\n" % (ty.hidden(), ty.init_fn + "_" + ku.keyvar.name, + ty.make_arg("p"), + ku.keyvar.type.make_arg(ku.keyvar.name))) + if ty.json_gen_fn is not None: + f.write("%schar *%s_to_json(libxl_ctx *ctx, %s);\n" % (ty.hidden(), ty.typename, ty.make_arg("p"))) + if ty.json_parse_fn is not None: + f.write("%sint %s_from_json(libxl_ctx *ctx, %s, const char *s);\n" % (ty.hidden(), ty.typename, ty.make_arg("p", passby=idl.PASS_BY_REFERENCE))) + if isinstance(ty, idl.Enumeration): + f.write("%sconst char *%s_to_string(%s);\n" % (ty.hidden(), ty.typename, ty.make_arg("p"))) + f.write("%sint %s_from_string(const char *s, %s);\n" % (ty.hidden(), ty.typename, ty.make_arg("e", passby=idl.PASS_BY_REFERENCE))) + f.write("%sextern libxl_enum_string_table %s_string_table[];\n" % (ty.hidden(), ty.typename)) + f.write("\n") + + f.write("""#endif /* %s */\n""" % (header_define)) + f.close() + + print("outputting libxl JSON definitions to %s" % header_json) + + f = open(header_json, "w") + + header_json_define = header_json.upper().replace('.','_') + f.write("""#ifndef %s +#define %s + +/* + * DO NOT EDIT. + * + * This file is autogenerated by + * "%s" + */ + +""" % (header_json_define, header_json_define, " ".join(sys.argv))) + + for ty in [ty for ty in types if ty.json_gen_fn is not None]: + f.write("%syajl_gen_status %s_gen_json(yajl_gen hand, %s);\n" % (ty.hidden(), ty.typename, ty.make_arg("p", passby=idl.PASS_BY_REFERENCE))) + + f.write("\n") + f.write("""#endif /* %s */\n""" % header_json_define) + f.close() + + print("outputting libxl type internal definitions to %s" % header_private) + + f = open(header_private, "w") + + header_private_define = header_private.upper().replace('.','_') + f.write("""#ifndef %s +#define %s + +/* + * DO NOT EDIT. + * + * This file is autogenerated by + * "%s" + */ + +""" % (header_private_define, header_private_define, " ".join(sys.argv))) + + for ty in [ty for ty in types if ty.json_parse_fn is not None]: + f.write("%sint %s_parse_json(libxl__gc *gc, const libxl__json_object *o, %s);\n" % \ + (ty.hidden(), ty.namespace + "_" + ty.rawname, + ty.make_arg("p", passby=idl.PASS_BY_REFERENCE))) + + f.write("\n") + f.write("""#endif /* %s */\n""" % header_json_define) + f.close() + + print("outputting libxl type implementations to %s" % impl) + + f = open(impl, "w") + f.write(""" +/* DO NOT EDIT. + * + * This file is autogenerated by + * "%s" + */ + +#include "libxl_osdeps.h" + +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "libxl_internal.h" + + +""" % " ".join(sys.argv)) + + for ty in [t for t in types if t.dispose_fn is not None and t.autogenerate_dispose_fn]: + f.write("void %s(%s)\n" % (ty.dispose_fn, ty.make_arg("p"))) + f.write("{\n") + f.write(" if (!p) return;\n") + f.write(libxl_C_type_dispose(ty, "p")) + f.write(" memset(p, 0, sizeof(*p));\n") + f.write("}\n") + f.write("\n") + + for ty in [t for t in types if t.copy_fn and t.autogenerate_copy_fn]: + f.write("void %s(libxl_ctx *ctx, %s, const %s)\n" % (ty.copy_fn, + ty.make_arg("dst", passby=idl.PASS_BY_REFERENCE), + ty.make_arg("src", passby=idl.PASS_BY_REFERENCE))) + f.write("{\n") + f.write(libxl_C_type_copy(ty, "dst", "src")) + f.write("}\n") + f.write("\n") + + for ty in [t for t in types if t.copy_deprecated_fn]: + f.write("int %s(libxl_ctx *ctx, %s)\n" % (ty.copy_deprecated_fn, + ty.make_arg("p", passby=idl.PASS_BY_REFERENCE))) + f.write("{\n") + for field in [field for field in ty.fields if not field.const]: + (vnparent,vfexpr) = ty.member("p", field, True) + f.write(libxl_C_type_copy_deprecated(field, vfexpr, + vparent = vnparent)) + f.write(" return 0;\n") + f.write("}\n") + f.write("\n") + + for ty in [t for t in types if t.init_fn is not None and t.autogenerate_init_fn]: + f.write(libxl_C_type_init(ty)) + for field in libxl_init_members(ty): + f.write(libxl_C_type_member_init(ty, field)) + + for ty in [t for t in types if isinstance(t,idl.Enumeration)]: + f.write("const char *%s_to_string(%s e)\n" % (ty.typename, ty.typename)) + f.write("{\n") + f.write(libxl_C_enum_to_string(ty, "e")) + f.write("}\n") + f.write("\n") + + f.write(libxl_C_enum_strings(ty)) + + f.write("int %s_from_string(const char *s, %s *e)\n" % (ty.typename, ty.typename)) + f.write("{\n") + f.write(libxl_C_enum_from_string(ty, "s", "e")) + f.write("}\n") + f.write("\n") + + for ty in [t for t in types if t.json_gen_fn is not None]: + f.write("yajl_gen_status %s_gen_json(yajl_gen hand, %s)\n" % (ty.typename, ty.make_arg("p", passby=idl.PASS_BY_REFERENCE))) + f.write("{\n") + f.write(libxl_C_type_gen_json(ty, "p")) + f.write("}\n") + f.write("\n") + + f.write("char *%s_to_json(libxl_ctx *ctx, %s)\n" % (ty.typename, ty.make_arg("p"))) + f.write("{\n") + f.write(libxl_C_type_to_json(ty, "p")) + f.write("}\n") + f.write("\n") + + for ty in [t for t in types if t.json_parse_fn is not None]: + f.write("int %s_parse_json(libxl__gc *gc, const libxl__json_object *%s, %s)\n" % \ + (ty.namespace + "_" + ty.rawname,"o",ty.make_arg("p", passby=idl.PASS_BY_REFERENCE))) + f.write("{\n") + f.write(libxl_C_type_parse_json(ty, "o", "p")) + f.write("}\n") + f.write("\n") + + f.write("int %s_from_json(libxl_ctx *ctx, %s, const char *s)\n" % (ty.typename, ty.make_arg("p", passby=idl.PASS_BY_REFERENCE))) + f.write("{\n") + if not isinstance(ty, idl.Enumeration): + f.write(" %s_init(p);\n" % ty.typename) + f.write(libxl_C_type_from_json(ty, "p", "s")) + f.write("}\n") + f.write("\n") + + f.close() diff --git a/tools/libs/light/idl.py b/tools/libs/light/idl.py new file mode 100644 index 0000000000..d7367503b4 --- /dev/null +++ b/tools/libs/light/idl.py @@ -0,0 +1,377 @@ +from __future__ import print_function + +import sys + +PASS_BY_VALUE = 1 +PASS_BY_REFERENCE = 2 + +DIR_NONE = 0 +DIR_IN = 1 +DIR_OUT = 2 +DIR_BOTH = 3 + +_default_namespace = "" +def namespace(s): + if type(s) != str: + raise TypeError("Require a string for the default namespace.") + global _default_namespace + _default_namespace = s + +def _get_default_namespace(): + global _default_namespace + return _default_namespace + +_default_hidden = False +def hidden(b): + global _default_hidden + _default_hidden = b + +def _get_default_hidden(): + global _default_hidden + return _default_hidden + +class Type(object): + def __init__(self, typename, **kwargs): + self.namespace = kwargs.setdefault('namespace', + _get_default_namespace()) + self._hidden = kwargs.setdefault('hidden', _get_default_hidden()) + self.dir = kwargs.setdefault('dir', DIR_BOTH) + if self.dir not in [DIR_NONE, DIR_IN, DIR_OUT, DIR_BOTH]: + raise ValueError + + self.passby = kwargs.setdefault('passby', PASS_BY_VALUE) + if self.passby not in [PASS_BY_VALUE, PASS_BY_REFERENCE]: + raise ValueError + + self.private = kwargs.setdefault('private', False) + + if typename is None: # Anonymous type + self.typename = None + self.rawname = None + elif self.namespace is None: # e.g. system provided types + self.typename = typename + self.rawname = typename + else: + self.typename = self.namespace + typename + self.rawname = typename + + if self.typename is not None: + self.dispose_fn = kwargs.setdefault('dispose_fn', self.typename + "_dispose") + else: + self.dispose_fn = kwargs.setdefault('dispose_fn', None) + + self.autogenerate_dispose_fn = kwargs.setdefault('autogenerate_dispose_fn', True) + + if self.typename is not None: + self.copy_fn = kwargs.setdefault('copy_fn', self.typename + "_copy") + else: + self.copy_fn = kwargs.setdefault('copy_fn', None) + + self.autogenerate_copy_fn = kwargs.setdefault('autogenerate_copy_fn', True) + + self.init_fn = kwargs.setdefault('init_fn', None) + self.init_val = kwargs.setdefault('init_val', None) + self.autogenerate_init_fn = kwargs.setdefault('autogenerate_init_fn', False) + + self.check_default_fn = kwargs.setdefault('check_default_fn', None) + self.copy_deprecated_fn = kwargs.setdefault('copy_deprecated_fn', + None) + + if self.typename is not None and not self.private: + self.json_gen_fn = kwargs.setdefault('json_gen_fn', self.typename + "_gen_json") + self.json_parse_type = kwargs.setdefault('json_parse_type', "JSON_ANY") + if self.namespace is not None: + self.json_parse_fn = kwargs.setdefault('json_parse_fn', + self.namespace + "_" + self.rawname + "_parse_json") + else: + self.json_parse_fn = kwargs.setdefault('json_parse_fn', + self.typename + "_parse_json") + else: + self.json_gen_fn = kwargs.setdefault('json_gen_fn', None) + self.json_parse_type = kwargs.setdefault('json_parse_type', None) + self.json_parse_fn = kwargs.setdefault('json_parse_fn', None) + + self.autogenerate_json = kwargs.setdefault('autogenerate_json', True) + + def marshal_in(self): + return self.dir in [DIR_IN, DIR_BOTH] + def marshal_out(self): + return self.dir in [DIR_OUT, DIR_BOTH] + + def hidden(self): + if self._hidden: + return "_hidden " + else: + return "" + + def make_arg(self, n, passby=None): + if passby is None: passby = self.passby + + if passby == PASS_BY_REFERENCE: + return "%s *%s" % (self.typename, n) + else: + return "%s %s" % (self.typename, n) + + def pass_arg(self, n, isref=None, passby=None): + if passby is None: passby = self.passby + if isref is None: isref = self.passby == PASS_BY_REFERENCE + + if passby == PASS_BY_REFERENCE: + if isref: + return "%s" % (n) + else: + return "&%s" % (n) + else: + if isref: + return "*%s" % (n) + else: + return "%s" % (n) + +class Builtin(Type): + """Builtin type""" + def __init__(self, typename, **kwargs): + kwargs.setdefault('dispose_fn', None) + kwargs.setdefault('autogenerate_dispose_fn', False) + kwargs.setdefault('autogenerate_json', False) + Type.__init__(self, typename, **kwargs) + +class Number(Builtin): + def __init__(self, ctype, **kwargs): + kwargs.setdefault('namespace', None) + kwargs.setdefault('dispose_fn', None) + kwargs.setdefault('copy_fn', None) + kwargs.setdefault('signed', False) + kwargs.setdefault('json_gen_fn', "yajl_gen_integer") + kwargs.setdefault('json_parse_type', "JSON_INTEGER") + # json_parse_fn might be overriden on specific type + kwargs.setdefault('json_parse_fn', "libxl__int_parse_json") + self.signed = kwargs['signed'] + Builtin.__init__(self, ctype, **kwargs) + +class UInt(Number): + def __init__(self, w, **kwargs): + kwargs.setdefault('namespace', None) + kwargs.setdefault('dispose_fn', None) + kwargs.setdefault('json_parse_fn', "libxl__uint%d_parse_json" % w) + kwargs.setdefault('copy_fn', None) + Number.__init__(self, "uint%d_t" % w, **kwargs) + + self.width = w + +class EnumerationValue(object): + def __init__(self, enum, value, name, **kwargs): + self.enum = enum + + self.valuename = str.upper(name) + self.rawname = str.upper(enum.rawname) + "_" + self.valuename + self.name = str.upper(enum.value_namespace) + self.rawname + self.value = value + +class Enumeration(Type): + def __init__(self, typename, values, **kwargs): + kwargs.setdefault('dispose_fn', None) + kwargs.setdefault('copy_fn', None) + kwargs.setdefault('json_parse_type', "JSON_STRING") + Type.__init__(self, typename, **kwargs) + + self.value_namespace = kwargs.setdefault('value_namespace', + self.namespace) + + self.values = [] + for v in values: + # (value, name) + (num,name) = v + self.values.append(EnumerationValue(self, num, name, + typename=self.rawname)) + def lookup(self, name): + for v in self.values: + if v.valuename == str.upper(name): + return v + return ValueError + +class Field(object): + """An element of an Aggregate type""" + def __init__(self, type, name, **kwargs): + self.type = type + self.name = name + self.const = kwargs.setdefault('const', False) + self.enumname = kwargs.setdefault('enumname', None) + self.init_val = kwargs.setdefault('init_val', None) + self.deprecated_by = kwargs.setdefault('deprecated_by', None) + +class Aggregate(Type): + """A type containing a collection of other types""" + def __init__(self, kind, typename, fields, **kwargs): + kwargs.setdefault('json_parse_type', "JSON_MAP") + Type.__init__(self, typename, **kwargs) + + if self.typename is not None: + self.init_fn = kwargs.setdefault('init_fn', self.typename + "_init") + else: + self.init_fn = kwargs.setdefault('init_fn', None) + + self.autogenerate_init_fn = kwargs.setdefault('autogenerate_init_fn', True) + + self.kind = kind + + self.fields = [] + for f in fields: + # (name, type[, {kw args}]) + if len(f) == 2: + n,t = f + kw = {} + elif len(f) == 3: + n,t,kw = f + else: + raise ValueError + if n is None: + raise ValueError + self.fields.append(Field(t,n,**kw)) + + # Returns a tuple (stem, field-expr) + # + # field-expr is a C expression for a field "f" within the struct + # "v". + # + # stem is the stem common to both "f" and any other sibbling field + # within the "v". + def member(self, v, f, isref): + if isref: + deref = v + "->" + else: + deref = v + "." + + if f.name is None: # Anonymous + return (deref, deref) + else: + return (deref, deref + f.name) + +class Struct(Aggregate): + def __init__(self, name, fields, **kwargs): + kwargs.setdefault('passby', PASS_BY_REFERENCE) + Aggregate.__init__(self, "struct", name, fields, **kwargs) + + def has_fields(self): + return len(self.fields) != 0 + +class Union(Aggregate): + def __init__(self, name, fields, **kwargs): + # Generally speaking some intelligence is required to free a + # union therefore any specific instance of this class will + # need to provide an explicit destructor function. + kwargs.setdefault('passby', PASS_BY_REFERENCE) + kwargs.setdefault('dispose_fn', None) + Aggregate.__init__(self, "union", name, fields, **kwargs) + +class KeyedUnion(Aggregate): + """A union which is keyed of another variable in the parent structure""" + def __init__(self, name, keyvar_type, keyvar_name, fields, **kwargs): + Aggregate.__init__(self, "union", name, [], **kwargs) + + if not isinstance(keyvar_type, Enumeration): + raise ValueError + + kv_kwargs = dict([(x.lstrip('keyvar_'),y) for (x,y) in kwargs.items() if x.startswith('keyvar_')]) + + self.keyvar = Field(keyvar_type, keyvar_name, **kv_kwargs) + + for f in fields: + # (name, enum, type) + e, ty = f + ev = keyvar_type.lookup(e) + en = ev.name + self.fields.append(Field(ty, e, enumname=en)) + +# +# Standard Types +# + +void = Builtin("void *", namespace = None) +bool = Builtin("bool", namespace = None, + copy_fn=None, + json_gen_fn = "yajl_gen_bool", + json_parse_type = "JSON_BOOL", + json_parse_fn = "libxl__bool_parse_json", + autogenerate_json = False) + +size_t = Number("size_t", namespace = None) + +integer = Number("int", namespace = None, signed = True) + +uint8 = UInt(8) +uint16 = UInt(16) +uint32 = UInt(32) +uint64 = UInt(64, json_gen_fn = "libxl__uint64_gen_json") + +string = Builtin("char *", namespace = None, copy_fn = "libxl_string_copy", dispose_fn = "free", + json_gen_fn = "libxl__string_gen_json", + json_parse_type = "JSON_STRING | JSON_NULL", + json_parse_fn = "libxl__string_parse_json", + autogenerate_json = False, + check_default_fn="libxl__string_is_default") + +class Array(Type): + """An array of the same type""" + def __init__(self, elem_type, lenvar_name, **kwargs): + kwargs.setdefault('dispose_fn', 'free') + kwargs.setdefault('json_parse_type', 'JSON_ARRAY') + Type.__init__(self, namespace=elem_type.namespace, typename=elem_type.rawname + " *", **kwargs) + + lv_kwargs = dict([(x.lstrip('lenvar_'),y) for (x,y) in kwargs.items() if x.startswith('lenvar_')]) + + self.lenvar = Field(integer, lenvar_name, **lv_kwargs) + self.elem_type = elem_type + +class OrderedDict(dict): + """A dictionary which remembers insertion order. + + push to back on duplicate insertion""" + + def __init__(self): + dict.__init__(self) + self.__ordered = [] + + def __setitem__(self, key, value): + try: + self.__ordered.remove(key) + except ValueError: + pass + + self.__ordered.append(key) + dict.__setitem__(self, key, value) + + def ordered_keys(self): + return self.__ordered + def ordered_values(self): + return [self[x] for x in self.__ordered] + def ordered_items(self): + return [(x,self[x]) for x in self.__ordered] + +def parse(f): + print("Parsing %s" % f, file=sys.stderr) + + globs = {} + locs = OrderedDict() + + for n,t in globals().items(): + if isinstance(t, Type): + globs[n] = t + elif isinstance(t,type(object)) and issubclass(t, Type): + globs[n] = t + elif n in ['PASS_BY_REFERENCE', 'PASS_BY_VALUE', + 'DIR_NONE', 'DIR_IN', 'DIR_OUT', 'DIR_BOTH', + 'namespace', 'hidden']: + globs[n] = t + + try: + exec(compile(open(f).read(), f, 'exec'), globs, locs) + except SyntaxError as e: + raise SyntaxError("Errors were found at line %d while processing %s:\n\t%s" + % (e.lineno, f, e.text)) + + types = [t for t in locs.ordered_values() if isinstance(t,Type)] + + builtins = [t for t in types if isinstance(t,Builtin)] + types = [t for t in types if not isinstance(t,Builtin)] + + return (builtins,types) diff --git a/tools/libs/light/idl.txt b/tools/libs/light/idl.txt new file mode 100644 index 0000000000..7440fb3b76 --- /dev/null +++ b/tools/libs/light/idl.txt @@ -0,0 +1,214 @@ +libxl IDL +--------- + +Each type in the libxl interface is represented by an object of type +idl.Type (or a subclass thereof). Every local variable defined by the +.idl file must be an instance of idl.Type (e.g. you may not define +Python functions or any other construct other than defining variables) + +The name of the type must be passed as the first argument to the +constructor when defining a new type. The name given should not +contain the initial namespace element (e.g. "libxl_"). See below for +how to specify a namespace. + +The Type.typename contains the C name of the type _including_ the +namespace element while Type.rawname is always set to the 'base' name +of the type. + +The idl.Type base class has several other properties which apply to +all types. The properties are set by passing a named parameter to the +constructor. + +Type.namespace: (default: "libxl_") + + The namespace in which the type resides. Usually this is "libxl_" but + system defined and builtin types may differ. + + If the typename is not None then the namespace is prepended to the + type. + +Type.passby: (default: idl.PASS_BY_VALUE) + + Defines the manner in which a type should be passed to C + functions. Valid values for this fields are: + idl.PASS_BY_VALUE + idl.PASS_BY_REFERENCE + +Type.dispose_fn: (default: typename + "_dispose" or None if type == None) + + The name of the C function which will free all dynamically allocated + memory contained within this type (but not the type itself). + +Type.autogenerate_dispose_fn: (default: True) + + Indicates if the above named Type.dispose_fn should be + autogenerated. + +Type.copy_fn: (default: typename + "_copy" or None if type == None) + + The name of the C function which will deep copy all fields within + this type. + +Type.autogenerate_copy_fn: (default: True) + + Indicates if the above named Type.copy_fn should be + autogenerated. + +Type.autogenerate_copy_fn + +Type.init_val: (default: None) + + C expression for the value to initialise instances of this type to. + + If present takes precendence over init_fn (see below). + +Type.init_fn: (default: typename + "_init" if dir in [IN, BOTH] and + type != None) + + The name of the C function which will initialist Type. + +Type.autogenerate_init_fn: (default: True if dir in [IN, BOTH]) + + Indicates if the above named Type.init_fn should be + autogenerated. + +Type.json_gen_fn: (default: typename + "_gen_json" or None if type == None) + + The name of the C function which will generate a YAJL data structure + representing this type. + +Type.json_parse_fn: (default: typename + "_parse_json" or None if type == None) + + The name of the C function which will parse a libxl JSON structure + representing this type to C type. + +Type.autogenerate_json: (default: True) + + Indicates if the above named Type.json_*_fn should be autogenerated. + +Type.check_default_fn: + + If it's set then calling this function shall return true if this type + has been set to default value (internal libxl implementation). + + If this is not set, that means we can check the type against init_val + (if it has one) or zero to determine whether the value is default + value. + +Other simple type-Classes +------------------------- + +idl.Builtin + + Instances of this class represent types which are predefined within + the system. + +idl.UInt + + Instances of this class represent the standard uint<N>_t types. + + The <N> for a given instance must be passed to the constructor and is + then available in UInt.width + +Complex type-Classes +-------------------- + +idl.Enumeration + + A class representing an enumeration (named integer values). + This class has one property besides the ones defined for the Type + class: + + Enumeration.value_namespace: (default: namespace) + + The namespace in which the values of the Enumeration (see below) reside. + This prefix is prepended to the name of the value. + + The values are available in the list Enumeration.values. Each + element in the list is of type idl.EnumerationValue. + + Each EnumerationValue has the following properties: + + EnumerationValue.enum Reference to containing Enumeration + EnumerationValue.name The C name of this value, including + the namespace and typename of the + containing Enumeration (e.g. + "LIBXL_FOOENUM_VALUE") + EnumerationValue.rawname The C name of this value, excluding + the namespace but including the + typename of the containing + Enumeration (e.g. "FOOENUM_VALUE") + EnumerationValue.valuename The name of this value, excluding the + name of the containing Enumeration + and any namespace (e.g. "VALUE") + EnumerationValue.value The integer value associated with this name. + +idl.Aggregate + + Base class for type-Classes which contain a number of other types + (e.g. structs and unions). + + The contained types are available in the list Aggregate.fields. Each + element in the list is of type idl.Field representing a member of the + aggregate. + + Each field has the following properties: + + Field.type The type of the member (a idl.Type). + Field.name The name of the member (can be None for anonymous + fields). + Field.const Boolean, true if the member is const. + Field.init_val The initialisation value for this field. Takes + precendence over both Field.type.init_val and + Field.type.init_fn. + +idl.Struct + + A subclass of idl.Aggregate representing the C struct type. + + Struct.kind == "struct" + +idl.Union + + A subclass of idl.Aggregate representing the C union type. + + Union.kind == "union" + +idl.KeyedUnion + + A subclass of idl.Aggregate which represents the C union type + where the currently valid member of the union can be determined based + upon another member in the containing type. An idl.KeyedUnion must + always be a member of a containing idl.Aggregate type. + + The KeyedUnion.keyvar contains an idl.Field, this is the member of + the containing type which determines the valid member of the + union. The idl.Field.type of the keyvar must be an Enumeration type. + +idl.Array + + A class representing an array of similar elements. An idl.Array must + always be an idl.Field of a containing idl.Aggregate. + + idl.Array.elem_type contains an idl.Type which is the type of each + element of the array. + + idl.Array.len_var contains an idl.Field which is added to the parent + idl.Aggregate and will contain the length of the array. The field + MUST be named num_ARRAYNAME. + +Standard Types +-------------- + +Several standard types a predefined. They are + +void (void pointer type) +bool +size_t +integer 24 bit signed integer. + +uint{8,16,32,64} uint{8,16,32,64}_t
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |