This is a repost of version 2 of this patch series to fix the OCaml binding to libxl. I believe I have addressed all the points raised by Dave Scott and Ian Campbell. Sorry for the delay in getting this new series out! The main changes are: * Several fixes to ensure the bindings play well with the OCaml GC. This includes properly using macros such as CAMLparam* and CAMLreturn* for _all_ OCaml values (even intermediate ones), and using "custom" blocks to encapsulate pointers to C code (including handy "finalize" functions for cleanup. * Fixes in the way KeyedUnions are handled. * Use the libxl init function to generate default records for libxl types. * Improve the functions that deal with event handling. We now have some higher-level functions to makes this easier as well as safer, and errors are translated properly. --------- The following series of patches fill in most of the gaps in the OCaml bindings to libxl, to make them useful for clients such as xapi/xenopsd (from XCP). There are a number of bugfixes to the existing bindings as well. I have an experimental version of xenopsd that successfully uses the new bindings. An earlier version of the first half of the series was submitted to the last by Ian Campbell on 20 Nov 2012. With his permission, I have updated most of them to fix some issues (which were discussed on the mailing list at the time). I have left Ian''s signed-off-by line on those patches (please let me know if that is not appropriate). For convenience, the patches in this series may be pulled using: git pull git://github.com/robhoes/xen.git hydrogen-upstream-v2-rebased Cheers, Rob
Rob Hoes
2013-Aug-22 10:50 UTC
[PATCH v2-resend 01/30] libxl: Add LIBXL_SHUTDOWN_REASON_UNKNOWN
libxl_dominfo.shutdown_reason is valid iff (shutdown||dying). This is a bit annoying when generating language bindings since it needs all sorts of special casing. Just introduce an explicit value instead. Signed-off-by: Ian Campbell <ian.cambell@citrix.com> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/libxl/libxl.c | 2 +- tools/libxl/libxl_types.idl | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 81785df..7fba2ee 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -526,7 +526,7 @@ static void xcinfo2xlinfo(const xc_domaininfo_t *xcinfo, if (xlinfo->shutdown || xlinfo->dying) xlinfo->shutdown_reason = (xcinfo->flags>>XEN_DOMINF_shutdownshift) & XEN_DOMINF_shutdownmask; else - xlinfo->shutdown_reason = ~0; + xlinfo->shutdown_reason = LIBXL_SHUTDOWN_REASON_UNKNOWN; xlinfo->outstanding_memkb = PAGE_TO_MEMKB(xcinfo->outstanding_pages); xlinfo->current_memkb = PAGE_TO_MEMKB(xcinfo->tot_pages); diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 85341a0..0b0a3eb 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -118,14 +118,15 @@ libxl_scheduler = Enumeration("scheduler", [ (7, "arinc653"), ]) -# Consistent with SHUTDOWN_* in sched.h +# Consistent with SHUTDOWN_* in sched.h (apart from UNKNOWN) libxl_shutdown_reason = Enumeration("shutdown_reason", [ + (-1, "unknown"), (0, "poweroff"), (1, "reboot"), (2, "suspend"), (3, "crash"), (4, "watchdog"), - ]) + ], init_val = "LIBXL_SHUTDOWN_REASON_UNKNOWN") libxl_vga_interface_type = Enumeration("vga_interface_type", [ (1, "CIRRUS"), -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:50 UTC
[PATCH v2-resend 02/30] libxl: idl: allow KeyedUnion members to be empty
This is useful when the key enum has an "invalid" option and avoids the need to declare a dummy struct. Use this for domain_build_info resulting in the generated API changing like so: --- tools/libxl/_libxl_BACKUP_types.h +++ tools/libxl/_libxl_types.h @@ -377,8 +377,6 @@ typedef struct libxl_domain_build_info { const char * features; libxl_defbool e820_host; } pv; - struct { - } invalid; } u; } libxl_domain_build_info; void libxl_domain_build_info_dispose(libxl_domain_build_info *p); + a related change to the JSON generation. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/libxl/gentest.py | 3 ++- tools/libxl/gentypes.py | 11 ++++++++--- tools/libxl/libxl_types.idl | 2 +- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/tools/libxl/gentest.py b/tools/libxl/gentest.py index 84b4fd7..6fab493 100644 --- a/tools/libxl/gentest.py +++ b/tools/libxl/gentest.py @@ -46,7 +46,8 @@ def gen_rand_init(ty, v, indent = " ", parent = None): for f in ty.fields: (nparent,fexpr) = ty.member(v, f, parent is None) s += "case %s:\n" % f.enumname - s += gen_rand_init(f.type, fexpr, indent + " ", nparent) + 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) \ diff --git a/tools/libxl/gentypes.py b/tools/libxl/gentypes.py index 30f29ba..be06257 100644 --- a/tools/libxl/gentypes.py +++ b/tools/libxl/gentypes.py @@ -45,6 +45,8 @@ def libxl_C_type_define(ty, indent = ""): 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 @@ -67,7 +69,8 @@ def libxl_C_type_dispose(ty, v, indent = " ", parent = None): for f in ty.fields: (nparent,fexpr) = ty.member(v, f, parent is None) s += "case %s:\n" % f.enumname - s += libxl_C_type_dispose(f.type, fexpr, indent + " ", nparent) + 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): @@ -115,7 +118,8 @@ def _libxl_C_type_init(ty, v, indent = " ", parent = None, subinit=False): for f in ty.fields: (nparent,fexpr) = ty.member(v, f, parent is None) s += "case %s:\n" % f.enumname - s += _libxl_C_type_init(f.type, fexpr, " ", nparent) + if f.type is not None: + s += _libxl_C_type_init(f.type, fexpr, " ", nparent) s += " break;\n" s += "}\n" else: @@ -214,7 +218,8 @@ def libxl_C_type_gen_json(ty, v, indent = " ", parent = None): for f in ty.fields: (nparent,fexpr) = ty.member(v, f, parent is None) s += "case %s:\n" % f.enumname - s += libxl_C_type_gen_json(f.type, fexpr, indent + " ", nparent) + if f.type is not None: + s += libxl_C_type_gen_json(f.type, fexpr, indent + " ", nparent) s += " break;\n" s += "}\n" elif isinstance(ty, idl.Struct) and (parent is None or ty.json_fn is None): diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 0b0a3eb..027d066 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -349,7 +349,7 @@ libxl_domain_build_info = Struct("domain_build_info",[ # Use host''s E820 for PCI passthrough. ("e820_host", libxl_defbool), ])), - ("invalid", Struct(None, [])), + ("invalid", None), ], keyvar_init_val = "LIBXL_DOMAIN_TYPE_INVALID")), ], dir=DIR_IN ) -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:50 UTC
[PATCH v2-resend 03/30] libxl: idl: add domain_type field to libxl_dominfo struct
This allows a toolstack to find out whether a VM has booted as PV or HVM. Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/libxl/libxl.c | 2 ++ tools/libxl/libxl_types.idl | 1 + 2 files changed, 3 insertions(+) diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c index 7fba2ee..1bce4bb 100644 --- a/tools/libxl/libxl.c +++ b/tools/libxl/libxl.c @@ -537,6 +537,8 @@ static void xcinfo2xlinfo(const xc_domaininfo_t *xcinfo, xlinfo->vcpu_max_id = xcinfo->max_vcpu_id; xlinfo->vcpu_online = xcinfo->nr_online_vcpus; xlinfo->cpupool = xcinfo->cpupool; + xlinfo->domain_type = (xcinfo->flags & XEN_DOMINF_hvm_guest) ? + LIBXL_DOMAIN_TYPE_HVM : LIBXL_DOMAIN_TYPE_PV; } libxl_dominfo * libxl_list_domain(libxl_ctx *ctx, int *nb_domain_out) diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 027d066..c780a2d 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -209,6 +209,7 @@ libxl_dominfo = Struct("dominfo",[ ("vcpu_max_id", uint32), ("vcpu_online", uint32), ("cpupool", uint32), + ("domain_type", libxl_domain_type), ], dir=DIR_OUT) libxl_cpupoolinfo = Struct("cpupoolinfo", [ -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:50 UTC
[PATCH v2-resend 04/30] libxl: idl: complete some enums in the IDL with their defaults
There are several enums in the IDL that are initialised to 0, while the value 0 is not part of the enum itself. This creates problems for language bindings generated from the IDL, such as the OCaml ones. Added an explicit (0, "UNKNOWN") enum value where appropriate, or used init_val to default to a sensible value. Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/libxl/libxl_types.idl | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index c780a2d..47c925a 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -32,14 +32,16 @@ libxl_domain_type = Enumeration("domain_type", [ (-1, "INVALID"), (1, "HVM"), (2, "PV"), - ]) + ], init_val = -1) libxl_device_model_version = Enumeration("device_model_version", [ + (0, "UNKNOWN"), (1, "QEMU_XEN_TRADITIONAL"), # Historical qemu-xen device model (qemu-dm) (2, "QEMU_XEN"), # Upstream based qemu-xen device model ]) libxl_console_type = Enumeration("console_type", [ + (0, "UNKNOWN"), (1, "SERIAL"), (2, "PV"), ]) @@ -61,6 +63,7 @@ libxl_disk_backend = Enumeration("disk_backend", [ ]) libxl_nic_type = Enumeration("nic_type", [ + (0, "UNKNOWN"), (1, "VIF_IOEMU"), (2, "VIF"), ]) @@ -75,7 +78,7 @@ libxl_action_on_shutdown = Enumeration("action_on_shutdown", [ (5, "COREDUMP_DESTROY"), (6, "COREDUMP_RESTART"), - ]) + ], init_val = 1) libxl_trigger = Enumeration("trigger", [ (0, "UNKNOWN"), @@ -96,6 +99,7 @@ libxl_tsc_mode = Enumeration("tsc_mode", [ # Consistent with the values defined for HVM_PARAM_TIMER_MODE. libxl_timer_mode = Enumeration("timer_mode", [ + (-1, "unknown"), (0, "delay_for_missed_ticks"), (1, "no_delay_for_missed_ticks"), (2, "no_missed_ticks_pending"), @@ -103,6 +107,7 @@ libxl_timer_mode = Enumeration("timer_mode", [ ], init_val = "LIBXL_TIMER_MODE_DEFAULT") libxl_bios_type = Enumeration("bios_type", [ + (0, "unknown"), (1, "rombios"), (2, "seabios"), (3, "ovmf"), @@ -131,7 +136,7 @@ libxl_shutdown_reason = Enumeration("shutdown_reason", [ libxl_vga_interface_type = Enumeration("vga_interface_type", [ (1, "CIRRUS"), (2, "STD"), - ], init_val = 0) + ], init_val = 1) libxl_vendor_device = Enumeration("vendor_device", [ (0, "NONE"), -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:50 UTC
[PATCH v2-resend 05/30] libxl: ocaml: fix code intended to output comments before definitions
I''m not sure how useful these comments actually are but erred on the side of fixing rather than removing. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index ea978bf..5757218 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -79,12 +79,14 @@ def gen_ocaml_ml(ty, interface, indent=""): s = ("""(* %s interface *)\n""" % ty.typename) else: s = ("""(* %s implementation *)\n""" % ty.typename) + if isinstance(ty, idl.Enumeration): - s = "type %s = \n" % ty.rawname + s += "type %s = \n" % ty.rawname for v in ty.values: s += "\t | %s\n" % v.rawname elif isinstance(ty, idl.Aggregate): - s = "" + s += "" + if ty.typename is None: raise NotImplementedError("%s has no typename" % type(ty)) else: -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:50 UTC
[PATCH v2-resend 06/30] libxl: ocaml: support for Arrays in bindings generator.
No change in generated code because no arrays are currently generated. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index 5757218..1b68b6b 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -143,7 +143,14 @@ def c_val(ty, c, o, indent="", parent = None): raise NotImplementedError("No c_val fn for Builtin %s (%s)" % (ty.typename, type(ty))) s += "%s;" % (fn % { "o": o, "c": c }) elif isinstance (ty,idl.Array): - raise("Cannot handle Array type\n") + s += "{\n" + s += "\tint i;\n" + s += "\t%s = Wosize_val(%s);\n" % (parent + ty.lenvar.name, o) + s += "\t%s = (%s) calloc(%s, sizeof(*%s));\n" % (c, ty.typename, parent + ty.lenvar.name, c) + s += "\tfor(i=0; i<%s; i++) {\n" % (parent + ty.lenvar.name) + s += c_val(ty.elem_type, c+"[i]", "Field(%s, i)" % o, indent="\t\t", parent=parent) + "\n" + s += "\t}\n" + s += "}\n" elif isinstance(ty,idl.Enumeration) and (parent is None): n = 0 s += "switch(Int_val(%s)) {\n" % o @@ -207,7 +214,7 @@ def ocaml_Val(ty, o, c, indent="", parent = None): s += "\t value array_elem;\n" s += "\t %s = caml_alloc(%s,0);\n" % (o, parent + ty.lenvar.name) s += "\t for(i=0; i<%s; i++) {\n" % (parent + ty.lenvar.name) - s += "\t %s\n" % ocaml_Val(ty.elem_type, "array_elem", c + "[i]", "") + s += "\t %s\n" % ocaml_Val(ty.elem_type, "array_elem", c + "[i]", "", parent=parent) s += "\t Store_field(%s, i, array_elem);\n" % o s += "\t }\n" s += "\t}" -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:50 UTC
[PATCH v2-resend 07/30] libxl: ocaml: avoid reserved words in type and field names.
Current just s/type/ty/ and there are no such fields (yet) so no change to generated code. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index 1b68b6b..d76a007 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -70,8 +70,14 @@ def ocaml_type_of(ty): else: return ty.rawname +def munge_name(name): + if name == "type": + return "ty" + else: + return name + def ocaml_instance_of(type, name): - return "%s : %s" % (name, ocaml_type_of(type)) + return "%s : %s" % (munge_name(name), ocaml_type_of(type)) def gen_ocaml_ml(ty, interface, indent=""): -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:50 UTC
[PATCH v2-resend 08/30] libxl: ocaml: support for KeyedUnion in the bindings generator.
A KeyedUnion consists of two fields in the containing struct. First an enum field ("e") used as a descriminator and second a union ("u") containing potentially anonymous structs associated with each enum value. We map the anonymous structs to structs named after the descriminator field ("e") and the specific enum values. We then declare an ocaml variant type name e__union mapping each enum value to its associated struct. So given IDL: foo = Enumeration("foo", [ (0, "BAR"), (1, "BAZ"), ]) s = Struct("s", [ ("u", KeyedUnion(none, foo, "blargle", [ ("bar", Struct(...xxx...)), ("baz", Struct(...yyy...)), ])), ]) We generate C: enum { FOO, BAR } foo; struct s { enum foo blargle; union { struct { ...xxx... } bar; struct { ...yyy... } baz; } u; } and map this to ocaml type foo = BAR | BAZ; module S = struct type blargle_bar = ...xxx...; type blargle_baz = ...yyy...; type blargle__union = Bar of blargle_bar | Baz of blargle_baz; type t { blargle : blargle__union; } end These type names are OK because they are already within the namespace associated with the struct "s". If the struct associated with bar is empty then we don''t bother with blargle_bar of "of blargle_bar". No actually change in the generated code since we don''t generate any KeyedUnions yet. The actual implementation was inspired by http://www.linux-nantes.org/~fmonnier/ocaml/ocaml-wrapping-c.php#ref_constvrnt Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/libxl/idl.py | 3 + tools/ocaml/libs/xl/genwrap.py | 160 +++++++++++++++++++++++++++++++++++----- 2 files changed, 146 insertions(+), 17 deletions(-) diff --git a/tools/libxl/idl.py b/tools/libxl/idl.py index 7d95e3f..f4908dd 100644 --- a/tools/libxl/idl.py +++ b/tools/libxl/idl.py @@ -216,6 +216,9 @@ class Struct(Aggregate): 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 diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index d76a007..0c80e3d 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -65,6 +65,8 @@ def ocaml_type_of(ty): if not typename: raise NotImplementedError("No typename for Builtin %s (%s)" % (ty.typename, type(ty))) return typename + elif isinstance(ty,idl.KeyedUnion): + return ty.union_name elif isinstance(ty,idl.Aggregate): return ty.rawname.capitalize() + ".t" else: @@ -76,8 +78,67 @@ def munge_name(name): else: return name -def ocaml_instance_of(type, name): - return "%s : %s" % (munge_name(name), ocaml_type_of(type)) +def ocaml_instance_of_field(f): + if isinstance(f.type, idl.KeyedUnion): + name = f.type.keyvar.name + else: + name = f.name + return "%s : %s" % (munge_name(name), ocaml_type_of(f.type)) + +def gen_struct(ty): + s = "" + for f in ty.fields: + if f.type.private: + continue + x = ocaml_instance_of_field(f) + x = x.replace("\n", "\n\t\t") + s += "\t\t" + x + ";\n" + return s + +def gen_ocaml_keyedunions(ty, interface, indent, parent = None): + s = "" + + if ty.rawname is not None: + # Non-anonymous types need no special handling + pass + elif isinstance(ty, idl.KeyedUnion): + if parent is None: + nparent = ty.keyvar.name + else: + nparent = parent + "_" + ty.keyvar.name + + for f in ty.fields: + if f.type is None: continue + if f.type.rawname is not None: continue + if isinstance(f.type, idl.Struct) and not f.type.has_fields(): continue + s += "\ntype %s_%s =\n" % (nparent,f.name) + s += "{\n" + s += gen_struct(f.type) + s += "}\n" + + name = "%s__union" % ty.keyvar.name + s += "\n" + s += "type %s = " % name + u = [] + for f in ty.fields: + if f.type is None: + u.append("%s" % (f.name.capitalize())) + elif isinstance(f.type, idl.Struct): + if f.type.rawname is not None: + u.append("%s of %s" % (f.name.capitalize(), f.type.rawname.capitalize())) + elif f.type.has_fields(): + u.append("%s of %s_%s" % (f.name.capitalize(), nparent, f.name)) + else: + u.append("%s" % (f.name.capitalize())) + else: + raise NotImplementedError("Cannot handle KeyedUnion fields which are not Structs") + + s += " | ".join(u) + "\n" + ty.union_name = name + + if s == "": + return None + return s.replace("\n", "\n%s" % indent) def gen_ocaml_ml(ty, interface, indent=""): @@ -103,16 +164,17 @@ def gen_ocaml_ml(ty, interface, indent=""): s += "module %s : sig\n" % module_name else: s += "module %s = struct\n" % module_name - s += "\ttype t =\n" - s += "\t{\n" - + + # Handle KeyedUnions... for f in ty.fields: - if f.type.private: - continue - x = ocaml_instance_of(f.type, f.name) - x = x.replace("\n", "\n\t\t") - s += "\t\t" + x + ";\n" + ku = gen_ocaml_keyedunions(f.type, interface, "\t") + if ku is not None: + s += ku + s += "\n" + s += "\ttype t =\n" + s += "\t{\n" + s += gen_struct(ty) s += "\t}\n" if functions.has_key(ty.rawname): @@ -165,12 +227,43 @@ def c_val(ty, c, o, indent="", parent = None): n += 1 s += " default: failwith_xl(\"cannot convert value to %s\", lg); break;\n" % ty.typename s += "}" - elif isinstance(ty, idl.Aggregate) and (parent is None): + elif isinstance(ty, idl.KeyedUnion): + s += "{\n" + s += "\tif(Is_long(%s)) {\n" % o + n = 0 + s += "\t\tswitch(Int_val(%s)) {\n" % o + for f in ty.fields: + if f.type is None or not f.type.has_fields(): + s += "\t\t case %d: %s = %s; break;\n" % (n, + parent + ty.keyvar.name, + f.enumname) + n += 1 + s += "\t\t default: failwith_xl(\"variant handling bug %s%s (long)\", lg); break;\n" % (parent, ty.keyvar.name) + s += "\t\t}\n" + s += "\t} else {\n" + s += "\t\t/* Is block... */\n" + s += "\t\tswitch(Tag_val(%s)) {\n" % o + n = 0 + for f in ty.fields: + if f.type is not None and f.type.has_fields(): + if f.type.private: + continue + s += "\t\t case %d:\n" % (n) + s += "\t\t %s = %s;\n" % (parent + ty.keyvar.name, f.enumname) + (nparent,fexpr) = ty.member(c, f, False) + s += "%s" % c_val(f.type, fexpr, "Field(%s, 0)" % o, indent=indent+"\t\t ") + s += "break;\n" + n += 1 + s += "\t\t default: failwith_xl(\"variant handling bug %s%s (block)\", lg); break;\n" % (parent, ty.keyvar.name) + s += "\t\t}\n" + s += "\t}\n" + s += "}" + elif isinstance(ty, idl.Aggregate) and (parent is None or ty.rawname is None): n = 0 for f in ty.fields: if f.type.private: continue - (nparent,fexpr) = ty.member(c, f, parent is None) + (nparent,fexpr) = ty.member(c, f, ty.rawname is not None) s += "%s\n" % c_val(f.type, fexpr, "Field(%s, %d)" % (o,n), parent=nparent) n = n + 1 else: @@ -192,7 +285,7 @@ def gen_c_val(ty, indent=""): s += "}\n" return s.replace("\n", "\n%s" % indent) - + def ocaml_Val(ty, o, c, indent="", parent = None): s = indent if isinstance(ty,idl.UInt): @@ -232,9 +325,42 @@ def ocaml_Val(ty, o, c, indent="", parent = None): n += 1 s += " default: failwith_xl(\"cannot convert value from %s\", lg); break;\n" % ty.typename s += "}" - elif isinstance(ty,idl.Aggregate) and (parent is None): + elif isinstance(ty, idl.KeyedUnion): + n = 0 + m = 0 + s += "switch(%s) {\n" % (parent + ty.keyvar.name) + for f in ty.fields: + s += "\t case %s:\n" % f.enumname + if f.type is None: + s += "\t /* %d: None */\n" % n + s += "\t %s = Val_long(%d);\n" % (o,n) + n += 1 + elif not f.type.has_fields(): + s += "\t /* %d: Long */\n" % n + s += "\t %s = Val_long(%d);\n" % (o,n) + n += 1 + else: + s += "\t /* %d: Block */\n" % m + (nparent,fexpr) = ty.member(c, f, parent is None) + s += "\t {\n" + s += "\t\t CAMLlocal1(tmp);\n" + s += "\t\t %s = caml_alloc(%d,%d);\n" % (o, 1, m) + s += ocaml_Val(f.type, ''tmp'', fexpr, indent="\t\t ", parent=nparent) + s += "\n" + s += "\t\t Store_field(%s, 0, tmp);\n" % o + s += "\t }\n" + m += 1 + #s += "\t %s = caml_alloc(%d,%d);\n" % (o,len(f.type.fields),n) + s += "\t break;\n" + s += "\t default: failwith_xl(\"cannot convert value from %s\", lg); break;\n" % ty.typename + s += "\t}" + elif isinstance(ty,idl.Aggregate) and (parent is None or ty.rawname is None): s += "{\n" - s += "\tvalue %s_field;\n" % ty.rawname + if ty.rawname is None: + fn = "anon_field" + else: + fn = "%s_field" % ty.rawname + s += "\tvalue %s;\n" % fn s += "\n" s += "\t%s = caml_alloc_tuple(%d);\n" % (o, len(ty.fields)) @@ -246,8 +372,8 @@ def ocaml_Val(ty, o, c, indent="", parent = None): (nparent,fexpr) = ty.member(c, f, parent is None) s += "\n" - s += "\t%s\n" % ocaml_Val(f.type, "%s_field" % ty.rawname, ty.pass_arg(fexpr, c), parent=nparent) - s += "\tStore_field(%s, %d, %s);\n" % (o, n, "%s_field" % ty.rawname) + s += "\t%s\n" % ocaml_Val(f.type, fn, ty.pass_arg(fexpr, c), parent=nparent) + s += "\tStore_field(%s, %d, %s);\n" % (o, n, fn) n = n + 1 s += "}" else: -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:50 UTC
[PATCH v2-resend 09/30] libxl: ocaml: add some more builtin types.
* bitmaps * string_list * key_value_list * cpuid_policy_list (left "empty" for now) None of these are used yet, so no change to the generated code. Bitmap_val requires a ctx, so leave it as an abort for now. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 6 +- tools/ocaml/libs/xl/xenlight_stubs.c | 127 ++++++++++++++++++++++++++++++---- 2 files changed, 119 insertions(+), 14 deletions(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index 0c80e3d..05c4582 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -13,9 +13,13 @@ builtins = { "libxl_devid": ("devid", "%(c)s = Int_val(%(o)s)", "Val_int(%(c)s)" ), "libxl_defbool": ("bool option", "%(c)s = Defbool_val(%(o)s)", "Val_defbool(%(c)s)" ), "libxl_uuid": ("int array", "Uuid_val(gc, lg, &%(c)s, %(o)s)", "Val_uuid(&%(c)s)"), - "libxl_key_value_list": ("(string * string) list", None, None), + "libxl_bitmap": ("bool array", "Bitmap_val(gc, lg, &%(c)s, %(o)s)", "Val_bitmap(&%(c)s)"), + "libxl_key_value_list": ("(string * string) list", "libxl_key_value_list_val(gc, lg, &%(c)s, %(o)s)", "Val_key_value_list(&%(c)s)"), + "libxl_string_list": ("string list", "libxl_string_list_val(gc, lg, &%(c)s, %(o)s)", "Val_string_list(&%(c)s)"), "libxl_mac": ("int array", "Mac_val(gc, lg, &%(c)s, %(o)s)", "Val_mac(&%(c)s)"), "libxl_hwcap": ("int32 array", None, "Val_hwcap(&%(c)s)"), + # The following needs to be sorted out later + "libxl_cpuid_policy_list": ("unit", "%(c)s = 0", "Val_unit"), } DEVICE_FUNCTIONS = [ ("add", ["t", "domid", "unit"]), diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index 5f19a82..a7bf6ba 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -27,6 +27,7 @@ #include <string.h> #include <libxl.h> +#include <libxl_utils.h> struct caml_logger { struct xentoollog_logger logger; @@ -96,7 +97,6 @@ static void failwith_xl(char *fname, struct caml_logger *lg) caml_raise_with_string(*caml_named_value("xl.error"), s); } -#if 0 /* TODO: wrap libxl_domain_create(), these functions will be needed then */ static void * gc_calloc(caml_gc *gc, size_t nmemb, size_t size) { void *ptr; @@ -107,28 +107,103 @@ static void * gc_calloc(caml_gc *gc, size_t nmemb, size_t size) return ptr; } -static int string_string_tuple_array_val (caml_gc *gc, char ***c_val, value v) +static int list_len(value v) +{ + int len = 0; + while ( v != Val_emptylist ) { + len++; + v = Field(v, 1); + } + return len; +} + +static int libxl_key_value_list_val(caml_gc *gc, struct caml_logger *lg, + libxl_key_value_list *c_val, + value v) { CAMLparam1(v); - CAMLlocal1(a); - int i; - char **array; + CAMLlocal1(elem); + int nr, i; + libxl_key_value_list array; - for (i = 0, a = Field(v, 5); a != Val_emptylist; a = Field(a, 1)) { i++; } + nr = list_len(v); - array = gc_calloc(gc, (i + 1) * 2, sizeof(char *)); + array = gc_calloc(gc, (nr + 1) * 2, sizeof(char *)); if (!array) - return 1; - for (i = 0, a = Field(v, 5); a != Val_emptylist; a = Field(a, 1), i++) { - value b = Field(a, 0); - array[i * 2] = dup_String_val(gc, Field(b, 0)); - array[i * 2 + 1] = dup_String_val(gc, Field(b, 1)); + caml_raise_out_of_memory(); + + for (i=0; v != Val_emptylist; i++, v = Field(v, 1) ) { + elem = Field(v, 0); + + array[i * 2] = dup_String_val(gc, Field(elem, 0)); + array[i * 2 + 1] = dup_String_val(gc, Field(elem, 1)); } + *c_val = array; CAMLreturn(0); } -#endif +static value Val_key_value_list(libxl_key_value_list *c_val) +{ + CAMLparam0(); + CAMLlocal5(list, cons, key, val, kv); + int i; + + list = Val_emptylist; + for (i = libxl_string_list_length((libxl_string_list *) c_val) - 1; i >= 0; i -= 2) { + val = caml_copy_string((char *) c_val[i]); + key = caml_copy_string((char *) c_val[i - 1]); + kv = caml_alloc_tuple(2); + Store_field(kv, 0, key); + Store_field(kv, 1, val); + + cons = caml_alloc(2, 0); + Store_field(cons, 0, kv); // head + Store_field(cons, 1, list); // tail + list = cons; + } + + CAMLreturn(list); +} + +static int libxl_string_list_val(caml_gc *gc, struct caml_logger *lg, + libxl_string_list *c_val, + value v) +{ + CAMLparam1(v); + int nr, i; + libxl_string_list array; + + nr = list_len(v); + + array = gc_calloc(gc, (nr + 1), sizeof(char *)); + if (!array) + caml_raise_out_of_memory(); + + for (i=0; v != Val_emptylist; i++, v = Field(v, 1) ) + array[i] = dup_String_val(gc, Field(v, 0)); + + *c_val = array; + CAMLreturn(0); +} + +static value Val_string_list(libxl_string_list *c_val) +{ + CAMLparam0(); + CAMLlocal3(list, cons, string); + int i; + + list = Val_emptylist; + for (i = libxl_string_list_length(c_val) - 1; i >= 0; i--) { + string = caml_copy_string((char *) c_val[i]); + cons = caml_alloc(2, 0); + Store_field(cons, 0, string); // head + Store_field(cons, 1, list); // tail + list = cons; + } + + CAMLreturn(list); +} /* Option type support as per http://www.linux-nantes.org/~fmonnier/ocaml/ocaml-wrapping-c.php */ #define Val_none Val_int(0) @@ -168,6 +243,32 @@ static int Mac_val(caml_gc *gc, struct caml_logger *lg, libxl_mac *c_val, value CAMLreturn(0); } +static value Val_bitmap (libxl_bitmap *c_val) +{ + CAMLparam0(); + CAMLlocal1(v); + int i; + + if (c_val->size == 0) + v = Atom(0); + else { + v = caml_alloc(8 * (c_val->size), 0); + libxl_for_each_bit(i, *c_val) { + if (libxl_bitmap_test(c_val, i)) + Store_field(v, i, Val_true); + else + Store_field(v, i, Val_false); + } + } + CAMLreturn(v); +} + +static int Bitmap_val(caml_gc *gc, struct caml_logger *lg, + libxl_bitmap *c_val, value v) +{ + abort(); /* XXX */ +} + static value Val_uuid (libxl_uuid *c_val) { CAMLparam0(); -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:50 UTC
[PATCH v2-resend 10/30] libxc: ocaml: add simple binding for xentoollog (output only).
These bindings allow ocaml code to receive log message via xentoollog but do not support injecting messages into xentoollog from ocaml. Receiving log messages from libx{c,l} and forwarding them to ocaml is the use case which is needed by the following patches. Add a simple noddy test case (tools/ocaml/test). Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- .gitignore | 1 + .hgignore | 1 + tools/ocaml/Makefile | 2 +- tools/ocaml/Makefile.rules | 2 +- tools/ocaml/libs/Makefile | 1 + tools/ocaml/libs/xentoollog/META.in | 4 + tools/ocaml/libs/xentoollog/Makefile | 33 ++++ tools/ocaml/libs/xentoollog/caml_xentoollog.h | 24 +++ tools/ocaml/libs/xentoollog/xentoollog.ml | 98 +++++++++++ tools/ocaml/libs/xentoollog/xentoollog.mli | 53 ++++++ tools/ocaml/libs/xentoollog/xentoollog_stubs.c | 222 ++++++++++++++++++++++++ tools/ocaml/test/Makefile | 28 +++ tools/ocaml/test/xtl.ml | 19 ++ 13 files changed, 486 insertions(+), 2 deletions(-) create mode 100644 tools/ocaml/libs/xentoollog/META.in create mode 100644 tools/ocaml/libs/xentoollog/Makefile create mode 100644 tools/ocaml/libs/xentoollog/caml_xentoollog.h create mode 100644 tools/ocaml/libs/xentoollog/xentoollog.ml create mode 100644 tools/ocaml/libs/xentoollog/xentoollog.mli create mode 100644 tools/ocaml/libs/xentoollog/xentoollog_stubs.c create mode 100644 tools/ocaml/test/Makefile create mode 100644 tools/ocaml/test/xtl.ml diff --git a/.gitignore b/.gitignore index c82a372..61a27c6 100644 --- a/.gitignore +++ b/.gitignore @@ -382,6 +382,7 @@ tools/ocaml/libs/xl/_libxl_types.mli.in tools/ocaml/libs/xl/xenlight.ml tools/ocaml/libs/xl/xenlight.mli tools/ocaml/xenstored/oxenstored +tools/ocaml/test/xtl tools/debugger/kdd/kdd tools/firmware/etherboot/ipxe.tar.gz diff --git a/.hgignore b/.hgignore index 05cb0de..bb1b67d 100644 --- a/.hgignore +++ b/.hgignore @@ -308,6 +308,7 @@ ^tools/ocaml/libs/xl/xenlight\.ml$ ^tools/ocaml/libs/xl/xenlight\.mli$ ^tools/ocaml/xenstored/oxenstored$ +^tools/ocaml/test/xtl$ ^tools/autom4te\.cache$ ^tools/config\.h$ ^tools/config\.log$ diff --git a/tools/ocaml/Makefile b/tools/ocaml/Makefile index 6b22bbe..8e4ca36 100644 --- a/tools/ocaml/Makefile +++ b/tools/ocaml/Makefile @@ -1,7 +1,7 @@ XEN_ROOT = $(CURDIR)/../.. include $(XEN_ROOT)/tools/Rules.mk -SUBDIRS_PROGRAMS = xenstored +SUBDIRS_PROGRAMS = xenstored test SUBDIRS = libs $(SUBDIRS_PROGRAMS) diff --git a/tools/ocaml/Makefile.rules b/tools/ocaml/Makefile.rules index 5e6d81e..0745e83 100644 --- a/tools/ocaml/Makefile.rules +++ b/tools/ocaml/Makefile.rules @@ -24,7 +24,7 @@ ALL_OCAML_OBJS ?= $(OBJS) %.cmi: %.mli $(call quiet-command, $(OCAMLC) $(OCAMLCFLAGS) -c -o $@ $<,MLI,$@) -%.cmx: %.ml +%.cmx %.o: %.ml $(call quiet-command, $(OCAMLOPT) $(OCAMLOPTFLAGS) -c -o $@ $<,MLOPT,$@) %.ml: %.mll diff --git a/tools/ocaml/libs/Makefile b/tools/ocaml/libs/Makefile index bca0fa2..3afdc89 100644 --- a/tools/ocaml/libs/Makefile +++ b/tools/ocaml/libs/Makefile @@ -3,6 +3,7 @@ include $(XEN_ROOT)/tools/Rules.mk SUBDIRS= \ mmap \ + xentoollog \ xc eventchn \ xb xs xl diff --git a/tools/ocaml/libs/xentoollog/META.in b/tools/ocaml/libs/xentoollog/META.in new file mode 100644 index 0000000..7b06683 --- /dev/null +++ b/tools/ocaml/libs/xentoollog/META.in @@ -0,0 +1,4 @@ +version = "@VERSION@" +description = "Xen Tools Logger Interface" +archive(byte) = "xentoollog.cma" +archive(native) = "xentoollog.cmxa" diff --git a/tools/ocaml/libs/xentoollog/Makefile b/tools/ocaml/libs/xentoollog/Makefile new file mode 100644 index 0000000..17dca95 --- /dev/null +++ b/tools/ocaml/libs/xentoollog/Makefile @@ -0,0 +1,33 @@ +TOPLEVEL=$(CURDIR)/../.. +XEN_ROOT=$(TOPLEVEL)/../.. +include $(TOPLEVEL)/common.make + +CFLAGS += $(CFLAGS_libxenctrl) $(CFLAGS_libxenguest) +OCAMLINCLUDE ++ +OBJS = xentoollog +INTF = xentoollog.cmi +LIBS = xentoollog.cma xentoollog.cmxa + +LIBS_xentoollog = $(LDLIBS_libxenctrl) + +xentoollog_OBJS = $(OBJS) +xentoollog_C_OBJS = xentoollog_stubs + +OCAML_LIBRARY = xentoollog + +all: $(INTF) $(LIBS) + +libs: $(LIBS) + +.PHONY: install +install: $(LIBS) META + mkdir -p $(OCAMLDESTDIR) + ocamlfind remove -destdir $(OCAMLDESTDIR) xentoollog + ocamlfind install -destdir $(OCAMLDESTDIR) -ldconf ignore xentoollog META $(INTF) $(LIBS) *.a *.so *.cmx + +.PHONY: uninstall +uninstall: + ocamlfind remove -destdir $(OCAMLDESTDIR) xentoollog + +include $(TOPLEVEL)/Makefile.rules diff --git a/tools/ocaml/libs/xentoollog/caml_xentoollog.h b/tools/ocaml/libs/xentoollog/caml_xentoollog.h new file mode 100644 index 0000000..0eb7618 --- /dev/null +++ b/tools/ocaml/libs/xentoollog/caml_xentoollog.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2013 Citrix Ltd. + * Author Ian Campbell <ian.campbell@citrix.com> + * Author Rob Hoes <rob.hoes@citrix.com> + * + * 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. + */ + +struct caml_xtl { + xentoollog_logger vtable; + char *vmessage_cb; + char *progress_cb; +}; + +#define Xtl_val(x)(*((struct caml_xtl **) Data_custom_val(x))) + diff --git a/tools/ocaml/libs/xentoollog/xentoollog.ml b/tools/ocaml/libs/xentoollog/xentoollog.ml new file mode 100644 index 0000000..0be736c --- /dev/null +++ b/tools/ocaml/libs/xentoollog/xentoollog.ml @@ -0,0 +1,98 @@ +(* + * Copyright (C) 2012 Citrix Ltd. + * Author Ian Campbell <ian.campbell@citrix.com> + * + * 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. + *) + +open Printf +open Random +open Callback + +type level = Debug + | Verbose + | Detail + | Progress + | Info + | Notice + | Warn + | Error + | Critical + +let level_to_string level + match level with + | Debug -> "Debug" + | Verbose -> "Verbose" + | Detail -> "Detail" + | Progress -> "Progress" + | Info -> "Info" + | Notice -> "Notice" + | Warn -> "Warn" + | Error -> "Error" + | Critical -> "Critical" + +let level_to_prio level = + match level with + | Debug -> 0 + | Verbose -> 1 + | Detail -> 2 + | Progress -> 3 + | Info -> 4 + | Notice -> 5 + | Warn -> 6 + | Error -> 7 + | Critical -> 8 + +let compare_level x y + compare (level_to_prio x) (level_to_prio y) + +type handle + +type logger_cbs = { + vmessage : level -> int option -> string option -> string -> unit; + progress : string option -> string -> int -> int64 -> int64 -> unit; + (*destroy : unit -> unit*) +} + +external _create_logger: (string * string) -> handle = "stub_xtl_create_logger" +external test: handle -> unit = "stub_xtl_test" + +let create name cbs : handle + (* Callback names are supposed to be unique *) + let suffix = string_of_int (Random.int 1000000) in + let vmessage_name = sprintf "%s_vmessage_%s" name suffix in + let progress_name = sprintf "%s_progress_%s" name suffix in + (*let destroy_name = sprintf "%s_destroy" name in*) + Callback.register vmessage_name cbs.vmessage; + Callback.register progress_name cbs.progress; + _create_logger (vmessage_name, progress_name) + + +let stdio_vmessage min_level level errno ctx msg + let level_str = level_to_string level + and errno_str = match errno with None -> "" | Some s -> sprintf ": errno=%d" s + and ctx_str = match ctx with None -> "" | Some s -> sprintf ": %s" s in + if compare min_level level <= 0 then begin + printf "%s%s%s: %s\n" level_str ctx_str errno_str msg; + flush stdout; + end + +let stdio_progress ctx what percent dne total + let nl = if dne = total then "\n" else "" in + printf "\rProgress %s %d%% (%Ld/%Ld)%s" what percent dne total nl; + flush stdout + +let create_stdio_logger ?(level=Info) () + let cbs = { + vmessage = stdio_vmessage level; + progress = stdio_progress; } in + create "Xentoollog.stdio_logger" cbs + diff --git a/tools/ocaml/libs/xentoollog/xentoollog.mli b/tools/ocaml/libs/xentoollog/xentoollog.mli new file mode 100644 index 0000000..c5c4f59 --- /dev/null +++ b/tools/ocaml/libs/xentoollog/xentoollog.mli @@ -0,0 +1,53 @@ +(* + * Copyright (C) 2012 Citrix Ltd. + * Author Ian Campbell <ian.campbell@citrix.com> + * + * 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. + *) + +type level + | Debug + | Verbose + | Detail + | Progress (* also used for "progress" messages *) + | Info + | Notice + | Warn + | Error + | Critical + +val level_to_string : level -> string +val compare_level : level -> level -> int + +type handle + +(** call back arguments. See xentoollog.h for more info. + vmessage: + level: level as above + errno: Some <errno> or None + context: Some <string> or None + message: The log message (already formatted) + progress: + context: Some <string> or None + doing_what: string + percent, done, total. +*) +type logger_cbs = { + vmessage : level -> int option -> string option -> string -> unit; + progress : string option -> string -> int -> int64 -> int64 -> unit; + (*destroy : handle -> unit*) +} + +external test: handle -> unit = "stub_xtl_test" + +val create : string -> logger_cbs -> handle +val create_stdio_logger : ?level:level -> unit -> handle + diff --git a/tools/ocaml/libs/xentoollog/xentoollog_stubs.c b/tools/ocaml/libs/xentoollog/xentoollog_stubs.c new file mode 100644 index 0000000..c6430b1 --- /dev/null +++ b/tools/ocaml/libs/xentoollog/xentoollog_stubs.c @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2012 Citrix Ltd. + * Author Ian Campbell <ian.campbell@citrix.com> + * + * 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. + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#define CAML_NAME_SPACE +#include <caml/alloc.h> +#include <caml/memory.h> +#include <caml/signals.h> +#include <caml/fail.h> +#include <caml/callback.h> +#include <caml/custom.h> + +#include <xentoollog.h> + +#include "caml_xentoollog.h" + +#define XTL ((xentoollog_logger *) Xtl_val(handle)) + +static char * dup_String_val(value s) +{ + int len; + char *c; + len = caml_string_length(s); + c = calloc(len + 1, sizeof(char)); + if (!c) + caml_raise_out_of_memory(); + memcpy(c, String_val(s), len); + return c; +} + +static value Val_level(xentoollog_level c_level) +{ + /* Must correspond to order in .mli */ + switch (c_level) { + case XTL_NONE: /* Not a real value */ + caml_raise_sys_error(caml_copy_string("Val_level XTL_NONE")); + break; + case XTL_DEBUG: return Val_int(0); + case XTL_VERBOSE: return Val_int(1); + case XTL_DETAIL: return Val_int(2); + case XTL_PROGRESS: return Val_int(3); + case XTL_INFO: return Val_int(4); + case XTL_NOTICE: return Val_int(5); + case XTL_WARN: return Val_int(6); + case XTL_ERROR: return Val_int(7); + case XTL_CRITICAL: return Val_int(8); + case XTL_NUM_LEVELS: /* Not a real value! */ + caml_raise_sys_error( + caml_copy_string("Val_level XTL_NUM_LEVELS")); +#if 0 /* Let the compiler catch this */ + default: + caml_raise_sys_error(caml_copy_string("Val_level Unknown")); + break; +#endif + } + abort(); +} + +/* Option type support as per http://www.linux-nantes.org/~fmonnier/ocaml/ocaml-wrapping-c.php */ +#define Val_none Val_int(0) +#define Some_val(v) Field(v,0) + +static value Val_some(value v) +{ + CAMLparam1(v); + CAMLlocal1(some); + some = caml_alloc(1, 0); + Store_field(some, 0, v); + CAMLreturn(some); +} + +static value Val_errno(int errnoval) +{ + if (errnoval == -1) + return Val_none; + return Val_some(Val_int(errnoval)); +} + +static value Val_context(const char *context) +{ + if (context == NULL) + return Val_none; + return Val_some(caml_copy_string(context)); +} + +static void stub_xtl_ocaml_vmessage(struct xentoollog_logger *logger, + xentoollog_level level, + int errnoval, + const char *context, + const char *format, + va_list al) +{ + CAMLparam0(); + CAMLlocalN(args, 4); + struct caml_xtl *xtl = (struct caml_xtl*)logger; + value *func = caml_named_value(xtl->vmessage_cb) ; + char *msg; + + if (args == NULL) + caml_raise_out_of_memory(); + if (func == NULL) + caml_raise_sys_error(caml_copy_string("Unable to find callback")); + if (vasprintf(&msg, format, al) < 0) + caml_raise_out_of_memory(); + + /* vmessage : level -> int option -> string option -> string -> unit; */ + args[0] = Val_level(level); + args[1] = Val_errno(errnoval); + args[2] = Val_context(context); + args[3] = caml_copy_string(msg); + + free(msg); + + caml_callbackN(*func, 4, args); + CAMLreturn0; +} + +static void stub_xtl_ocaml_progress(struct xentoollog_logger *logger, + const char *context, + const char *doing_what /* no \r,\n */, + int percent, unsigned long done, unsigned long total) +{ + CAMLparam0(); + CAMLlocalN(args, 5); + struct caml_xtl *xtl = (struct caml_xtl*)logger; + value *func = caml_named_value(xtl->progress_cb) ; + + if (args == NULL) + caml_raise_out_of_memory(); + if (func == NULL) + caml_raise_sys_error(caml_copy_string("Unable to find callback")); + + /* progress : string option -> string -> int -> int64 -> int64 -> unit; */ + args[0] = Val_context(context); + args[1] = caml_copy_string(doing_what); + args[2] = Val_int(percent); + args[3] = caml_copy_int64(done); + args[4] = caml_copy_int64(total); + + caml_callbackN(*func, 5, args); + CAMLreturn0; +} + +static void xtl_destroy(struct xentoollog_logger *logger) +{ + struct caml_xtl *xtl = (struct caml_xtl*)logger; + free(xtl->vmessage_cb); + free(xtl->progress_cb); + free(xtl); +} + +void xtl_finalize(value handle) +{ + xtl_destroy(XTL); +} + +static struct custom_operations xentoollogger_custom_operations = { + "xentoollogger_custom_operations", + xtl_finalize /* custom_finalize_default */, + custom_compare_default, + custom_hash_default, + custom_serialize_default, + custom_deserialize_default +}; + +/* external _create_logger: (string * string) -> handle = "stub_xtl_create_logger" */ +CAMLprim value stub_xtl_create_logger(value cbs) +{ + CAMLparam1(cbs); + CAMLlocal1(handle); + struct caml_xtl *xtl = malloc(sizeof(*xtl)); + if (xtl == NULL) + caml_raise_out_of_memory(); + + memset(xtl, 0, sizeof(*xtl)); + + xtl->vtable.vmessage = &stub_xtl_ocaml_vmessage; + xtl->vtable.progress = &stub_xtl_ocaml_progress; + xtl->vtable.destroy = &xtl_destroy; + + xtl->vmessage_cb = dup_String_val(Field(cbs, 0)); + xtl->progress_cb = dup_String_val(Field(cbs, 1)); + + handle = caml_alloc_custom(&xentoollogger_custom_operations, sizeof(xtl), 0, 1); + Xtl_val(handle) = xtl; + + CAMLreturn(handle); +} + +/* external test: handle -> unit = "stub_xtl_test" */ +CAMLprim value stub_xtl_test(value handle) +{ + unsigned long l; + CAMLparam1(handle); + xtl_log(XTL, XTL_DEBUG, -1, "debug", "%s -- debug", __func__); + xtl_log(XTL, XTL_INFO, -1, "test", "%s -- test 1", __func__); + xtl_log(XTL, XTL_INFO, ENOSYS, "test errno", "%s -- test 2", __func__); + xtl_log(XTL, XTL_CRITICAL, -1, "critical", "%s -- critical", __func__); + for (l = 0UL; l<=100UL; l += 10UL) { + xtl_progress(XTL, "progress", "testing", l, 100UL); + usleep(10000); + } + CAMLreturn(Val_unit); +} + diff --git a/tools/ocaml/test/Makefile b/tools/ocaml/test/Makefile new file mode 100644 index 0000000..980054c --- /dev/null +++ b/tools/ocaml/test/Makefile @@ -0,0 +1,28 @@ +XEN_ROOT = $(CURDIR)/../../.. +OCAML_TOPLEVEL = $(CURDIR)/.. +include $(OCAML_TOPLEVEL)/common.make + +OCAMLINCLUDE += \ + -I $(OCAML_TOPLEVEL)/libs/xentoollog + +OBJS = xtl + +PROGRAMS = xtl + +xtl_LIBS = \ + -ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/xentoollog $(OCAML_TOPLEVEL)/libs/xentoollog/xentoollog.cmxa \ + -cclib -lxenctrl + +xtl_OBJS = xtl + +OCAML_PROGRAM = xtl + +all: $(PROGRAMS) + +bins: $(PROGRAMS) + +install: all + $(INSTALL_DIR) $(DESTDIR)$(BINDIR) + $(INSTALL_PROG) $(PROGRAMS) $(DESTDIR)$(BINDIR) + +include $(OCAML_TOPLEVEL)/Makefile.rules diff --git a/tools/ocaml/test/xtl.ml b/tools/ocaml/test/xtl.ml new file mode 100644 index 0000000..3a1df82 --- /dev/null +++ b/tools/ocaml/test/xtl.ml @@ -0,0 +1,19 @@ +open Arg +open Xentoollog + +let do_test level = + let lgr = Xentoollog.create_stdio_logger ~level:level () in + begin + Xentoollog.test lgr; + end + +let () + let debug_level = ref Xentoollog.Info in + let speclist = [ + ("-v", Arg.Unit (fun () -> debug_level := Xentoollog.Debug), "Verbose"); + ("-q", Arg.Unit (fun () -> debug_level := Xentoollog.Critical), "Quiet"); + ] in + let usage_msg = "usage: xtl [OPTIONS]" in + Arg.parse speclist (fun s -> ()) usage_msg; + + do_test !debug_level -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:50 UTC
[PATCH v2-resend 11/30] libxl: ocaml: allocate a long lived libxl context.
Rather than allocating a new context for every libxl call begin to switch to a model where a context is allocated by the caller and may then be used for multiple calls down into the library. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/META.in | 1 + tools/ocaml/libs/xl/Makefile | 3 +++ tools/ocaml/libs/xl/xenlight.ml.in | 4 ++++ tools/ocaml/libs/xl/xenlight.mli.in | 4 ++++ tools/ocaml/libs/xl/xenlight_stubs.c | 42 +++++++++++++++++++++++++++++++++- 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/tools/ocaml/libs/xl/META.in b/tools/ocaml/libs/xl/META.in index fe2c60b..3f0c552 100644 --- a/tools/ocaml/libs/xl/META.in +++ b/tools/ocaml/libs/xl/META.in @@ -1,4 +1,5 @@ version = "@VERSION@" description = "Xen Toolstack Library" +requires = "xentoollog" archive(byte) = "xenlight.cma" archive(native) = "xenlight.cmxa" diff --git a/tools/ocaml/libs/xl/Makefile b/tools/ocaml/libs/xl/Makefile index c9e5274..6917a20 100644 --- a/tools/ocaml/libs/xl/Makefile +++ b/tools/ocaml/libs/xl/Makefile @@ -5,11 +5,14 @@ include $(TOPLEVEL)/common.make # ignore unused generated functions CFLAGS += -Wno-unused CFLAGS += $(CFLAGS_libxenlight) +CFLAGS += -I ../xentoollog OBJS = xenlight INTF = xenlight.cmi LIBS = xenlight.cma xenlight.cmxa +OCAMLINCLUDE += -I ../xentoollog + LIBS_xenlight = $(LDLIBS_libxenlight) xenlight_OBJS = $(OBJS) diff --git a/tools/ocaml/libs/xl/xenlight.ml.in b/tools/ocaml/libs/xl/xenlight.ml.in index dcc1a38..3d663d8 100644 --- a/tools/ocaml/libs/xl/xenlight.ml.in +++ b/tools/ocaml/libs/xl/xenlight.ml.in @@ -20,6 +20,10 @@ type devid = int (* @@LIBXL_TYPES@@ *) +type ctx + +external ctx_alloc: Xentoollog.handle -> ctx = "stub_libxl_ctx_alloc" + external send_trigger : domid -> trigger -> int -> unit = "stub_xl_send_trigger" external send_sysrq : domid -> char -> unit = "stub_xl_send_sysrq" external send_debug_keys : domid -> string -> unit = "stub_xl_send_debug_keys" diff --git a/tools/ocaml/libs/xl/xenlight.mli.in b/tools/ocaml/libs/xl/xenlight.mli.in index 3fd0165..96d859c 100644 --- a/tools/ocaml/libs/xl/xenlight.mli.in +++ b/tools/ocaml/libs/xl/xenlight.mli.in @@ -20,6 +20,10 @@ type devid = int (* @@LIBXL_TYPES@@ *) +type ctx + +external ctx_alloc: Xentoollog.handle -> ctx = "stub_libxl_ctx_alloc" + external send_trigger : domid -> trigger -> int -> unit = "stub_xl_send_trigger" external send_sysrq : domid -> char -> unit = "stub_xl_send_sysrq" external send_debug_keys : domid -> string -> unit = "stub_xl_send_debug_keys" diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index a7bf6ba..65e9a4a 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -21,6 +21,7 @@ #include <caml/signals.h> #include <caml/fail.h> #include <caml/callback.h> +#include <caml/custom.h> #include <sys/mman.h> #include <stdint.h> @@ -29,6 +30,11 @@ #include <libxl.h> #include <libxl_utils.h> +#include "caml_xentoollog.h" + +#define Ctx_val(x)(*((libxl_ctx **) Data_custom_val(x))) +#define CTX ((libxl_ctx *) Ctx_val(ctx)) + struct caml_logger { struct xentoollog_logger logger; int log_offset; @@ -59,6 +65,8 @@ static void log_destroy(struct xentoollog_logger *logger) lg.logger.vmessage = log_vmessage; \ lg.logger.destroy = log_destroy; \ lg.logger.progress = NULL; \ + lg.log_offset = 0; \ + memset(&lg.log_buf,0,sizeof(lg.log_buf)); \ caml_enter_blocking_section(); \ ret = libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, (struct xentoollog_logger *) &lg); \ if (ret != 0) \ @@ -77,7 +85,7 @@ static char * dup_String_val(caml_gc *gc, value s) c = calloc(len + 1, sizeof(char)); if (!c) caml_raise_out_of_memory(); - gc->ptrs[gc->offset++] = c; + if (gc) gc->ptrs[gc->offset++] = c; memcpy(c, String_val(s), len); return c; } @@ -94,9 +102,41 @@ static void failwith_xl(char *fname, struct caml_logger *lg) { char *s; s = (lg) ? lg->log_buf : fname; + printf("Error: %s\n", fname); caml_raise_with_string(*caml_named_value("xl.error"), s); } +void ctx_finalize(value ctx) +{ + libxl_ctx_free(CTX); +} + +static struct custom_operations libxl_ctx_custom_operations = { + "libxl_ctx_custom_operations", + ctx_finalize /* custom_finalize_default */, + custom_compare_default, + custom_hash_default, + custom_serialize_default, + custom_deserialize_default +}; + +CAMLprim value stub_libxl_ctx_alloc(value logger) +{ + CAMLparam1(logger); + CAMLlocal1(handle); + libxl_ctx *ctx; + int ret; + + ret = libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, (xentoollog_logger *) Xtl_val(logger)); + if (ret != 0) \ + failwith_xl("cannot init context", NULL); + + handle = caml_alloc_custom(&libxl_ctx_custom_operations, sizeof(ctx), 0, 1); + Ctx_val(handle) = ctx; + + CAMLreturn(handle); +} + static void * gc_calloc(caml_gc *gc, size_t nmemb, size_t size) { void *ptr; -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 12/30] libxl: ocaml: switch all functions over to take a context.
Since the context has a logger we can get rid of the logger built into these bindings and use the xentoollog bindings instead. The gc is of limited use when most things are freed with libxl_FOO_dispose, so get rid of that too. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 44 ++-- tools/ocaml/libs/xl/xenlight.ml.in | 11 +- tools/ocaml/libs/xl/xenlight.mli.in | 9 +- tools/ocaml/libs/xl/xenlight_stubs.c | 477 +++++++++------------------------- 4 files changed, 153 insertions(+), 388 deletions(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index 05c4582..b617cb5 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -8,23 +8,23 @@ import idl builtins = { "bool": ("bool", "%(c)s = Bool_val(%(o)s)", "Val_bool(%(c)s)" ), "int": ("int", "%(c)s = Int_val(%(o)s)", "Val_int(%(c)s)" ), - "char *": ("string", "%(c)s = dup_String_val(gc, %(o)s)", "caml_copy_string(%(c)s)"), + "char *": ("string", "%(c)s = dup_String_val(%(o)s)", "caml_copy_string(%(c)s)"), "libxl_domid": ("domid", "%(c)s = Int_val(%(o)s)", "Val_int(%(c)s)" ), "libxl_devid": ("devid", "%(c)s = Int_val(%(o)s)", "Val_int(%(c)s)" ), "libxl_defbool": ("bool option", "%(c)s = Defbool_val(%(o)s)", "Val_defbool(%(c)s)" ), - "libxl_uuid": ("int array", "Uuid_val(gc, lg, &%(c)s, %(o)s)", "Val_uuid(&%(c)s)"), - "libxl_bitmap": ("bool array", "Bitmap_val(gc, lg, &%(c)s, %(o)s)", "Val_bitmap(&%(c)s)"), - "libxl_key_value_list": ("(string * string) list", "libxl_key_value_list_val(gc, lg, &%(c)s, %(o)s)", "Val_key_value_list(&%(c)s)"), - "libxl_string_list": ("string list", "libxl_string_list_val(gc, lg, &%(c)s, %(o)s)", "Val_string_list(&%(c)s)"), - "libxl_mac": ("int array", "Mac_val(gc, lg, &%(c)s, %(o)s)", "Val_mac(&%(c)s)"), + "libxl_uuid": ("int array", "Uuid_val(&%(c)s, %(o)s)", "Val_uuid(&%(c)s)"), + "libxl_bitmap": ("bool array", "Bitmap_val(ctx, &%(c)s, %(o)s)", "Val_bitmap(&%(c)s)"), + "libxl_key_value_list": ("(string * string) list", "libxl_key_value_list_val(&%(c)s, %(o)s)", "Val_key_value_list(&%(c)s)"), + "libxl_string_list": ("string list", "libxl_string_list_val(&%(c)s, %(o)s)", "Val_string_list(&%(c)s)"), + "libxl_mac": ("int array", "Mac_val(&%(c)s, %(o)s)", "Val_mac(&%(c)s)"), "libxl_hwcap": ("int32 array", None, "Val_hwcap(&%(c)s)"), # The following needs to be sorted out later "libxl_cpuid_policy_list": ("unit", "%(c)s = 0", "Val_unit"), } -DEVICE_FUNCTIONS = [ ("add", ["t", "domid", "unit"]), - ("remove", ["t", "domid", "unit"]), - ("destroy", ["t", "domid", "unit"]), +DEVICE_FUNCTIONS = [ ("add", ["ctx", "t", "domid", "unit"]), + ("remove", ["ctx", "t", "domid", "unit"]), + ("destroy", ["ctx", "t", "domid", "unit"]), ] functions = { # ( name , [type1,type2,....] ) @@ -33,13 +33,13 @@ functions = { # ( name , [type1,type2,....] ) "device_disk": DEVICE_FUNCTIONS, "device_nic": DEVICE_FUNCTIONS, "device_pci": DEVICE_FUNCTIONS, - "physinfo": [ ("get", ["unit", "t"]), + "physinfo": [ ("get", ["ctx", "t"]), ], - "cputopology": [ ("get", ["unit", "t array"]), + "cputopology": [ ("get", ["ctx", "t array"]), ], "domain_sched_params": - [ ("get", ["domid", "t"]), - ("set", ["domid", "t", "unit"]), + [ ("get", ["ctx", "domid", "t"]), + ("set", ["ctx", "domid", "t", "unit"]), ], } def stub_fn_name(ty, name): @@ -229,7 +229,7 @@ def c_val(ty, c, o, indent="", parent = None): for e in ty.values: s += " case %d: *%s = %s; break;\n" % (n, c, e.name) n += 1 - s += " default: failwith_xl(\"cannot convert value to %s\", lg); break;\n" % ty.typename + s += " default: failwith_xl(\"cannot convert value to %s\"); break;\n" % ty.typename s += "}" elif isinstance(ty, idl.KeyedUnion): s += "{\n" @@ -242,7 +242,7 @@ def c_val(ty, c, o, indent="", parent = None): parent + ty.keyvar.name, f.enumname) n += 1 - s += "\t\t default: failwith_xl(\"variant handling bug %s%s (long)\", lg); break;\n" % (parent, ty.keyvar.name) + s += "\t\t default: failwith_xl(\"variant handling bug %s%s (long)\"); break;\n" % (parent, ty.keyvar.name) s += "\t\t}\n" s += "\t} else {\n" s += "\t\t/* Is block... */\n" @@ -258,7 +258,7 @@ def c_val(ty, c, o, indent="", parent = None): s += "%s" % c_val(f.type, fexpr, "Field(%s, 0)" % o, indent=indent+"\t\t ") s += "break;\n" n += 1 - s += "\t\t default: failwith_xl(\"variant handling bug %s%s (block)\", lg); break;\n" % (parent, ty.keyvar.name) + s += "\t\t default: failwith_xl(\"variant handling bug %s%s (block)\"); break;\n" % (parent, ty.keyvar.name) s += "\t\t}\n" s += "\t}\n" s += "}" @@ -271,14 +271,14 @@ def c_val(ty, c, o, indent="", parent = None): s += "%s\n" % c_val(f.type, fexpr, "Field(%s, %d)" % (o,n), parent=nparent) n = n + 1 else: - s += "%s_val(gc, lg, %s, %s);" % (ty.rawname, ty.pass_arg(c, parent is None, passby=idl.PASS_BY_REFERENCE), o) + s += "%s_val(ctx, %s, %s);" % (ty.rawname, ty.pass_arg(c, parent is None, passby=idl.PASS_BY_REFERENCE), o) return s.replace("\n", "\n%s" % indent) def gen_c_val(ty, indent=""): s = "/* Convert caml value to %s */\n" % ty.rawname - s += "static int %s_val (caml_gc *gc, struct caml_logger *lg, %s, value v)\n" % (ty.rawname, ty.make_arg("c_val", passby=idl.PASS_BY_REFERENCE)) + s += "static int %s_val (libxl_ctx *ctx, %s, value v)\n" % (ty.rawname, ty.make_arg("c_val", passby=idl.PASS_BY_REFERENCE)) s += "{\n" s += "\tCAMLparam1(v);\n" s += "\n" @@ -327,7 +327,7 @@ def ocaml_Val(ty, o, c, indent="", parent = None): for e in ty.values: s += " case %s: %s = Int_val(%d); break;\n" % (e.name, o, n) n += 1 - s += " default: failwith_xl(\"cannot convert value from %s\", lg); break;\n" % ty.typename + s += " default: failwith_xl(\"cannot convert value from %s\"); break;\n" % ty.typename s += "}" elif isinstance(ty, idl.KeyedUnion): n = 0 @@ -356,7 +356,7 @@ def ocaml_Val(ty, o, c, indent="", parent = None): m += 1 #s += "\t %s = caml_alloc(%d,%d);\n" % (o,len(f.type.fields),n) s += "\t break;\n" - s += "\t default: failwith_xl(\"cannot convert value from %s\", lg); break;\n" % ty.typename + s += "\t default: failwith_xl(\"cannot convert value from %s\"); break;\n" % ty.typename s += "\t}" elif isinstance(ty,idl.Aggregate) and (parent is None or ty.rawname is None): s += "{\n" @@ -381,14 +381,14 @@ def ocaml_Val(ty, o, c, indent="", parent = None): n = n + 1 s += "}" else: - s += "%s = Val_%s(gc, lg, %s);" % (o, ty.rawname, ty.pass_arg(c, parent is None)) + s += "%s = Val_%s(%s);" % (o, ty.rawname, ty.pass_arg(c, parent is None)) return s.replace("\n", "\n%s" % indent).rstrip(indent) def gen_Val_ocaml(ty, indent=""): s = "/* Convert %s to a caml value */\n" % ty.rawname - s += "static value Val_%s (caml_gc *gc, struct caml_logger *lg, %s)\n" % (ty.rawname, ty.make_arg(ty.rawname+"_c")) + s += "static value Val_%s (%s)\n" % (ty.rawname, ty.make_arg(ty.rawname+"_c")) s += "{\n" s += "\tCAMLparam0();\n" s += "\tCAMLlocal1(%s_ocaml);\n" % ty.rawname diff --git a/tools/ocaml/libs/xl/xenlight.ml.in b/tools/ocaml/libs/xl/xenlight.ml.in index 3d663d8..dffba72 100644 --- a/tools/ocaml/libs/xl/xenlight.ml.in +++ b/tools/ocaml/libs/xl/xenlight.ml.in @@ -15,17 +15,16 @@ exception Error of string +type ctx type domid = int type devid = int (* @@LIBXL_TYPES@@ *) -type ctx - external ctx_alloc: Xentoollog.handle -> ctx = "stub_libxl_ctx_alloc" -external send_trigger : domid -> trigger -> int -> unit = "stub_xl_send_trigger" -external send_sysrq : domid -> char -> unit = "stub_xl_send_sysrq" -external send_debug_keys : domid -> string -> unit = "stub_xl_send_debug_keys" +external send_trigger : ctx -> domid -> trigger -> int -> unit = "stub_xl_send_trigger" +external send_sysrq : ctx -> domid -> char -> unit = "stub_xl_send_sysrq" +external send_debug_keys : ctx -> string -> unit = "stub_xl_send_debug_keys" -let _ = Callback.register_exception "xl.error" (Error "register_callback") +let _ = Callback.register_exception "Xenlight.Error" (Error("")) diff --git a/tools/ocaml/libs/xl/xenlight.mli.in b/tools/ocaml/libs/xl/xenlight.mli.in index 96d859c..e2686bb 100644 --- a/tools/ocaml/libs/xl/xenlight.mli.in +++ b/tools/ocaml/libs/xl/xenlight.mli.in @@ -15,15 +15,14 @@ exception Error of string +type ctx type domid = int type devid = int (* @@LIBXL_TYPES@@ *) -type ctx - external ctx_alloc: Xentoollog.handle -> ctx = "stub_libxl_ctx_alloc" -external send_trigger : domid -> trigger -> int -> unit = "stub_xl_send_trigger" -external send_sysrq : domid -> char -> unit = "stub_xl_send_sysrq" -external send_debug_keys : domid -> string -> unit = "stub_xl_send_debug_keys" +external send_trigger : ctx -> domid -> trigger -> int -> unit = "stub_xl_send_trigger" +external send_sysrq : ctx -> domid -> char -> unit = "stub_xl_send_sysrq" +external send_debug_keys : ctx -> string -> unit = "stub_xl_send_debug_keys" diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index 65e9a4a..062f65b 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -35,49 +35,7 @@ #define Ctx_val(x)(*((libxl_ctx **) Data_custom_val(x))) #define CTX ((libxl_ctx *) Ctx_val(ctx)) -struct caml_logger { - struct xentoollog_logger logger; - int log_offset; - char log_buf[2048]; -}; - -typedef struct caml_gc { - int offset; - void *ptrs[64]; -} caml_gc; - -static void log_vmessage(struct xentoollog_logger *logger, xentoollog_level level, - int errnoval, const char *context, const char *format, va_list al) -{ - struct caml_logger *ologger = (struct caml_logger *) logger; - - ologger->log_offset += vsnprintf(ologger->log_buf + ologger->log_offset, - 2048 - ologger->log_offset, format, al); -} - -static void log_destroy(struct xentoollog_logger *logger) -{ -} - -#define INIT_STRUCT() libxl_ctx *ctx; struct caml_logger lg; struct caml_gc gc; gc.offset = 0; - -#define INIT_CTX() \ - lg.logger.vmessage = log_vmessage; \ - lg.logger.destroy = log_destroy; \ - lg.logger.progress = NULL; \ - lg.log_offset = 0; \ - memset(&lg.log_buf,0,sizeof(lg.log_buf)); \ - caml_enter_blocking_section(); \ - ret = libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, (struct xentoollog_logger *) &lg); \ - if (ret != 0) \ - failwith_xl("cannot init context", &lg); - -#define FREE_CTX() \ - gc_free(&gc); \ - caml_leave_blocking_section(); \ - libxl_ctx_free(ctx) - -static char * dup_String_val(caml_gc *gc, value s) +static char * dup_String_val(value s) { int len; char *c; @@ -85,25 +43,16 @@ static char * dup_String_val(caml_gc *gc, value s) c = calloc(len + 1, sizeof(char)); if (!c) caml_raise_out_of_memory(); - if (gc) gc->ptrs[gc->offset++] = c; memcpy(c, String_val(s), len); return c; } -static void gc_free(caml_gc *gc) -{ - int i; - for (i = 0; i < gc->offset; i++) { - free(gc->ptrs[i]); - } -} - -static void failwith_xl(char *fname, struct caml_logger *lg) +static void failwith_xl(char *fname) { - char *s; - s = (lg) ? lg->log_buf : fname; - printf("Error: %s\n", fname); - caml_raise_with_string(*caml_named_value("xl.error"), s); + value *exc = caml_named_value("Xenlight.Error"); + if (!exc) + caml_invalid_argument("Exception Xenlight.Error not initialized, please link xl.cma"); + caml_raise_with_string(*exc, fname); } void ctx_finalize(value ctx) @@ -129,7 +78,7 @@ CAMLprim value stub_libxl_ctx_alloc(value logger) ret = libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, (xentoollog_logger *) Xtl_val(logger)); if (ret != 0) \ - failwith_xl("cannot init context", NULL); + failwith_xl("cannot init context"); handle = caml_alloc_custom(&libxl_ctx_custom_operations, sizeof(ctx), 0, 1); Ctx_val(handle) = ctx; @@ -137,16 +86,6 @@ CAMLprim value stub_libxl_ctx_alloc(value logger) CAMLreturn(handle); } -static void * gc_calloc(caml_gc *gc, size_t nmemb, size_t size) -{ - void *ptr; - ptr = calloc(nmemb, size); - if (!ptr) - caml_raise_out_of_memory(); - gc->ptrs[gc->offset++] = ptr; - return ptr; -} - static int list_len(value v) { int len = 0; @@ -157,9 +96,8 @@ static int list_len(value v) return len; } -static int libxl_key_value_list_val(caml_gc *gc, struct caml_logger *lg, - libxl_key_value_list *c_val, - value v) +static int libxl_key_value_list_val(libxl_key_value_list *c_val, + value v) { CAMLparam1(v); CAMLlocal1(elem); @@ -168,15 +106,15 @@ static int libxl_key_value_list_val(caml_gc *gc, struct caml_logger *lg, nr = list_len(v); - array = gc_calloc(gc, (nr + 1) * 2, sizeof(char *)); + array = calloc((nr + 1) * 2, sizeof(char *)); if (!array) caml_raise_out_of_memory(); for (i=0; v != Val_emptylist; i++, v = Field(v, 1) ) { elem = Field(v, 0); - array[i * 2] = dup_String_val(gc, Field(elem, 0)); - array[i * 2 + 1] = dup_String_val(gc, Field(elem, 1)); + array[i * 2] = dup_String_val(Field(elem, 0)); + array[i * 2 + 1] = dup_String_val(Field(elem, 1)); } *c_val = array; @@ -206,9 +144,7 @@ static value Val_key_value_list(libxl_key_value_list *c_val) CAMLreturn(list); } -static int libxl_string_list_val(caml_gc *gc, struct caml_logger *lg, - libxl_string_list *c_val, - value v) +static int libxl_string_list_val(libxl_string_list *c_val, value v) { CAMLparam1(v); int nr, i; @@ -216,12 +152,12 @@ static int libxl_string_list_val(caml_gc *gc, struct caml_logger *lg, nr = list_len(v); - array = gc_calloc(gc, (nr + 1), sizeof(char *)); + array = calloc(nr + 1, sizeof(char *)); if (!array) caml_raise_out_of_memory(); for (i=0; v != Val_emptylist; i++, v = Field(v, 1) ) - array[i] = dup_String_val(gc, Field(v, 0)); + array[i] = dup_String_val(Field(v, 0)); *c_val = array; CAMLreturn(0); @@ -272,7 +208,7 @@ static value Val_mac (libxl_mac *c_val) CAMLreturn(v); } -static int Mac_val(caml_gc *gc, struct caml_logger *lg, libxl_mac *c_val, value v) +static int Mac_val(libxl_mac *c_val, value v) { CAMLparam1(v); int i; @@ -303,10 +239,21 @@ static value Val_bitmap (libxl_bitmap *c_val) CAMLreturn(v); } -static int Bitmap_val(caml_gc *gc, struct caml_logger *lg, - libxl_bitmap *c_val, value v) +static int Bitmap_val(libxl_ctx *ctx, libxl_bitmap *c_val, value v) { - abort(); /* XXX */ + CAMLparam1(v); + int i, len = Wosize_val(v); + + c_val->size = 0; + if (len > 0 && !libxl_bitmap_alloc(ctx, c_val, len)) + failwith_xl("cannot allocate bitmap"); + for (i=0; i<len; i++) { + if (Int_val(Field(v, i))) + libxl_bitmap_set(c_val, i); + else + libxl_bitmap_reset(c_val, i); + } + CAMLreturn(0); } static value Val_uuid (libxl_uuid *c_val) @@ -324,7 +271,7 @@ static value Val_uuid (libxl_uuid *c_val) CAMLreturn(v); } -static int Uuid_val(caml_gc *gc, struct caml_logger *lg, libxl_uuid *c_val, value v) +static int Uuid_val(libxl_uuid *c_val, value v) { CAMLparam1(v); int i; @@ -378,254 +325,76 @@ static value Val_hwcap(libxl_hwcap *c_val) #include "_libxl_types.inc" -value stub_xl_device_disk_add(value info, value domid) -{ - CAMLparam2(info, domid); - libxl_device_disk c_info; - int ret; - INIT_STRUCT(); - - device_disk_val(&gc, &lg, &c_info, info); - - INIT_CTX(); - ret = libxl_device_disk_add(ctx, Int_val(domid), &c_info, 0); - if (ret != 0) - failwith_xl("disk_add", &lg); - FREE_CTX(); - CAMLreturn(Val_unit); -} - -value stub_xl_device_disk_del(value info, value domid) -{ - CAMLparam2(info, domid); - libxl_device_disk c_info; - int ret; - INIT_STRUCT(); - - device_disk_val(&gc, &lg, &c_info, info); - - INIT_CTX(); - ret = libxl_device_disk_remove(ctx, Int_val(domid), &c_info, 0); - if (ret != 0) - failwith_xl("disk_del", &lg); - FREE_CTX(); - CAMLreturn(Val_unit); -} - -value stub_xl_device_nic_add(value info, value domid) -{ - CAMLparam2(info, domid); - libxl_device_nic c_info; - int ret; - INIT_STRUCT(); - - device_nic_val(&gc, &lg, &c_info, info); - - INIT_CTX(); - ret = libxl_device_nic_add(ctx, Int_val(domid), &c_info, 0); - if (ret != 0) - failwith_xl("nic_add", &lg); - FREE_CTX(); - CAMLreturn(Val_unit); -} - -value stub_xl_device_nic_del(value info, value domid) -{ - CAMLparam2(info, domid); - libxl_device_nic c_info; - int ret; - INIT_STRUCT(); - - device_nic_val(&gc, &lg, &c_info, info); - - INIT_CTX(); - ret = libxl_device_nic_remove(ctx, Int_val(domid), &c_info, 0); - if (ret != 0) - failwith_xl("nic_del", &lg); - FREE_CTX(); - CAMLreturn(Val_unit); -} - -value stub_xl_device_vkb_add(value info, value domid) -{ - CAMLparam2(info, domid); - libxl_device_vkb c_info; - int ret; - INIT_STRUCT(); - - device_vkb_val(&gc, &lg, &c_info, info); - - INIT_CTX(); - ret = libxl_device_vkb_add(ctx, Int_val(domid), &c_info, 0); - if (ret != 0) - failwith_xl("vkb_add", &lg); - FREE_CTX(); - - CAMLreturn(Val_unit); -} - -value stub_xl_device_vkb_remove(value info, value domid) -{ - CAMLparam1(domid); - libxl_device_vkb c_info; - int ret; - INIT_STRUCT(); - - device_vkb_val(&gc, &lg, &c_info, info); - - INIT_CTX(); - ret = libxl_device_vkb_remove(ctx, Int_val(domid), &c_info, 0); - if (ret != 0) - failwith_xl("vkb_clean_shutdown", &lg); - FREE_CTX(); - - CAMLreturn(Val_unit); -} - -value stub_xl_device_vkb_destroy(value info, value domid) -{ - CAMLparam1(domid); - libxl_device_vkb c_info; - int ret; - INIT_STRUCT(); - - device_vkb_val(&gc, &lg, &c_info, info); - - INIT_CTX(); - ret = libxl_device_vkb_destroy(ctx, Int_val(domid), &c_info, 0); - if (ret != 0) - failwith_xl("vkb_hard_shutdown", &lg); - FREE_CTX(); - - CAMLreturn(Val_unit); -} - -value stub_xl_device_vfb_add(value info, value domid) -{ - CAMLparam2(info, domid); - libxl_device_vfb c_info; - int ret; - INIT_STRUCT(); - - device_vfb_val(&gc, &lg, &c_info, info); - - INIT_CTX(); - ret = libxl_device_vfb_add(ctx, Int_val(domid), &c_info, 0); - if (ret != 0) - failwith_xl("vfb_add", &lg); - FREE_CTX(); - - CAMLreturn(Val_unit); -} - -value stub_xl_device_vfb_remove(value info, value domid) -{ - CAMLparam1(domid); - libxl_device_vfb c_info; - int ret; - INIT_STRUCT(); - - device_vfb_val(&gc, &lg, &c_info, info); - - INIT_CTX(); - ret = libxl_device_vfb_remove(ctx, Int_val(domid), &c_info, 0); - if (ret != 0) - failwith_xl("vfb_clean_shutdown", &lg); - FREE_CTX(); - - CAMLreturn(Val_unit); -} - -value stub_xl_device_vfb_destroy(value info, value domid) -{ - CAMLparam1(domid); - libxl_device_vfb c_info; - int ret; - INIT_STRUCT(); - - device_vfb_val(&gc, &lg, &c_info, info); - - INIT_CTX(); - ret = libxl_device_vfb_destroy(ctx, Int_val(domid), &c_info, 0); - if (ret != 0) - failwith_xl("vfb_hard_shutdown", &lg); - FREE_CTX(); - - CAMLreturn(Val_unit); -} - -value stub_xl_device_pci_add(value info, value domid) -{ - CAMLparam2(info, domid); - libxl_device_pci c_info; - int ret; - INIT_STRUCT(); - - device_pci_val(&gc, &lg, &c_info, info); - - INIT_CTX(); - ret = libxl_device_pci_add(ctx, Int_val(domid), &c_info, 0); - if (ret != 0) - failwith_xl("pci_add", &lg); - FREE_CTX(); - - CAMLreturn(Val_unit); -} - -value stub_xl_device_pci_remove(value info, value domid) -{ - CAMLparam2(info, domid); - libxl_device_pci c_info; +#define _STRINGIFY(x) #x +#define STRINGIFY(x) _STRINGIFY(x) + +#define _DEVICE_ADDREMOVE(type,op) \ +value stub_xl_device_##type##_##op(value ctx, value info, value domid) \ +{ \ + CAMLparam3(ctx, info, domid); \ + libxl_device_##type c_info; \ + int ret, marker_var; \ + \ + device_##type##_val(CTX, &c_info, info); \ + \ + ret = libxl_device_##type##_##op(CTX, Int_val(domid), &c_info, 0); \ + \ + libxl_device_##type##_dispose(&c_info); \ + \ + if (ret != 0) \ + failwith_xl(STRINGIFY(type) "_" STRINGIFY(op)); \ + \ + CAMLreturn(Val_unit); \ +} + +#define DEVICE_ADDREMOVE(type) \ + _DEVICE_ADDREMOVE(type, add) \ + _DEVICE_ADDREMOVE(type, remove) \ + _DEVICE_ADDREMOVE(type, destroy) + +DEVICE_ADDREMOVE(disk) +DEVICE_ADDREMOVE(nic) +DEVICE_ADDREMOVE(vfb) +DEVICE_ADDREMOVE(vkb) +DEVICE_ADDREMOVE(pci) + +value stub_xl_physinfo_get(value ctx) +{ + CAMLparam1(ctx); + CAMLlocal1(physinfo); + libxl_physinfo c_physinfo; int ret; - INIT_STRUCT(); - device_pci_val(&gc, &lg, &c_info, info); + ret = libxl_get_physinfo(CTX, &c_physinfo); - INIT_CTX(); - ret = libxl_device_pci_remove(ctx, Int_val(domid), &c_info, 0); if (ret != 0) - failwith_xl("pci_remove", &lg); - FREE_CTX(); - - CAMLreturn(Val_unit); -} + failwith_xl("get_physinfo"); -value stub_xl_physinfo_get(value unit) -{ - CAMLparam1(unit); - CAMLlocal1(physinfo); - libxl_physinfo c_physinfo; - int ret; - INIT_STRUCT(); + physinfo = Val_physinfo(&c_physinfo); - INIT_CTX(); - ret = libxl_get_physinfo(ctx, &c_physinfo); - if (ret != 0) - failwith_xl("physinfo", &lg); - FREE_CTX(); + libxl_physinfo_dispose(&c_physinfo); - physinfo = Val_physinfo(&gc, &lg, &c_physinfo); CAMLreturn(physinfo); } -value stub_xl_cputopology_get(value unit) +value stub_xl_cputopology_get(value ctx) { - CAMLparam1(unit); - CAMLlocal2(topology, v); + CAMLparam1(ctx); + CAMLlocal3(topology, v, v0); libxl_cputopology *c_topology; - int i, nr, ret; - INIT_STRUCT(); + int i, nr; - INIT_CTX(); + c_topology = libxl_get_cpu_topology(CTX, &nr); - c_topology = libxl_get_cpu_topology(ctx, &nr); - if (ret != 0) - failwith_xl("topologyinfo", &lg); + if (!c_topology) + failwith_xl("topologyinfo"); topology = caml_alloc_tuple(nr); for (i = 0; i < nr; i++) { - if (c_topology[i].core != LIBXL_CPUTOPOLOGY_INVALID_ENTRY) - v = Val_some(Val_cputopology(&gc, &lg, &c_topology[i])); + if (c_topology[i].core != LIBXL_CPUTOPOLOGY_INVALID_ENTRY) { + v0 = Val_cputopology(&c_topology[i]); + v = Val_some(v0); + } else v = Val_none; Store_field(topology, i, v); @@ -633,91 +402,89 @@ value stub_xl_cputopology_get(value unit) libxl_cputopology_list_free(c_topology, nr); - FREE_CTX(); CAMLreturn(topology); } -value stub_xl_domain_sched_params_get(value domid) +value stub_xl_domain_sched_params_get(value ctx, value domid) { - CAMLparam1(domid); + CAMLparam2(ctx, domid); CAMLlocal1(scinfo); libxl_domain_sched_params c_scinfo; int ret; - INIT_STRUCT(); - INIT_CTX(); - ret = libxl_domain_sched_params_get(ctx, Int_val(domid), &c_scinfo); + ret = libxl_domain_sched_params_get(CTX, Int_val(domid), &c_scinfo); if (ret != 0) - failwith_xl("domain_sched_params_get", &lg); - FREE_CTX(); + failwith_xl("domain_sched_params_get"); + + scinfo = Val_domain_sched_params(&c_scinfo); + + libxl_domain_sched_params_dispose(&c_scinfo); - scinfo = Val_domain_sched_params(&gc, &lg, &c_scinfo); CAMLreturn(scinfo); } -value stub_xl_domain_sched_params_set(value domid, value scinfo) +value stub_xl_domain_sched_params_set(value ctx, value domid, value scinfo) { - CAMLparam2(domid, scinfo); + CAMLparam3(ctx, domid, scinfo); libxl_domain_sched_params c_scinfo; int ret; - INIT_STRUCT(); - domain_sched_params_val(&gc, &lg, &c_scinfo, scinfo); + domain_sched_params_val(CTX, &c_scinfo, scinfo); + + ret = libxl_domain_sched_params_set(CTX, Int_val(domid), &c_scinfo); + + libxl_domain_sched_params_dispose(&c_scinfo); - INIT_CTX(); - ret = libxl_domain_sched_params_set(ctx, Int_val(domid), &c_scinfo); if (ret != 0) - failwith_xl("domain_sched_params_set", &lg); - FREE_CTX(); + failwith_xl("domain_sched_params_set"); CAMLreturn(Val_unit); } -value stub_xl_send_trigger(value domid, value trigger, value vcpuid) +value stub_xl_send_trigger(value ctx, value domid, value trigger, value vcpuid) { - CAMLparam3(domid, trigger, vcpuid); + CAMLparam4(ctx, domid, trigger, vcpuid); int ret; libxl_trigger c_trigger = LIBXL_TRIGGER_UNKNOWN; - INIT_STRUCT(); - trigger_val(&gc, &lg, &c_trigger, trigger); + trigger_val(CTX, &c_trigger, trigger); + + ret = libxl_send_trigger(CTX, Int_val(domid), + c_trigger, Int_val(vcpuid)); - INIT_CTX(); - ret = libxl_send_trigger(ctx, Int_val(domid), c_trigger, Int_val(vcpuid)); if (ret != 0) - failwith_xl("send_trigger", &lg); - FREE_CTX(); + failwith_xl("send_trigger"); + CAMLreturn(Val_unit); } -value stub_xl_send_sysrq(value domid, value sysrq) +value stub_xl_send_sysrq(value ctx, value domid, value sysrq) { - CAMLparam2(domid, sysrq); + CAMLparam3(ctx, domid, sysrq); int ret; - INIT_STRUCT(); - INIT_CTX(); - ret = libxl_send_sysrq(ctx, Int_val(domid), Int_val(sysrq)); + ret = libxl_send_sysrq(CTX, Int_val(domid), Int_val(sysrq)); + if (ret != 0) - failwith_xl("send_sysrq", &lg); - FREE_CTX(); + failwith_xl("send_sysrq"); + CAMLreturn(Val_unit); } -value stub_xl_send_debug_keys(value keys) +value stub_xl_send_debug_keys(value ctx, value keys) { - CAMLparam1(keys); + CAMLparam2(ctx, keys); int ret; char *c_keys; - INIT_STRUCT(); - c_keys = dup_String_val(&gc, keys); + c_keys = dup_String_val(keys); - INIT_CTX(); - ret = libxl_send_debug_keys(ctx, c_keys); + ret = libxl_send_debug_keys(CTX, c_keys); if (ret != 0) - failwith_xl("send_debug_keys", &lg); - FREE_CTX(); + failwith_xl("send_debug_keys"); + + free(c_keys); + CAMLreturn(Val_unit); } -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 13/30] libxl: ocaml: propagate the libxl return error code in exceptions
Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 10 ++--- tools/ocaml/libs/xl/xenlight.ml.in | 43 ++++++++++++++++++-- tools/ocaml/libs/xl/xenlight.mli.in | 26 ++++++++++-- tools/ocaml/libs/xl/xenlight_stubs.c | 74 +++++++++++++++++++++++++++------- 4 files changed, 127 insertions(+), 26 deletions(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index b617cb5..15d513a 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -229,7 +229,7 @@ def c_val(ty, c, o, indent="", parent = None): for e in ty.values: s += " case %d: *%s = %s; break;\n" % (n, c, e.name) n += 1 - s += " default: failwith_xl(\"cannot convert value to %s\"); break;\n" % ty.typename + s += " default: failwith_xl(ERROR_FAIL, \"cannot convert value to %s\"); break;\n" % ty.typename s += "}" elif isinstance(ty, idl.KeyedUnion): s += "{\n" @@ -242,7 +242,7 @@ def c_val(ty, c, o, indent="", parent = None): parent + ty.keyvar.name, f.enumname) n += 1 - s += "\t\t default: failwith_xl(\"variant handling bug %s%s (long)\"); break;\n" % (parent, ty.keyvar.name) + s += "\t\t default: failwith_xl(ERROR_FAIL, \"variant handling bug %s%s (long)\"); break;\n" % (parent, ty.keyvar.name) s += "\t\t}\n" s += "\t} else {\n" s += "\t\t/* Is block... */\n" @@ -258,7 +258,7 @@ def c_val(ty, c, o, indent="", parent = None): s += "%s" % c_val(f.type, fexpr, "Field(%s, 0)" % o, indent=indent+"\t\t ") s += "break;\n" n += 1 - s += "\t\t default: failwith_xl(\"variant handling bug %s%s (block)\"); break;\n" % (parent, ty.keyvar.name) + s += "\t\t default: failwith_xl(ERROR_FAIL, \"variant handling bug %s%s (block)\"); break;\n" % (parent, ty.keyvar.name) s += "\t\t}\n" s += "\t}\n" s += "}" @@ -327,7 +327,7 @@ def ocaml_Val(ty, o, c, indent="", parent = None): for e in ty.values: s += " case %s: %s = Int_val(%d); break;\n" % (e.name, o, n) n += 1 - s += " default: failwith_xl(\"cannot convert value from %s\"); break;\n" % ty.typename + s += " default: failwith_xl(ERROR_FAIL, \"cannot convert value from %s\"); break;\n" % ty.typename s += "}" elif isinstance(ty, idl.KeyedUnion): n = 0 @@ -356,7 +356,7 @@ def ocaml_Val(ty, o, c, indent="", parent = None): m += 1 #s += "\t %s = caml_alloc(%d,%d);\n" % (o,len(f.type.fields),n) s += "\t break;\n" - s += "\t default: failwith_xl(\"cannot convert value from %s\"); break;\n" % ty.typename + s += "\t default: failwith_xl(ERROR_FAIL, \"cannot convert value from %s\"); break;\n" % ty.typename s += "\t}" elif isinstance(ty,idl.Aggregate) and (parent is None or ty.rawname is None): s += "{\n" diff --git a/tools/ocaml/libs/xl/xenlight.ml.in b/tools/ocaml/libs/xl/xenlight.ml.in index dffba72..883df0c 100644 --- a/tools/ocaml/libs/xl/xenlight.ml.in +++ b/tools/ocaml/libs/xl/xenlight.ml.in @@ -13,18 +13,53 @@ * GNU Lesser General Public License for more details. *) -exception Error of string - type ctx type domid = int type devid = int -(* @@LIBXL_TYPES@@ *) +type error + Nonspecific | + Version | + Fail | + Ni | + Nomem | + Inval | + Badfail | + Guest_Timedout | + Timedout | + Noparavirt | + Not_Ready | + Osevent_Reg_Fail | + Bufferfull | + Unknown_Child + +let string_of_error error + match error with + | Nonspecific -> "Non specific" + | Version -> "Version" + | Fail -> "Fail" + | Ni -> "Ni" + | Nomem -> "Nomem" + | Inval -> "Inval" + | Badfail -> "Badfail" + | Guest_Timedout -> "Guest Timedout" + | Timedout -> "Timedout" + | Noparavirt -> "Noparavirt" + | Not_Ready -> "Not Ready" + | Osevent_Reg_Fail -> "Osevent Reg Fail" + | Bufferfull -> "Bufferfull" + | Unknown_Child -> "Unknown Child" + +exception Error of (error * string) external ctx_alloc: Xentoollog.handle -> ctx = "stub_libxl_ctx_alloc" +external test_raise_exception: unit -> unit = "stub_raise_exception" + +(* @@LIBXL_TYPES@@ *) + external send_trigger : ctx -> domid -> trigger -> int -> unit = "stub_xl_send_trigger" external send_sysrq : ctx -> domid -> char -> unit = "stub_xl_send_sysrq" external send_debug_keys : ctx -> string -> unit = "stub_xl_send_debug_keys" -let _ = Callback.register_exception "Xenlight.Error" (Error("")) +let _ = Callback.register_exception "Xenlight.Error" (Error(Fail, "")) diff --git a/tools/ocaml/libs/xl/xenlight.mli.in b/tools/ocaml/libs/xl/xenlight.mli.in index e2686bb..34b1ce5 100644 --- a/tools/ocaml/libs/xl/xenlight.mli.in +++ b/tools/ocaml/libs/xl/xenlight.mli.in @@ -13,16 +13,36 @@ * GNU Lesser General Public License for more details. *) -exception Error of string - type ctx type domid = int type devid = int -(* @@LIBXL_TYPES@@ *) +type error + Nonspecific | + Version | + Fail | + Ni | + Nomem | + Inval | + Badfail | + Guest_Timedout | + Timedout | + Noparavirt | + Not_Ready | + Osevent_Reg_Fail | + Bufferfull | + Unknown_Child + +val string_of_error: error -> string + +exception Error of (error * string) external ctx_alloc: Xentoollog.handle -> ctx = "stub_libxl_ctx_alloc" +external test_raise_exception: unit -> unit = "stub_raise_exception" + +(* @@LIBXL_TYPES@@ *) + external send_trigger : ctx -> domid -> trigger -> int -> unit = "stub_xl_send_trigger" external send_sysrq : ctx -> domid -> char -> unit = "stub_xl_send_sysrq" external send_debug_keys : ctx -> string -> unit = "stub_xl_send_debug_keys" diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index 062f65b..53b9d4e 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -47,12 +47,58 @@ static char * dup_String_val(value s) return c; } -static void failwith_xl(char *fname) +static value Val_error(int error) { - value *exc = caml_named_value("Xenlight.Error"); + switch (error) { + case ERROR_NONSPECIFIC: return Val_int(0); + case ERROR_VERSION: return Val_int(1); + case ERROR_FAIL: return Val_int(2); + case ERROR_NI: return Val_int(3); + case ERROR_NOMEM: return Val_int(4); + case ERROR_INVAL: return Val_int(5); + case ERROR_BADFAIL: return Val_int(6); + case ERROR_GUEST_TIMEDOUT: return Val_int(7); + case ERROR_TIMEDOUT: return Val_int(8); + case ERROR_NOPARAVIRT: return Val_int(9); + case ERROR_NOT_READY: return Val_int(10); + case ERROR_OSEVENT_REG_FAIL: return Val_int(11); + case ERROR_BUFFERFULL: return Val_int(12); + case ERROR_UNKNOWN_CHILD: return Val_int(13); +#if 0 /* Let the compiler catch this */ + default: + caml_raise_sys_error(caml_copy_string("Unknown libxl ERROR")); + break; +#endif + } + /* Should not reach here */ + abort(); +} + +static void failwith_xl(int error, char *fname) +{ + CAMLlocal1(arg); + static value *exc = NULL; + + /* First time around, lookup by name */ + if (!exc) + exc = caml_named_value("Xenlight.Error"); + if (!exc) - caml_invalid_argument("Exception Xenlight.Error not initialized, please link xl.cma"); - caml_raise_with_string(*exc, fname); + caml_invalid_argument("Exception Xenlight.Error not initialized, please link xenlight.cma"); + + arg = caml_alloc(2, 0); + + Store_field(arg, 0, Val_error(error)); + Store_field(arg, 1, caml_copy_string(fname)); + + caml_raise_with_arg(*exc, arg); +} + +CAMLprim value stub_raise_exception(value unit) +{ + CAMLparam1(unit); + failwith_xl(ERROR_FAIL, "test exception"); + CAMLreturn(Val_unit); } void ctx_finalize(value ctx) @@ -78,7 +124,7 @@ CAMLprim value stub_libxl_ctx_alloc(value logger) ret = libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0, (xentoollog_logger *) Xtl_val(logger)); if (ret != 0) \ - failwith_xl("cannot init context"); + failwith_xl(ERROR_FAIL, "cannot init context"); handle = caml_alloc_custom(&libxl_ctx_custom_operations, sizeof(ctx), 0, 1); Ctx_val(handle) = ctx; @@ -246,7 +292,7 @@ static int Bitmap_val(libxl_ctx *ctx, libxl_bitmap *c_val, value v) c_val->size = 0; if (len > 0 && !libxl_bitmap_alloc(ctx, c_val, len)) - failwith_xl("cannot allocate bitmap"); + failwith_xl(ERROR_NOMEM, "cannot allocate bitmap"); for (i=0; i<len; i++) { if (Int_val(Field(v, i))) libxl_bitmap_set(c_val, i); @@ -342,7 +388,7 @@ value stub_xl_device_##type##_##op(value ctx, value info, value domid) \ libxl_device_##type##_dispose(&c_info); \ \ if (ret != 0) \ - failwith_xl(STRINGIFY(type) "_" STRINGIFY(op)); \ + failwith_xl(ret, STRINGIFY(type) "_" STRINGIFY(op)); \ \ CAMLreturn(Val_unit); \ } @@ -368,7 +414,7 @@ value stub_xl_physinfo_get(value ctx) ret = libxl_get_physinfo(CTX, &c_physinfo); if (ret != 0) - failwith_xl("get_physinfo"); + failwith_xl(ret, "get_physinfo"); physinfo = Val_physinfo(&c_physinfo); @@ -387,7 +433,7 @@ value stub_xl_cputopology_get(value ctx) c_topology = libxl_get_cpu_topology(CTX, &nr); if (!c_topology) - failwith_xl("topologyinfo"); + failwith_xl(ERROR_FAIL, "get_cpu_topologyinfo"); topology = caml_alloc_tuple(nr); for (i = 0; i < nr; i++) { @@ -414,7 +460,7 @@ value stub_xl_domain_sched_params_get(value ctx, value domid) ret = libxl_domain_sched_params_get(CTX, Int_val(domid), &c_scinfo); if (ret != 0) - failwith_xl("domain_sched_params_get"); + failwith_xl(ret, "domain_sched_params_get"); scinfo = Val_domain_sched_params(&c_scinfo); @@ -436,7 +482,7 @@ value stub_xl_domain_sched_params_set(value ctx, value domid, value scinfo) libxl_domain_sched_params_dispose(&c_scinfo); if (ret != 0) - failwith_xl("domain_sched_params_set"); + failwith_xl(ret, "domain_sched_params_set"); CAMLreturn(Val_unit); } @@ -453,7 +499,7 @@ value stub_xl_send_trigger(value ctx, value domid, value trigger, value vcpuid) c_trigger, Int_val(vcpuid)); if (ret != 0) - failwith_xl("send_trigger"); + failwith_xl(ret, "send_trigger"); CAMLreturn(Val_unit); } @@ -466,7 +512,7 @@ value stub_xl_send_sysrq(value ctx, value domid, value sysrq) ret = libxl_send_sysrq(CTX, Int_val(domid), Int_val(sysrq)); if (ret != 0) - failwith_xl("send_sysrq"); + failwith_xl(ret, "send_sysrq"); CAMLreturn(Val_unit); } @@ -481,7 +527,7 @@ value stub_xl_send_debug_keys(value ctx, value keys) ret = libxl_send_debug_keys(CTX, c_keys); if (ret != 0) - failwith_xl("send_debug_keys"); + failwith_xl(ret, "send_debug_keys"); free(c_keys); -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 14/30] libxl: ocaml: make Val_defbool GC-proof
Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/xenlight_stubs.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index 53b9d4e..7b7d696 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -332,15 +332,17 @@ static int Uuid_val(libxl_uuid *c_val, value v) static value Val_defbool(libxl_defbool c_val) { CAMLparam0(); - CAMLlocal1(v); + CAMLlocal2(v1, v2); + bool b; if (libxl_defbool_is_default(c_val)) - v = Val_none; + v2 = Val_none; else { - bool b = libxl_defbool_val(c_val); - v = Val_some(b ? Val_bool(true) : Val_bool(false)); + b = libxl_defbool_val(c_val); + v1 = b ? Val_bool(true) : Val_bool(false); + v2 = Val_some(v1); } - CAMLreturn(v); + CAMLreturn(v2); } static libxl_defbool Defbool_val(value v) -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 15/30] libxl: ocaml: add domain_build/create_info/config and events to the bindings.
We now have enoguh infrastructure in place to do this trivially. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/libxl/libxl_types.idl | 2 +- tools/ocaml/libs/xl/genwrap.py | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl index 47c925a..4e99365 100644 --- a/tools/libxl/libxl_types.idl +++ b/tools/libxl/libxl_types.idl @@ -440,7 +440,7 @@ libxl_domain_config = Struct("domain_config", [ ("on_reboot", libxl_action_on_shutdown), ("on_watchdog", libxl_action_on_shutdown), ("on_crash", libxl_action_on_shutdown), - ]) + ], dir=DIR_IN) libxl_diskinfo = Struct("diskinfo", [ ("backend", string), diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index 15d513a..3f8bcbf 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -426,11 +426,7 @@ if __name__ == ''__main__'': # Do not generate these yet. blacklist = [ "cpupoolinfo", - "domain_create_info", - "domain_build_info", - "domain_config", "vcpuinfo", - "event", ] for t in blacklist: -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 16/30] libxl: ocaml: add META to list of generated files in Makefile
Signed-off-by: Rob Hoes <rob.hoes@citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> --- tools/ocaml/libs/xl/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ocaml/libs/xl/Makefile b/tools/ocaml/libs/xl/Makefile index 6917a20..0408cc2 100644 --- a/tools/ocaml/libs/xl/Makefile +++ b/tools/ocaml/libs/xl/Makefile @@ -22,7 +22,7 @@ OCAML_LIBRARY = xenlight GENERATED_FILES += xenlight.ml xenlight.ml.tmp xenlight.mli xenlight.mli.tmp GENERATED_FILES += _libxl_types.ml.in _libxl_types.mli.in -GENERATED_FILES += _libxl_types.inc +GENERATED_FILES += _libxl_types.inc META all: $(INTF) $(LIBS) -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 17/30] libxl: ocaml: fix the handling of enums in the bindings generator
Signed-off-by: Rob Hoes <rob.hoes@citrix.com> Acked-by: Ian Campbell <ian.campbell@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index 3f8bcbf..f0d4885 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -325,7 +325,7 @@ def ocaml_Val(ty, o, c, indent="", parent = None): n = 0 s += "switch(%s) {\n" % c for e in ty.values: - s += " case %s: %s = Int_val(%d); break;\n" % (e.name, o, n) + s += " case %s: %s = Val_int(%d); break;\n" % (e.name, o, n) n += 1 s += " default: failwith_xl(ERROR_FAIL, \"cannot convert value from %s\"); break;\n" % ty.typename s += "}" -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 18/30] libxl: ocaml: use the "string option" type for IDL strings
The libxl IDL is based on C type "char *", and therefore "strings" can by NULL, or be an actual string. In ocaml, it is common to encode such things as option types. Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 2 +- tools/ocaml/libs/xl/xenlight_stubs.c | 21 +++++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index f0d4885..d967ee6 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -8,7 +8,7 @@ import idl builtins = { "bool": ("bool", "%(c)s = Bool_val(%(o)s)", "Val_bool(%(c)s)" ), "int": ("int", "%(c)s = Int_val(%(o)s)", "Val_int(%(c)s)" ), - "char *": ("string", "%(c)s = dup_String_val(%(o)s)", "caml_copy_string(%(c)s)"), + "char *": ("string option", "%(c)s = String_option_val(%(o)s)", "Val_string_option(%(c)s)"), "libxl_domid": ("domid", "%(c)s = Int_val(%(o)s)", "Val_int(%(c)s)" ), "libxl_devid": ("devid", "%(c)s = Int_val(%(o)s)", "Val_int(%(c)s)" ), "libxl_defbool": ("bool option", "%(c)s = Defbool_val(%(o)s)", "Val_defbool(%(c)s)" ), diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index 7b7d696..e801643 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -371,6 +371,27 @@ static value Val_hwcap(libxl_hwcap *c_val) CAMLreturn(hwcap); } +static value Val_string_option(const char *c_val) +{ + CAMLparam0(); + CAMLlocal2(tmp1, tmp2); + if (c_val) { + tmp1 = caml_copy_string(c_val); + tmp2 = Val_some(tmp1); + CAMLreturn(tmp2); + } + else + CAMLreturn(Val_none); +} + +static char *String_option_val(value v) +{ + char *s = NULL; + if (v != Val_none) + s = dup_String_val(Some_val(v)); + return s; +} + #include "_libxl_types.inc" #define _STRINGIFY(x) #x -- 1.7.10.4
Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/xenlight.ml.in | 1 + tools/ocaml/libs/xl/xenlight.mli.in | 1 + tools/ocaml/libs/xl/xenlight_stubs.c | 27 +++++++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/tools/ocaml/libs/xl/xenlight.ml.in b/tools/ocaml/libs/xl/xenlight.ml.in index 883df0c..fd5c4ce 100644 --- a/tools/ocaml/libs/xl/xenlight.ml.in +++ b/tools/ocaml/libs/xl/xenlight.ml.in @@ -61,5 +61,6 @@ external test_raise_exception: unit -> unit = "stub_raise_exception" external send_trigger : ctx -> domid -> trigger -> int -> unit = "stub_xl_send_trigger" external send_sysrq : ctx -> domid -> char -> unit = "stub_xl_send_sysrq" external send_debug_keys : ctx -> string -> unit = "stub_xl_send_debug_keys" +external xen_console_read : ctx -> string list = "stub_xl_xen_console_read" let _ = Callback.register_exception "Xenlight.Error" (Error(Fail, "")) diff --git a/tools/ocaml/libs/xl/xenlight.mli.in b/tools/ocaml/libs/xl/xenlight.mli.in index 34b1ce5..11ea43c 100644 --- a/tools/ocaml/libs/xl/xenlight.mli.in +++ b/tools/ocaml/libs/xl/xenlight.mli.in @@ -46,3 +46,4 @@ external test_raise_exception: unit -> unit = "stub_raise_exception" external send_trigger : ctx -> domid -> trigger -> int -> unit = "stub_xl_send_trigger" external send_sysrq : ctx -> domid -> char -> unit = "stub_xl_send_sysrq" external send_debug_keys : ctx -> string -> unit = "stub_xl_send_debug_keys" +external xen_console_read : ctx -> string list = "stub_xl_xen_console_read" diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index e801643..cacaaca 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -557,6 +557,33 @@ value stub_xl_send_debug_keys(value ctx, value keys) CAMLreturn(Val_unit); } +value stub_xl_xen_console_read(value ctx) +{ + CAMLparam1(ctx); + CAMLlocal3(list, cons, ml_line); + int i = 0, ret; + char *console[32768], *line; + libxl_xen_console_reader *cr; + + cr = libxl_xen_console_read_start(CTX, 0); + if (cr) + for (i = 0; libxl_xen_console_read_line(CTX, cr, &line) > 0; i++) + console[i] = strdup(line); + libxl_xen_console_read_finish(CTX, cr); + + list = Val_emptylist; + for (; i > 0; i--) { + ml_line = caml_copy_string(console[i - 1]); + free(console[i - 1]); + cons = caml_alloc(2, 0); + Store_field(cons, 0, ml_line); // head + Store_field(cons, 1, list); // tail + list = cons; + } + + CAMLreturn(list); +} + /* * Local variables: * indent-tabs-mode: t -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 20/30] libxl: ocaml: add dominfo_list and dominfo_get
Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 3 +++ tools/ocaml/libs/xl/xenlight_stubs.c | 41 ++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index d967ee6..23de43a 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -33,6 +33,9 @@ functions = { # ( name , [type1,type2,....] ) "device_disk": DEVICE_FUNCTIONS, "device_nic": DEVICE_FUNCTIONS, "device_pci": DEVICE_FUNCTIONS, + "dominfo": [ ("list", ["ctx", "t list"]), + ("get", ["ctx", "domid", "t"]), + ], "physinfo": [ ("get", ["ctx", "t"]), ], "cputopology": [ ("get", ["ctx", "t array"]), diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index cacaaca..4e15edb 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -474,6 +474,47 @@ value stub_xl_cputopology_get(value ctx) CAMLreturn(topology); } +value stub_xl_dominfo_list(value ctx) +{ + CAMLparam1(ctx); + CAMLlocal2(domlist, temp); + libxl_dominfo *c_domlist; + int i, nb; + + c_domlist = libxl_list_domain(CTX, &nb); + if (!c_domlist) + failwith_xl(ERROR_FAIL, "dominfo_list"); + + domlist = temp = Val_emptylist; + for (i = nb - 1; i >= 0; i--) { + domlist = caml_alloc_small(2, Tag_cons); + Field(domlist, 0) = Val_int(0); + Field(domlist, 1) = temp; + temp = domlist; + + Store_field(domlist, 0, Val_dominfo(&c_domlist[i])); + } + + libxl_dominfo_list_free(c_domlist, nb); + + CAMLreturn(domlist); +} + +value stub_xl_dominfo_get(value ctx, value domid) +{ + CAMLparam2(ctx, domid); + CAMLlocal1(dominfo); + libxl_dominfo c_dominfo; + int ret; + + ret = libxl_domain_info(CTX, &c_dominfo, Int_val(domid)); + if (ret != 0) + failwith_xl(ERROR_FAIL, "domain_info"); + dominfo = Val_dominfo(&c_dominfo); + + CAMLreturn(dominfo); +} + value stub_xl_domain_sched_params_get(value ctx, value domid) { CAMLparam2(ctx, domid); -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 21/30] libxl: ocaml: implement some simple tests
Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- .gitignore | 3 ++- .hgignore | 2 ++ tools/ocaml/test/Makefile | 30 ++++++++++++++++++++++++++---- tools/ocaml/test/list_domains.ml | 29 +++++++++++++++++++++++++++++ tools/ocaml/test/raise_exception.ml | 11 +++++++++++ tools/ocaml/test/send_debug_keys.ml | 16 ++++++++++++++++ 6 files changed, 86 insertions(+), 5 deletions(-) create mode 100644 tools/ocaml/test/list_domains.ml create mode 100644 tools/ocaml/test/raise_exception.ml create mode 100644 tools/ocaml/test/send_debug_keys.ml diff --git a/.gitignore b/.gitignore index 61a27c6..a30ff64 100644 --- a/.gitignore +++ b/.gitignore @@ -383,7 +383,8 @@ tools/ocaml/libs/xl/xenlight.ml tools/ocaml/libs/xl/xenlight.mli tools/ocaml/xenstored/oxenstored tools/ocaml/test/xtl - +tools/ocaml/test/send_debug_keys +tools/ocaml/test/list_domains tools/debugger/kdd/kdd tools/firmware/etherboot/ipxe.tar.gz tools/firmware/etherboot/ipxe/ diff --git a/.hgignore b/.hgignore index bb1b67d..ee5c084 100644 --- a/.hgignore +++ b/.hgignore @@ -309,6 +309,8 @@ ^tools/ocaml/libs/xl/xenlight\.mli$ ^tools/ocaml/xenstored/oxenstored$ ^tools/ocaml/test/xtl$ +^tools/ocaml/test/send_debug_keys$ +^tools/ocaml/test/list_domains$ ^tools/autom4te\.cache$ ^tools/config\.h$ ^tools/config\.log$ diff --git a/tools/ocaml/test/Makefile b/tools/ocaml/test/Makefile index 980054c..2c5fdd8 100644 --- a/tools/ocaml/test/Makefile +++ b/tools/ocaml/test/Makefile @@ -3,11 +3,12 @@ OCAML_TOPLEVEL = $(CURDIR)/.. include $(OCAML_TOPLEVEL)/common.make OCAMLINCLUDE += \ - -I $(OCAML_TOPLEVEL)/libs/xentoollog + -I $(OCAML_TOPLEVEL)/libs/xentoollog \ + -I $(OCAML_TOPLEVEL)/libs/xl -OBJS = xtl +OBJS = xtl send_debug_keys list_domains raise_exception -PROGRAMS = xtl +PROGRAMS = xtl send_debug_keys list_domains raise_exception xtl_LIBS = \ -ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/xentoollog $(OCAML_TOPLEVEL)/libs/xentoollog/xentoollog.cmxa \ @@ -15,7 +16,28 @@ xtl_LIBS = \ xtl_OBJS = xtl -OCAML_PROGRAM = xtl +send_debug_keys_LIBS = \ + -ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/xentoollog $(OCAML_TOPLEVEL)/libs/xentoollog/xentoollog.cmxa \ + -ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/xl $(OCAML_TOPLEVEL)/libs/xl/xenlight.cmxa \ + -cclib -lxenlight + +send_debug_keys_OBJS = send_debug_keys + +list_domains_LIBS = \ + -ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/xentoollog $(OCAML_TOPLEVEL)/libs/xentoollog/xentoollog.cmxa \ + -ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/xl $(OCAML_TOPLEVEL)/libs/xl/xenlight.cmxa \ + -cclib -lxenlight + +list_domains_OBJS = list_domains + +raise_exception_LIBS = \ + -ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/xentoollog $(OCAML_TOPLEVEL)/libs/xentoollog/xentoollog.cmxa \ + -ccopt -L -ccopt $(OCAML_TOPLEVEL)/libs/xl $(OCAML_TOPLEVEL)/libs/xl/xenlight.cmxa \ + -cclib -lxenlight + +raise_exception_OBJS = raise_exception + +OCAML_PROGRAM = xtl send_debug_keys list_domains raise_exception all: $(PROGRAMS) diff --git a/tools/ocaml/test/list_domains.ml b/tools/ocaml/test/list_domains.ml new file mode 100644 index 0000000..e21dd71 --- /dev/null +++ b/tools/ocaml/test/list_domains.ml @@ -0,0 +1,29 @@ +open Arg +open Printf +open Xentoollog +open Xenlight + +let bool_as_char b c = if b then c else ''-'' + +let print_dominfo dominfo + let id = dominfo.Xenlight.Dominfo.domid + and running = bool_as_char dominfo.Xenlight.Dominfo.running ''r'' + and blocked = bool_as_char dominfo.Xenlight.Dominfo.blocked ''b'' + and paused = bool_as_char dominfo.Xenlight.Dominfo.paused ''p'' + and shutdown = bool_as_char dominfo.Xenlight.Dominfo.shutdown ''s'' + and dying = bool_as_char dominfo.Xenlight.Dominfo.dying ''d'' + and memory = dominfo.Xenlight.Dominfo.current_memkb + in + printf "Dom %d: %c%c%c%c%c %LdKB\n" id running blocked paused shutdown dying memory + +let _ + let logger = Xentoollog.create_stdio_logger (*~level:Xentoollog.Debug*) () in + let ctx = Xenlight.ctx_alloc logger in + try + let domains = Xenlight.Dominfo.list ctx in + List.iter (fun d -> print_dominfo d) domains + with Xenlight.Error(err, fn) -> begin + printf "Caught Exception: %s: %s\n" (Xenlight.string_of_error err) fn; + end + + diff --git a/tools/ocaml/test/raise_exception.ml b/tools/ocaml/test/raise_exception.ml new file mode 100644 index 0000000..d4371f5 --- /dev/null +++ b/tools/ocaml/test/raise_exception.ml @@ -0,0 +1,11 @@ +open Printf +open Xentoollog +open Xenlight + +let _ = + try + Xenlight.test_raise_exception () + with Xenlight.Error(err, fn) -> begin + printf "Caught Exception: %s: %s\n" (Xenlight.string_of_error err) fn; + end + diff --git a/tools/ocaml/test/send_debug_keys.ml b/tools/ocaml/test/send_debug_keys.ml new file mode 100644 index 0000000..6db89e8 --- /dev/null +++ b/tools/ocaml/test/send_debug_keys.ml @@ -0,0 +1,16 @@ +open Arg +open Printf +open Xentoollog +open Xenlight + +let send_keys ctx s = + printf "Sending debug key %s\n" s; + Xenlight.send_debug_keys ctx s; + () + +let _ = + let logger = Xentoollog.create_stdio_logger () in + let ctx = Xenlight.ctx_alloc logger in + Arg.parse [ + ] (fun s -> send_keys ctx s) "usage: send_debug_keys <keys>" + -- 1.7.10.4
Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/xenlight.ml.in | 70 +++++++- tools/ocaml/libs/xl/xenlight.mli.in | 48 +++++ tools/ocaml/libs/xl/xenlight_stubs.c | 325 ++++++++++++++++++++++++++++++++++ 3 files changed, 442 insertions(+), 1 deletion(-) diff --git a/tools/ocaml/libs/xl/xenlight.ml.in b/tools/ocaml/libs/xl/xenlight.ml.in index fd5c4ce..06c9f52 100644 --- a/tools/ocaml/libs/xl/xenlight.ml.in +++ b/tools/ocaml/libs/xl/xenlight.ml.in @@ -56,6 +56,14 @@ external ctx_alloc: Xentoollog.handle -> ctx = "stub_libxl_ctx_alloc" external test_raise_exception: unit -> unit = "stub_raise_exception" +type event + | POLLIN (* There is data to read *) + | POLLPRI (* There is urgent data to read *) + | POLLOUT (* Writing now will not block *) + | POLLERR (* Error condition (revents only) *) + | POLLHUP (* Device has been disconnected (revents only) *) + | POLLNVAL (* Invalid request: fd not open (revents only). *) + (* @@LIBXL_TYPES@@ *) external send_trigger : ctx -> domid -> trigger -> int -> unit = "stub_xl_send_trigger" @@ -63,4 +71,64 @@ external send_sysrq : ctx -> domid -> char -> unit = "stub_xl_send_sysrq" external send_debug_keys : ctx -> string -> unit = "stub_xl_send_debug_keys" external xen_console_read : ctx -> string list = "stub_xl_xen_console_read" -let _ = Callback.register_exception "Xenlight.Error" (Error(Fail, "")) +module type EVENT_USERS + sig + type osevent_user + type event_user + type async_user + end + +module Async = functor (S: EVENT_USERS) -> struct + type for_libxl + type event_hooks + type osevent_hooks + + module OseventSet = Set.Make(struct type t = S.osevent_user;; let compare = Pervasives.compare end) + module EventSet = Set.Make(struct type t = S.event_user;; let compare = Pervasives.compare end) + module AsyncSet = Set.Make(struct type t = S.async_user;; let compare = Pervasives.compare end) + + let osevent_users = ref OseventSet.empty + let event_users = ref EventSet.empty + let async_users = ref AsyncSet.empty + let async_callback_ref = ref None + + external osevent_register_hooks'' : ctx -> S.osevent_user -> osevent_hooks = "stub_libxl_osevent_register_hooks" + external osevent_occurred_fd : ctx -> for_libxl -> Unix.file_descr -> event list -> event list -> unit = "stub_libxl_osevent_occurred_fd" + external osevent_occurred_timeout : ctx -> for_libxl -> unit = "stub_libxl_osevent_occurred_timeout" + + let osevent_register_hooks ctx ~user ~fd_register ~fd_modify ~fd_deregister ~timeout_register ~timeout_modify + Callback.register "libxl_fd_register" fd_register; + Callback.register "libxl_fd_modify" fd_modify; + Callback.register "libxl_fd_deregister" fd_deregister; + Callback.register "libxl_timeout_register" timeout_register; + Callback.register "libxl_timeout_modify" timeout_modify; + osevent_users := OseventSet.add user !osevent_users; + osevent_register_hooks'' ctx user + + let async f user + async_users := AsyncSet.add user !async_users; + f ?async:(Some user) () + + let async_callback'' result user + async_users := AsyncSet.remove user !async_users; + match !async_callback_ref with + | None -> () + | Some f -> f ~result ~user + + let async_register_callback ~async_callback + async_callback_ref := Some async_callback; + Callback.register "libxl_async_callback" async_callback'' + + external evenable_domain_death : ctx -> domid -> int -> unit = "stub_libxl_evenable_domain_death" + external event_register_callbacks'' : ctx -> S.event_user -> event_hooks = "stub_libxl_event_register_callbacks" + + let event_register_callbacks ctx ~user ~event_occurs_callback ~event_disaster_callback + Callback.register "libxl_event_occurs_callback" event_occurs_callback; + Callback.register "libxl_event_disaster_callback" event_disaster_callback; + event_users := EventSet.add user !event_users; + event_register_callbacks'' ctx user +end + +let _ + Callback.register_exception "Xenlight.Error" (Error(Fail, "")) + diff --git a/tools/ocaml/libs/xl/xenlight.mli.in b/tools/ocaml/libs/xl/xenlight.mli.in index 11ea43c..0b06712 100644 --- a/tools/ocaml/libs/xl/xenlight.mli.in +++ b/tools/ocaml/libs/xl/xenlight.mli.in @@ -41,9 +41,57 @@ external ctx_alloc: Xentoollog.handle -> ctx = "stub_libxl_ctx_alloc" external test_raise_exception: unit -> unit = "stub_raise_exception" +type event + | POLLIN (* There is data to read *) + | POLLPRI (* There is urgent data to read *) + | POLLOUT (* Writing now will not block *) + | POLLERR (* Error condition (revents only) *) + | POLLHUP (* Device has been disconnected (revents only) *) + | POLLNVAL (* Invalid request: fd not open (revents only). *) + (* @@LIBXL_TYPES@@ *) external send_trigger : ctx -> domid -> trigger -> int -> unit = "stub_xl_send_trigger" external send_sysrq : ctx -> domid -> char -> unit = "stub_xl_send_sysrq" external send_debug_keys : ctx -> string -> unit = "stub_xl_send_debug_keys" external xen_console_read : ctx -> string list = "stub_xl_xen_console_read" + +module type EVENT_USERS + sig + type osevent_user + type event_user + type async_user + end + +module Async : functor (S: EVENT_USERS) -> sig + type for_libxl + type event_hooks + type osevent_hooks + + val osevent_register_hooks : ctx -> + user:S.osevent_user -> + fd_register:(S.osevent_user -> Unix.file_descr -> event list -> for_libxl -> unit) -> + fd_modify:(S.osevent_user -> Unix.file_descr -> event list -> unit) -> + fd_deregister:(S.osevent_user -> Unix.file_descr -> unit) -> + timeout_register:(S.osevent_user -> int -> int -> for_libxl -> unit) -> + timeout_modify:(S.osevent_user -> unit) -> + osevent_hooks + + external osevent_occurred_fd : ctx -> for_libxl -> Unix.file_descr -> event list -> event list -> unit = "stub_libxl_osevent_occurred_fd" + external osevent_occurred_timeout : ctx -> for_libxl -> unit = "stub_libxl_osevent_occurred_timeout" + + val async : (?async:S.async_user -> unit -> ''a) -> S.async_user -> ''a + + val async_register_callback : + async_callback:(result:error option -> user:S.async_user -> unit) -> + unit + + external evenable_domain_death : ctx -> domid -> int -> unit = "stub_libxl_evenable_domain_death" + + val event_register_callbacks : ctx -> + user:S.event_user -> + event_occurs_callback:(S.event_user -> Event.t -> unit) -> + event_disaster_callback:(S.event_user -> event_type -> string -> int -> unit) -> + event_hooks +end + diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index 4e15edb..c98a660 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -30,6 +30,8 @@ #include <libxl.h> #include <libxl_utils.h> +#include <unistd.h> + #include "caml_xentoollog.h" #define Ctx_val(x)(*((libxl_ctx **) Data_custom_val(x))) @@ -394,6 +396,26 @@ static char *String_option_val(value v) #include "_libxl_types.inc" +void async_callback(libxl_ctx *ctx, int rc, void *for_callback) +{ + CAMLparam0(); + CAMLlocal1(error); + int *task = (int *) for_callback; + static value *func = NULL; + + if (func == NULL) { + /* First time around, lookup by name */ + func = caml_named_value("libxl_async_callback"); + } + + if (rc == 0) + error = Val_none; + else + error = Val_some(Val_error(rc)); + + caml_callback2(*func, error, (value) for_callback); +} + #define _STRINGIFY(x) #x #define STRINGIFY(x) _STRINGIFY(x) @@ -625,6 +647,309 @@ value stub_xl_xen_console_read(value ctx) CAMLreturn(list); } + +/* Event handling */ + +short Poll_val(value event) +{ + CAMLparam1(event); + short res = -1; + + switch (Int_val(event)) { + case 0: res = POLLIN; break; + case 1: res = POLLPRI; break; + case 2: res = POLLOUT; break; + case 3: res = POLLERR; break; + case 4: res = POLLHUP; break; + case 5: res = POLLNVAL; break; + } + + CAMLreturn(res); +} + +short Poll_events_val(value event_list) +{ + CAMLparam1(event_list); + short events = 0; + + while (event_list != Val_emptylist) { + events |= Poll_val(Field(event_list, 0)); + event_list = Field(event_list, 1); + } + + CAMLreturn(events); +} + +value Val_poll(short event) +{ + CAMLparam0(); + CAMLlocal1(res); + + switch (event) { + case POLLIN: res = Val_int(0); break; + case POLLPRI: res = Val_int(1); break; + case POLLOUT: res = Val_int(2); break; + case POLLERR: res = Val_int(3); break; + case POLLHUP: res = Val_int(4); break; + case POLLNVAL: res = Val_int(5); break; + default: failwith_xl(ERROR_FAIL, "cannot convert poll event value"); break; + } + + CAMLreturn(res); +} + +value add_event(value event_list, short event) +{ + CAMLparam1(event_list); + CAMLlocal1(new_list); + + new_list = caml_alloc(2, 0); + Store_field(new_list, 0, Val_poll(event)); + Store_field(new_list, 1, event_list); + + CAMLreturn(new_list); +} + +value Val_poll_events(short events) +{ + CAMLparam0(); + CAMLlocal1(event_list); + + event_list = Val_emptylist; + if (events & POLLIN) + event_list = add_event(event_list, POLLIN); + if (events & POLLPRI) + event_list = add_event(event_list, POLLPRI); + if (events & POLLOUT) + event_list = add_event(event_list, POLLOUT); + if (events & POLLERR) + event_list = add_event(event_list, POLLERR); + if (events & POLLHUP) + event_list = add_event(event_list, POLLHUP); + if (events & POLLNVAL) + event_list = add_event(event_list, POLLNVAL); + + CAMLreturn(event_list); +} + +int fd_register(void *user, int fd, void **for_app_registration_out, + short events, void *for_libxl) +{ + CAMLparam0(); + CAMLlocalN(args, 4); + static value *func = NULL; + + if (func == NULL) { + /* First time around, lookup by name */ + func = caml_named_value("libxl_fd_register"); + } + + args[0] = (value) user; + args[1] = Val_int(fd); + args[2] = Val_poll_events(events); + args[3] = (value) for_libxl; + + caml_callbackN(*func, 4, args); + CAMLreturn(0); +} + +int fd_modify(void *user, int fd, void **for_app_registration_update, + short events) +{ + CAMLparam0(); + CAMLlocalN(args, 3); + static value *func = NULL; + + if (func == NULL) { + /* First time around, lookup by name */ + func = caml_named_value("libxl_fd_modify"); + } + + args[0] = (value) user; + args[1] = Val_int(fd); + args[2] = Val_poll_events(events); + + caml_callbackN(*func, 3, args); + CAMLreturn(0); +} + +void fd_deregister(void *user, int fd, void *for_app_registration) +{ + CAMLparam0(); + CAMLlocalN(args, 2); + static value *func = NULL; + + if (func == NULL) { + /* First time around, lookup by name */ + func = caml_named_value("libxl_fd_deregister"); + } + + args[0] = (value) user; + args[1] = Val_int(fd); + + caml_callbackN(*func, 2, args); + CAMLreturn0; +} + +int timeout_register(void *user, void **for_app_registration_out, + struct timeval abs, void *for_libxl) +{ + CAMLparam0(); + CAMLlocalN(args, 4); + static value *func = NULL; + + if (func == NULL) { + /* First time around, lookup by name */ + func = caml_named_value("libxl_timeout_register"); + } + + args[0] = (value) user; + args[1] = Val_int(abs.tv_sec); + args[2] = Val_int(abs.tv_usec); + args[3] = (value) for_libxl; + + caml_callbackN(*func, 4, args); + CAMLreturn(0); +} + +int timeout_modify(void *user, void **for_app_registration_update, + struct timeval abs) +{ + CAMLparam0(); + static value *func = NULL; + + if (func == NULL) { + /* First time around, lookup by name */ + func = caml_named_value("libxl_timeout_modify"); + } + + caml_callback(*func, (value) user); + CAMLreturn(0); +} + +void timeout_deregister(void *user, void *for_app_registration) +{ + failwith_xl(ERROR_FAIL, "timeout_deregister not yet implemented"); + return; +} + +value stub_libxl_osevent_register_hooks(value ctx, value user) +{ + CAMLparam2(ctx, user); + CAMLlocal1(result); + libxl_osevent_hooks *hooks; + + hooks = malloc(sizeof(*hooks)); + hooks->fd_register = fd_register; + hooks->fd_modify = fd_modify; + hooks->fd_deregister = fd_deregister; + hooks->timeout_register = timeout_register; + hooks->timeout_modify = timeout_modify; + hooks->timeout_deregister = timeout_deregister; + + libxl_osevent_register_hooks(CTX, hooks, (void *) user); + result = caml_alloc(1, Abstract_tag); + *((libxl_osevent_hooks **) result) = hooks; + + CAMLreturn(result); +} + +value stub_libxl_osevent_occurred_fd(value ctx, value for_libxl, value fd, + value events, value revents) +{ + CAMLparam5(ctx, for_libxl, fd, events, revents); + libxl_osevent_occurred_fd(CTX, (void *) for_libxl, Int_val(fd), + Poll_events_val(events), Poll_events_val(revents)); + CAMLreturn(Val_unit); +} + +value stub_libxl_osevent_occurred_timeout(value ctx, value for_libxl) +{ + CAMLparam2(ctx, for_libxl); + libxl_osevent_occurred_timeout(CTX, (void *) for_libxl); + CAMLreturn(Val_unit); +} + +struct user_with_ctx { + libxl_ctx *ctx; + void *user; +}; + +void event_occurs(void *user, libxl_event *event) +{ + CAMLparam0(); + CAMLlocalN(args, 2); + struct user_with_ctx *c_user = (struct user_with_ctx *) user; + static value *func = NULL; + + if (func == NULL) { + /* First time around, lookup by name */ + func = caml_named_value("libxl_event_occurs_callback"); + } + + args[0] = (value) c_user->user; + args[1] = Val_event(event); + libxl_event_free(c_user->ctx, event); + + caml_callbackN(*func, 2, args); + CAMLreturn0; +} + +void disaster(void *user, libxl_event_type type, + const char *msg, int errnoval) +{ + CAMLparam0(); + CAMLlocalN(args, 2); + struct user_with_ctx *c_user = (struct user_with_ctx *) user; + static value *func = NULL; + + if (func == NULL) { + /* First time around, lookup by name */ + func = caml_named_value("libxl_event_disaster_callback"); + } + + args[0] = (value) c_user->user; + args[1] = Val_event_type(type); + args[2] = caml_copy_string(msg); + args[3] = Val_int(errnoval); + + caml_callbackN(*func, 4, args); + CAMLreturn0; +} + +value stub_libxl_event_register_callbacks(value ctx, value user) +{ + CAMLparam2(ctx, user); + CAMLlocal1(result); + struct user_with_ctx *c_user = NULL; + libxl_event_hooks *hooks; + + c_user = malloc(sizeof(*c_user)); + c_user->user = (void *) user; + c_user->ctx = CTX; + + hooks = malloc(sizeof(*hooks)); + hooks->event_occurs_mask = LIBXL_EVENTMASK_ALL; + hooks->event_occurs = event_occurs; + hooks->disaster = disaster; + + libxl_event_register_callbacks(CTX, hooks, (void *) c_user); + result = caml_alloc(1, Abstract_tag); + *((libxl_event_hooks **) result) = hooks; + + CAMLreturn(result); +} + +value stub_libxl_evenable_domain_death(value ctx, value domid, value user) +{ + CAMLparam3(ctx, domid, user); + libxl_evgen_domain_death *evgen_out; + + libxl_evenable_domain_death(CTX, Int_val(domid), Int_val(user), &evgen_out); + + CAMLreturn(Val_unit); +} + /* * Local variables: * indent-tabs-mode: t -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 23/30] libxl: ocaml: allow device operations to be called asynchronously
Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 6 +++--- tools/ocaml/libs/xl/xenlight_stubs.c | 14 +++++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index 23de43a..57ec143 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -22,9 +22,9 @@ builtins = { "libxl_cpuid_policy_list": ("unit", "%(c)s = 0", "Val_unit"), } -DEVICE_FUNCTIONS = [ ("add", ["ctx", "t", "domid", "unit"]), - ("remove", ["ctx", "t", "domid", "unit"]), - ("destroy", ["ctx", "t", "domid", "unit"]), +DEVICE_FUNCTIONS = [ ("add", ["ctx", "t", "domid", "?async:''a", "unit", "unit"]), + ("remove", ["ctx", "t", "domid", "?async:''a", "unit", "unit"]), + ("destroy", ["ctx", "t", "domid", "?async:''a", "unit", "unit"]), ] functions = { # ( name , [type1,type2,....] ) diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index c98a660..5ac8213 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -420,15 +420,23 @@ void async_callback(libxl_ctx *ctx, int rc, void *for_callback) #define STRINGIFY(x) _STRINGIFY(x) #define _DEVICE_ADDREMOVE(type,op) \ -value stub_xl_device_##type##_##op(value ctx, value info, value domid) \ +value stub_xl_device_##type##_##op(value ctx, value info, value domid, \ + value async, value unit) \ { \ - CAMLparam3(ctx, info, domid); \ + CAMLparam5(ctx, info, domid, async, unit); \ libxl_device_##type c_info; \ int ret, marker_var; \ + libxl_asyncop_how ao_how; \ \ device_##type##_val(CTX, &c_info, info); \ \ - ret = libxl_device_##type##_##op(CTX, Int_val(domid), &c_info, 0); \ + if (async != Val_none) { \ + ao_how.callback = async_callback; \ + ao_how.u.for_callback = (void *) Some_val(async); \ + } \ + \ + ret = libxl_device_##type##_##op(CTX, Int_val(domid), &c_info, \ + async != Val_none ? &ao_how : NULL); \ \ libxl_device_##type##_dispose(&c_info); \ \ -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 24/30] libxl: ocaml: add NIC helper functions
Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 5 ++++- tools/ocaml/libs/xl/xenlight_stubs.c | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index 57ec143..c99326b 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -31,7 +31,10 @@ functions = { # ( name , [type1,type2,....] ) "device_vfb": DEVICE_FUNCTIONS, "device_vkb": DEVICE_FUNCTIONS, "device_disk": DEVICE_FUNCTIONS, - "device_nic": DEVICE_FUNCTIONS, + "device_nic": DEVICE_FUNCTIONS + + [ ("list", ["ctx", "domid", "t list"]), + ("of_devid", ["ctx", "domid", "int", "t"]), + ], "device_pci": DEVICE_FUNCTIONS, "dominfo": [ ("list", ["ctx", "t list"]), ("get", ["ctx", "domid", "t"]), diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index 5ac8213..d833ba1 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -457,6 +457,42 @@ DEVICE_ADDREMOVE(vfb) DEVICE_ADDREMOVE(vkb) DEVICE_ADDREMOVE(pci) +value stub_xl_device_nic_of_devid(value ctx, value domid, value devid) +{ + CAMLparam3(ctx, domid, devid); + libxl_device_nic nic; + libxl_devid_to_device_nic(CTX, Int_val(domid), Int_val(devid), &nic); + CAMLreturn(Val_device_nic(&nic)); +} + +value stub_xl_device_nic_list(value ctx, value domid) +{ + CAMLparam2(ctx, domid); + CAMLlocal2(list, temp); + libxl_device_nic *c_list; + int i, nb; + uint32_t c_domid; + + c_domid = Int_val(domid); + + c_list = libxl_device_nic_list(CTX, c_domid, &nb); + if (!c_list) + failwith_xl(ERROR_FAIL, "nic_list"); + + list = temp = Val_emptylist; + for (i = 0; i < nb; i++) { + list = caml_alloc_small(2, Tag_cons); + Field(list, 0) = Val_int(0); + Field(list, 1) = temp; + temp = list; + Store_field(list, 0, Val_device_nic(&c_list[i])); + libxl_device_nic_dispose(&c_list[i]); + } + free(c_list); + + CAMLreturn(list); +} + value stub_xl_physinfo_get(value ctx) { CAMLparam1(ctx); -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 25/30] libxl: ocaml: add PCI device helper functions
Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 7 ++- tools/ocaml/libs/xl/xenlight_stubs.c | 90 ++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+), 1 deletion(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index c99326b..489ae9d 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -35,7 +35,12 @@ functions = { # ( name , [type1,type2,....] ) [ ("list", ["ctx", "domid", "t list"]), ("of_devid", ["ctx", "domid", "int", "t"]), ], - "device_pci": DEVICE_FUNCTIONS, + "device_pci": DEVICE_FUNCTIONS + + [ ("list", ["ctx", "domid", "t list"]), + ("assignable_add", ["ctx", "t", "bool", "unit"]), + ("assignable_remove", ["ctx", "t", "bool", "unit"]), + ("assignable_list", ["ctx", "t list"]), + ], "dominfo": [ ("list", ["ctx", "t list"]), ("get", ["ctx", "domid", "t"]), ], diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index d833ba1..51ed855 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -493,6 +493,96 @@ value stub_xl_device_nic_list(value ctx, value domid) CAMLreturn(list); } +value stub_xl_device_pci_list(value ctx, value domid) +{ + CAMLparam2(ctx, domid); + CAMLlocal2(list, temp); + libxl_device_pci *c_list; + int i, nb; + uint32_t c_domid; + + c_domid = Int_val(domid); + + c_list = libxl_device_pci_list(CTX, c_domid, &nb); + if (!c_list) + failwith_xl(ERROR_FAIL, "pci_list"); + + list = temp = Val_emptylist; + for (i = 0; i < nb; i++) { + list = caml_alloc_small(2, Tag_cons); + Field(list, 0) = Val_int(0); + Field(list, 1) = temp; + temp = list; + Store_field(list, 0, Val_device_pci(&c_list[i])); + libxl_device_pci_dispose(&c_list[i]); + } + free(c_list); + + CAMLreturn(list); +} + +value stub_xl_device_pci_assignable_add(value ctx, value info, value rebind) +{ + CAMLparam3(ctx, info, rebind); + libxl_device_pci c_info; + int ret, marker_var; + + device_pci_val(CTX, &c_info, info); + + ret = libxl_device_pci_assignable_add(CTX, &c_info, (int) Bool_val(rebind)); + + libxl_device_pci_dispose(&c_info); + + if (ret != 0) + failwith_xl(ret, "pci_assignable_add"); + + CAMLreturn(Val_unit); +} + +value stub_xl_device_pci_assignable_remove(value ctx, value info, value rebind) +{ + CAMLparam3(ctx, info, rebind); + libxl_device_pci c_info; + int ret, marker_var; + + device_pci_val(CTX, &c_info, info); + + ret = libxl_device_pci_assignable_remove(CTX, &c_info, (int) Bool_val(rebind)); + + libxl_device_pci_dispose(&c_info); + + if (ret != 0) + failwith_xl(ret, "pci_assignable_remove"); + + CAMLreturn(Val_unit); +} + +value stub_xl_device_pci_assignable_list(value ctx) +{ + CAMLparam1(ctx); + CAMLlocal2(list, temp); + libxl_device_pci *c_list; + int i, nb; + uint32_t c_domid; + + c_list = libxl_device_pci_assignable_list(CTX, &nb); + if (!c_list) + failwith_xl(ERROR_FAIL, "pci_assignable_list"); + + list = temp = Val_emptylist; + for (i = 0; i < nb; i++) { + list = caml_alloc_small(2, Tag_cons); + Field(list, 0) = Val_int(0); + Field(list, 1) = temp; + temp = list; + Store_field(list, 0, Val_device_pci(&c_list[i])); + libxl_device_pci_dispose(&c_list[i]); + } + free(c_list); + + CAMLreturn(list); +} + value stub_xl_physinfo_get(value ctx) { CAMLparam1(ctx); -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 26/30] libxl: ocaml: add disk and cdrom helper functions
Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 17 +++++++----- tools/ocaml/libs/xl/xenlight_stubs.c | 47 ++++++++++++++++++++++++++++++---- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index 489ae9d..92326e1 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -26,18 +26,21 @@ DEVICE_FUNCTIONS = [ ("add", ["ctx", "t", "domid", "?async:''a", "unit ("remove", ["ctx", "t", "domid", "?async:''a", "unit", "unit"]), ("destroy", ["ctx", "t", "domid", "?async:''a", "unit", "unit"]), ] +DEVICE_LIST = [ ("list", ["ctx", "domid", "t list"]), + ] functions = { # ( name , [type1,type2,....] ) "device_vfb": DEVICE_FUNCTIONS, "device_vkb": DEVICE_FUNCTIONS, - "device_disk": DEVICE_FUNCTIONS, - "device_nic": DEVICE_FUNCTIONS + - [ ("list", ["ctx", "domid", "t list"]), - ("of_devid", ["ctx", "domid", "int", "t"]), + "device_disk": DEVICE_FUNCTIONS + DEVICE_LIST + + [ ("insert", ["ctx", "t", "domid", "?async:''a", "unit", "unit"]), + ("of_vdev", ["ctx", "domid", "string", "t"]), + ], + "device_nic": DEVICE_FUNCTIONS + DEVICE_LIST + + [ ("of_devid", ["ctx", "domid", "int", "t"]), ], - "device_pci": DEVICE_FUNCTIONS + - [ ("list", ["ctx", "domid", "t list"]), - ("assignable_add", ["ctx", "t", "bool", "unit"]), + "device_pci": DEVICE_FUNCTIONS + DEVICE_LIST + + [ ("assignable_add", ["ctx", "t", "bool", "unit"]), ("assignable_remove", ["ctx", "t", "bool", "unit"]), ("assignable_list", ["ctx", "t list"]), ], diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index 51ed855..0faa425 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -419,7 +419,7 @@ void async_callback(libxl_ctx *ctx, int rc, void *for_callback) #define _STRINGIFY(x) #x #define STRINGIFY(x) _STRINGIFY(x) -#define _DEVICE_ADDREMOVE(type,op) \ +#define _DEVICE_ADDREMOVE(type,fn,op) \ value stub_xl_device_##type##_##op(value ctx, value info, value domid, \ value async, value unit) \ { \ @@ -435,7 +435,7 @@ value stub_xl_device_##type##_##op(value ctx, value info, value domid, \ ao_how.u.for_callback = (void *) Some_val(async); \ } \ \ - ret = libxl_device_##type##_##op(CTX, Int_val(domid), &c_info, \ + ret = libxl_##fn##_##op(CTX, Int_val(domid), &c_info, \ async != Val_none ? &ao_how : NULL); \ \ libxl_device_##type##_dispose(&c_info); \ @@ -447,15 +447,16 @@ value stub_xl_device_##type##_##op(value ctx, value info, value domid, \ } #define DEVICE_ADDREMOVE(type) \ - _DEVICE_ADDREMOVE(type, add) \ - _DEVICE_ADDREMOVE(type, remove) \ - _DEVICE_ADDREMOVE(type, destroy) + _DEVICE_ADDREMOVE(type, device_##type, add) \ + _DEVICE_ADDREMOVE(type, device_##type, remove) \ + _DEVICE_ADDREMOVE(type, device_##type, destroy) DEVICE_ADDREMOVE(disk) DEVICE_ADDREMOVE(nic) DEVICE_ADDREMOVE(vfb) DEVICE_ADDREMOVE(vkb) DEVICE_ADDREMOVE(pci) +_DEVICE_ADDREMOVE(disk, cdrom, insert) value stub_xl_device_nic_of_devid(value ctx, value domid, value devid) { @@ -493,6 +494,42 @@ value stub_xl_device_nic_list(value ctx, value domid) CAMLreturn(list); } +value stub_xl_device_disk_list(value ctx, value domid) +{ + CAMLparam2(ctx, domid); + CAMLlocal2(list, temp); + libxl_device_disk *c_list; + int i, nb; + uint32_t c_domid; + + c_domid = Int_val(domid); + + c_list = libxl_device_disk_list(CTX, c_domid, &nb); + if (!c_list) + failwith_xl(ERROR_FAIL, "disk_list"); + + list = temp = Val_emptylist; + for (i = 0; i < nb; i++) { + list = caml_alloc_small(2, Tag_cons); + Field(list, 0) = Val_int(0); + Field(list, 1) = temp; + temp = list; + Store_field(list, 0, Val_device_disk(&c_list[i])); + libxl_device_disk_dispose(&c_list[i]); + } + free(c_list); + + CAMLreturn(list); +} + +value stub_xl_device_disk_of_vdev(value ctx, value domid, value vdev) +{ + CAMLparam3(ctx, domid, vdev); + libxl_device_disk disk; + libxl_vdev_to_device_disk(CTX, Int_val(domid), String_val(vdev), &disk); + CAMLreturn(Val_device_disk(&disk)); +} + value stub_xl_device_pci_list(value ctx, value domid) { CAMLparam2(ctx, domid); -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 27/30] libxl: ocaml: add VM lifecycle operations
Also, reorganise toplevel OCaml functions into modules of Xenlight. Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/xenlight.ml.in | 23 +++- tools/ocaml/libs/xl/xenlight.mli.in | 23 +++- tools/ocaml/libs/xl/xenlight_stubs.c | 198 ++++++++++++++++++++++++++++++++++ tools/ocaml/test/send_debug_keys.ml | 2 +- 4 files changed, 237 insertions(+), 9 deletions(-) diff --git a/tools/ocaml/libs/xl/xenlight.ml.in b/tools/ocaml/libs/xl/xenlight.ml.in index 06c9f52..4cfd085 100644 --- a/tools/ocaml/libs/xl/xenlight.ml.in +++ b/tools/ocaml/libs/xl/xenlight.ml.in @@ -66,10 +66,25 @@ type event (* @@LIBXL_TYPES@@ *) -external send_trigger : ctx -> domid -> trigger -> int -> unit = "stub_xl_send_trigger" -external send_sysrq : ctx -> domid -> char -> unit = "stub_xl_send_sysrq" -external send_debug_keys : ctx -> string -> unit = "stub_xl_send_debug_keys" -external xen_console_read : ctx -> string list = "stub_xl_xen_console_read" +module Domain = struct + external create_new : ctx -> Domain_config.t -> ?async:''a -> unit -> domid = "stub_libxl_domain_create_new" + external create_restore : ctx -> Domain_config.t -> Unix.file_descr -> ?async:''a -> unit -> domid = "stub_libxl_domain_create_restore" + external shutdown : ctx -> domid -> unit = "stub_libxl_domain_shutdown" + external wait_shutdown : ctx -> domid -> unit = "stub_libxl_domain_wait_shutdown" + external reboot : ctx -> domid -> unit = "stub_libxl_domain_reboot" + external destroy : ctx -> domid -> ?async:''a -> unit -> unit = "stub_libxl_domain_destroy" + external suspend : ctx -> domid -> Unix.file_descr -> ?async:''a -> unit -> unit = "stub_libxl_domain_suspend" + external pause : ctx -> domid -> unit = "stub_libxl_domain_pause" + external unpause : ctx -> domid -> unit = "stub_libxl_domain_unpause" + + external send_trigger : ctx -> domid -> trigger -> int -> unit = "stub_xl_send_trigger" + external send_sysrq : ctx -> domid -> char -> unit = "stub_xl_send_sysrq" +end + +module Host = struct + external send_debug_keys : ctx -> string -> unit = "stub_xl_send_debug_keys" + external xen_console_read : ctx -> string list = "stub_xl_xen_console_read" +end module type EVENT_USERS sig diff --git a/tools/ocaml/libs/xl/xenlight.mli.in b/tools/ocaml/libs/xl/xenlight.mli.in index 0b06712..d49edde 100644 --- a/tools/ocaml/libs/xl/xenlight.mli.in +++ b/tools/ocaml/libs/xl/xenlight.mli.in @@ -51,10 +51,25 @@ type event (* @@LIBXL_TYPES@@ *) -external send_trigger : ctx -> domid -> trigger -> int -> unit = "stub_xl_send_trigger" -external send_sysrq : ctx -> domid -> char -> unit = "stub_xl_send_sysrq" -external send_debug_keys : ctx -> string -> unit = "stub_xl_send_debug_keys" -external xen_console_read : ctx -> string list = "stub_xl_xen_console_read" +module Domain : sig + external create_new : ctx -> Domain_config.t -> ?async:''a -> unit -> domid = "stub_libxl_domain_create_new" + external create_restore : ctx -> Domain_config.t -> Unix.file_descr -> ?async:''a -> unit -> domid = "stub_libxl_domain_create_restore" + external shutdown : ctx -> domid -> unit = "stub_libxl_domain_shutdown" + external wait_shutdown : ctx -> domid -> unit = "stub_libxl_domain_wait_shutdown" + external reboot : ctx -> domid -> unit = "stub_libxl_domain_reboot" + external destroy : ctx -> domid -> ?async:''a -> unit -> unit = "stub_libxl_domain_destroy" + external suspend : ctx -> domid -> Unix.file_descr -> ?async:''a -> unit -> unit = "stub_libxl_domain_suspend" + external pause : ctx -> domid -> unit = "stub_libxl_domain_pause" + external unpause : ctx -> domid -> unit = "stub_libxl_domain_unpause" + + external send_trigger : ctx -> domid -> trigger -> int -> unit = "stub_xl_send_trigger" + external send_sysrq : ctx -> domid -> char -> unit = "stub_xl_send_sysrq" +end + +module Host : sig + external send_debug_keys : ctx -> string -> unit = "stub_xl_send_debug_keys" + external xen_console_read : ctx -> string list = "stub_xl_xen_console_read" +end module type EVENT_USERS sig diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index 0faa425..aab3b21 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -416,6 +416,204 @@ void async_callback(libxl_ctx *ctx, int rc, void *for_callback) caml_callback2(*func, error, (value) for_callback); } +static int domain_wait_event(libxl_ctx *ctx, int domid, libxl_event **event_r) +{ + int ret; + for (;;) { + ret = libxl_event_wait(ctx, event_r, LIBXL_EVENTMASK_ALL, 0,0); + if (ret) { + return ret; + } + if ((*event_r)->domid != domid) { + libxl_event_free(CTX, *event_r); + continue; + } + return ret; + } +} + +value stub_libxl_domain_create_new(value ctx, value domain_config, value async, value unit) +{ + CAMLparam4(ctx, async, domain_config, unit); + int ret; + libxl_domain_config c_dconfig; + uint32_t c_domid; + libxl_asyncop_how ao_how; + + if (async != Val_none) { + ao_how.callback = async_callback; + ao_how.u.for_callback = (void *) Some_val(async); + } + + libxl_domain_config_init(&c_dconfig); + ret = domain_config_val(CTX, &c_dconfig, domain_config); + if (ret != 0) { + libxl_domain_config_dispose(&c_dconfig); + failwith_xl(ret, "domain_create_new"); + } + + ret = libxl_domain_create_new(CTX, &c_dconfig, &c_domid, + async != Val_none ? &ao_how : NULL, NULL); + + libxl_domain_config_dispose(&c_dconfig); + + if (ret != 0) + failwith_xl(ret, "domain_create_new"); + + CAMLreturn(Val_int(c_domid)); +} + +value stub_libxl_domain_create_restore(value ctx, value domain_config, value restore_fd, value async, value unit) +{ + CAMLparam5(ctx, domain_config, restore_fd, async, unit); + int ret; + libxl_domain_config c_dconfig; + uint32_t c_domid; + libxl_asyncop_how ao_how; + + if (async != Val_none) { + ao_how.callback = async_callback; + ao_how.u.for_callback = (void *) Some_val(async); + } + + libxl_domain_config_init(&c_dconfig); + ret = domain_config_val(CTX, &c_dconfig, domain_config); + if (ret != 0) { + libxl_domain_config_dispose(&c_dconfig); + failwith_xl(ret, "domain_create_restore"); + } + + ret = libxl_domain_create_restore(CTX, &c_dconfig, &c_domid, Int_val(restore_fd), + async != Val_none ? &ao_how : NULL, NULL); + + libxl_domain_config_dispose(&c_dconfig); + + if (ret != 0) + failwith_xl(ret, "domain_create_restore"); + + CAMLreturn(Val_int(c_domid)); +} + +value stub_libxl_domain_wait_shutdown(value ctx, value domid) +{ + CAMLparam2(ctx, domid); + int ret; + libxl_event *event; + libxl_evgen_domain_death *deathw; + ret = libxl_evenable_domain_death(CTX, Int_val(domid), 0, &deathw); + if (ret) + failwith_xl(ret, "domain_wait_shutdown"); + + for (;;) { + ret = domain_wait_event(CTX, Int_val(domid), &event); + if (ret) { + libxl_evdisable_domain_death(CTX, deathw); + failwith_xl(ret, "domain_wait_shutdown"); + } + + switch (event->type) { + case LIBXL_EVENT_TYPE_DOMAIN_DEATH: + goto done; + case LIBXL_EVENT_TYPE_DOMAIN_SHUTDOWN: + goto done; + default: + break; + } + libxl_event_free(CTX, event); + } +done: + libxl_event_free(CTX, event); + libxl_evdisable_domain_death(CTX, deathw); + + CAMLreturn(Val_unit); +} + +value stub_libxl_domain_shutdown(value ctx, value domid) +{ + CAMLparam2(ctx, domid); + int ret; + + ret = libxl_domain_shutdown(CTX, Int_val(domid)); + if (ret != 0) + failwith_xl(ret, "domain_shutdown"); + + CAMLreturn(Val_unit); +} + +value stub_libxl_domain_reboot(value ctx, value domid) +{ + CAMLparam2(ctx, domid); + int ret; + + ret = libxl_domain_reboot(CTX, Int_val(domid)); + if (ret != 0) + failwith_xl(ret, "domain_reboot"); + + CAMLreturn(Val_unit); +} + +value stub_libxl_domain_destroy(value ctx, value domid, value async, value unit) +{ + CAMLparam4(ctx, domid, async, unit); + int ret; + libxl_asyncop_how ao_how; + + if (async != Val_none) { + ao_how.callback = async_callback; + ao_how.u.for_callback = (void *) Some_val(async); + } + + ret = libxl_domain_destroy(CTX, Int_val(domid), + async != Val_none ? &ao_how : NULL); + if (ret != 0) + failwith_xl(ret, "domain_destroy"); + + CAMLreturn(Val_unit); +} + +value stub_libxl_domain_suspend(value ctx, value domid, value fd, value async, value unit) +{ + CAMLparam5(ctx, domid, fd, async, unit); + int ret; + libxl_asyncop_how ao_how; + + if (async != Val_none) { + ao_how.callback = async_callback; + ao_how.u.for_callback = (void *) Some_val(async); + } + + ret = libxl_domain_suspend(CTX, Int_val(domid), Int_val(fd), 0, + async != Val_none ? &ao_how : NULL); + if (ret != 0) + failwith_xl(ret, "domain_suspend"); + + CAMLreturn(Val_unit); +} + +value stub_libxl_domain_pause(value ctx, value domid) +{ + CAMLparam2(ctx, domid); + int ret; + + ret = libxl_domain_pause(CTX, Int_val(domid)); + if (ret != 0) + failwith_xl(ret, "domain_pause"); + + CAMLreturn(Val_unit); +} + +value stub_libxl_domain_unpause(value ctx, value domid) +{ + CAMLparam2(ctx, domid); + int ret; + + ret = libxl_domain_unpause(CTX, Int_val(domid)); + if (ret != 0) + failwith_xl(ret, "domain_unpause"); + + CAMLreturn(Val_unit); +} + #define _STRINGIFY(x) #x #define STRINGIFY(x) _STRINGIFY(x) diff --git a/tools/ocaml/test/send_debug_keys.ml b/tools/ocaml/test/send_debug_keys.ml index 6db89e8..6cf59ea 100644 --- a/tools/ocaml/test/send_debug_keys.ml +++ b/tools/ocaml/test/send_debug_keys.ml @@ -5,7 +5,7 @@ open Xenlight let send_keys ctx s = printf "Sending debug key %s\n" s; - Xenlight.send_debug_keys ctx s; + Xenlight.Host.send_debug_keys ctx s; () let _ = -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 28/30] libxl: ocaml: in send_debug_keys, clean up before raising exception
Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/xenlight_stubs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ocaml/libs/xl/xenlight_stubs.c b/tools/ocaml/libs/xl/xenlight_stubs.c index aab3b21..084961a 100644 --- a/tools/ocaml/libs/xl/xenlight_stubs.c +++ b/tools/ocaml/libs/xl/xenlight_stubs.c @@ -981,11 +981,11 @@ value stub_xl_send_debug_keys(value ctx, value keys) c_keys = dup_String_val(keys); ret = libxl_send_debug_keys(CTX, c_keys); + free(c_keys); + if (ret != 0) failwith_xl(ret, "send_debug_keys"); - free(c_keys); - CAMLreturn(Val_unit); } -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 29/30] libxl: ocaml: provide defaults for libxl types
Libxl functions such as libxl_domain_create_new take large structs of configuration parameters. Often, we would like to use the default values for many of these parameters. The struct and keyed-union types in libxl have init functions, which fill in the defaults for a given type. This commit provides an OCaml interface to obtain records of defaults by calling the relevant init function. These default records can be used as a base to construct your own records, and to selectively override parameters where needed. For example, a Domain_create_info record can now be created as follows: Xenlight.Domain_create_info.({ default ctx () with ty = Xenlight.DOMAIN_TYPE_PV; name = Some vm_name; uuid = vm_uuid; }) For types with KeyedUnion fields, such as Domain_build_info, a record with defaults is obtained by specifying the type key: Xenlight.Domain_build_info.default ctx ~ty:Xenlight.DOMAIN_TYPE_HVM () Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 61 +++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 7 deletions(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index 92326e1..7738b96 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -115,6 +115,7 @@ def gen_struct(ty): def gen_ocaml_keyedunions(ty, interface, indent, parent = None): s = "" + union_type = "" if ty.rawname is not None: # Non-anonymous types need no special handling @@ -154,9 +155,11 @@ def gen_ocaml_keyedunions(ty, interface, indent, parent = None): s += " | ".join(u) + "\n" ty.union_name = name + union_type = "?%s:%s" % (munge_name(nparent), ty.keyvar.type.rawname) + if s == "": - return None - return s.replace("\n", "\n%s" % indent) + return None, None + return s.replace("\n", "\n%s" % indent), union_type def gen_ocaml_ml(ty, interface, indent=""): @@ -184,17 +187,27 @@ def gen_ocaml_ml(ty, interface, indent=""): s += "module %s = struct\n" % module_name # Handle KeyedUnions... + union_types = [] for f in ty.fields: - ku = gen_ocaml_keyedunions(f.type, interface, "\t") + ku, union_type = gen_ocaml_keyedunions(f.type, interface, "\t") if ku is not None: s += ku s += "\n" + if union_type is not None: + union_types.append(union_type) s += "\ttype t =\n" s += "\t{\n" s += gen_struct(ty) s += "\t}\n" - + + if ty.init_fn is not None: + union_args = "".join([u + " -> " for u in union_types]) + if interface: + s += "\tval default : ctx -> %sunit -> t\n" % union_args + else: + s += "\texternal default : ctx -> %sunit -> t = \"stub_libxl_%s_init\"\n" % (union_args, ty.rawname) + if functions.has_key(ty.rawname): for name,args in functions[ty.rawname]: s += "\texternal %s : " % name @@ -422,6 +435,38 @@ def gen_c_stub_prototype(ty, fns): s += ");\n" return s +def gen_c_default(ty): + s = "/* Get the defaults for %s */\n" % ty.rawname + # Handle KeyedUnions... + union_types = [] + for f in ty.fields: + if isinstance(f.type, idl.KeyedUnion): + union_types.append(f.type.keyvar) + + s += "value stub_libxl_%s_init(value ctx, %svalue unit)\n" % (ty.rawname, + "".join(["value " + u.name + ", " for u in union_types])) + s += "{\n" + s += "\tCAMLparam%d(ctx, %sunit);\n" % (len(union_types) + 2, "".join([u.name + ", " for u in union_types])) + s += "\tCAMLlocal1(val);\n" + s += "\tlibxl_%s c_val;\n" % ty.rawname + s += "\tlibxl_%s_init(&c_val);\n" % ty.rawname + for u in union_types: + s += "\tif (%s != Val_none) {\n" % u.name + s += "\t\t%s c = 0;\n" % u.type.typename + s += "\t\t%s_val(CTX, &c, Some_val(%s));\n" % (u.type.rawname, u.name) + s += "\t\tlibxl_%s_init_%s(&c_val, c);\n" % (ty.rawname, u.name) + s += "\t}\n" + s += "\tval = Val_%s(&c_val);\n" % ty.rawname + if ty.dispose_fn: + s += "\tlibxl_%s_dispose(&c_val);\n" % ty.rawname + s += "\tCAMLreturn(val);\n" + s += "}\n" + return s + +def gen_c_defaults(ty): + s = gen_c_default(ty) + return s + def autogen_header(open_comment, close_comment): s = open_comment + " AUTO-GENERATED FILE DO NOT EDIT " + close_comment + "\n" s += open_comment + " autogenerated by \n" @@ -474,12 +519,14 @@ if __name__ == ''__main__'': if ty.marshal_in(): cinc.write(gen_c_val(ty)) cinc.write("\n") - if ty.marshal_out(): - cinc.write(gen_Val_ocaml(ty)) - cinc.write("\n") + cinc.write(gen_Val_ocaml(ty)) + cinc.write("\n") if functions.has_key(ty.rawname): cinc.write(gen_c_stub_prototype(ty, functions[ty.rawname])) cinc.write("\n") + if ty.init_fn is not None: + cinc.write(gen_c_defaults(ty)) + cinc.write("\n") #sys.stdout.write("\n") ml.write("(* END OF AUTO-GENERATED CODE *)\n") -- 1.7.10.4
Rob Hoes
2013-Aug-22 10:51 UTC
[PATCH v2-resend 30/30] libxl: ocaml: use CAMLlocal1 macro rather than value-type in auto-generated C-code
Signed-off-by: Rob Hoes <rob.hoes@citrix.com> --- tools/ocaml/libs/xl/genwrap.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/ocaml/libs/xl/genwrap.py b/tools/ocaml/libs/xl/genwrap.py index 7738b96..e074f5e 100644 --- a/tools/ocaml/libs/xl/genwrap.py +++ b/tools/ocaml/libs/xl/genwrap.py @@ -341,7 +341,7 @@ def ocaml_Val(ty, o, c, indent="", parent = None): elif isinstance(ty, idl.Array): s += "{\n" s += "\t int i;\n" - s += "\t value array_elem;\n" + s += "\t CAMLlocal1(array_elem);\n" s += "\t %s = caml_alloc(%s,0);\n" % (o, parent + ty.lenvar.name) s += "\t for(i=0; i<%s; i++) {\n" % (parent + ty.lenvar.name) s += "\t %s\n" % ocaml_Val(ty.elem_type, "array_elem", c + "[i]", "", parent=parent) @@ -391,7 +391,7 @@ def ocaml_Val(ty, o, c, indent="", parent = None): fn = "anon_field" else: fn = "%s_field" % ty.rawname - s += "\tvalue %s;\n" % fn + s += "\tCAMLlocal1(%s);\n" % fn s += "\n" s += "\t%s = caml_alloc_tuple(%d);\n" % (o, len(ty.fields)) -- 1.7.10.4
Ian Jackson
2013-Aug-27 14:53 UTC
Re: [PATCH v2-resend 02/30] libxl: idl: allow KeyedUnion members to be empty
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 02/30] libxl: idl: allow KeyedUnion members to be empty"):> This is useful when the key enum has an "invalid" option and avoids > the need to declare a dummy struct. Use this for domain_build_info > resulting in the generated API changing like so: > --- tools/libxl/_libxl_BACKUP_types.h > +++ tools/libxl/_libxl_types.h > @@ -377,8 +377,6 @@ typedef struct libxl_domain_build_info { > const char * features; > libxl_defbool e820_host; > } pv; > - struct { > - } invalid; > } u;I assume that the problem here is that the compiler rejects the empty struct.> - ("invalid", Struct(None, [])), > + ("invalid", None),Is it really necessary to do this with a special-cased new "None" type rather than just fixing the empty structs by putting a dummy member in them ? Ian.
Ian Jackson
2013-Aug-27 14:54 UTC
Re: [PATCH v2-resend 01/30] libxl: Add LIBXL_SHUTDOWN_REASON_UNKNOWN
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 01/30] libxl: Add LIBXL_SHUTDOWN_REASON_UNKNOWN"):> libxl_dominfo.shutdown_reason is valid iff (shutdown||dying). This is a bit > annoying when generating language bindings since it needs all sorts of special > casing. Just introduce an explicit value instead.Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Ian Jackson
2013-Aug-27 14:55 UTC
Re: [PATCH v2-resend 03/30] libxl: idl: add domain_type field to libxl_dominfo struct
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 03/30] libxl: idl: add domain_type field to libxl_dominfo struct"):> This allows a toolstack to find out whether a VM has booted as PV or HVM.Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Ian Jackson
2013-Aug-27 14:56 UTC
Re: [PATCH v2-resend 04/30] libxl: idl: complete some enums in the IDL with their defaults
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 04/30] libxl: idl: complete some enums in the IDL with their defaults"):> There are several enums in the IDL that are initialised to 0, while > the value 0 is not part of the enum itself. This creates problems for > language bindings generated from the IDL, such as the OCaml ones. > > Added an explicit (0, "UNKNOWN") enum value where appropriate, or used > init_val to default to a sensible value.Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> (I haven''t double checked each of these changes against the context, but the principle is sound.) Ian.
Ian Campbell
2013-Aug-27 14:56 UTC
Re: [PATCH v2-resend 02/30] libxl: idl: allow KeyedUnion members to be empty
On Tue, 2013-08-27 at 15:53 +0100, Ian Jackson wrote:> Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 02/30] libxl: idl: allow KeyedUnion members to be empty"): > > This is useful when the key enum has an "invalid" option and avoids > > the need to declare a dummy struct. Use this for domain_build_info > > resulting in the generated API changing like so: > > --- tools/libxl/_libxl_BACKUP_types.h > > +++ tools/libxl/_libxl_types.h > > @@ -377,8 +377,6 @@ typedef struct libxl_domain_build_info { > > const char * features; > > libxl_defbool e820_host; > > } pv; > > - struct { > > - } invalid; > > } u; > > I assume that the problem here is that the compiler rejects the empty > struct.I don''t recall exactly, but I think so.> > > - ("invalid", Struct(None, [])), > > + ("invalid", None), > > Is it really necessary to do this with a special-cased new "None" type > rather than just fixing the empty structs by putting a dummy member in > them ?I''d rather a bit of skaniness in the idl compiler than in the end user facing eventual API. Ian.
Ian Jackson
2013-Aug-27 14:57 UTC
Re: [PATCH v2-resend 05/30] libxl: ocaml: fix code intended to output comments before definitions
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 05/30] libxl: ocaml: fix code intended to output comments before definitions"):> I''m not sure how useful these comments actually are but erred on the > side of fixing rather than removing.Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Ian Jackson
2013-Aug-27 14:59 UTC
Re: [PATCH v2-resend 02/30] libxl: idl: allow KeyedUnion members to be empty
Ian Campbell writes ("Re: [Xen-devel] [PATCH v2-resend 02/30] libxl: idl: allow KeyedUnion members to be empty"):> On Tue, 2013-08-27 at 15:53 +0100, Ian Jackson wrote: > > I assume that the problem here is that the compiler rejects the empty > > struct. > > I don''t recall exactly, but I think so.GCC even permits them as an extension.> > Is it really necessary to do this with a special-cased new "None" type > > rather than just fixing the empty structs by putting a dummy member in > > them ? > > I''d rather a bit of skaniness in the idl compiler than in the end user > facing eventual API.You are introducing skankiness not in the IDL compiler, but in the IDL itself. I think it is better to have skankiness in some particular language''s output than in the IDL input. Ian.
Ian Jackson
2013-Aug-27 14:59 UTC
Re: [PATCH v2-resend 06/30] libxl: ocaml: support for Arrays in bindings generator.
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 06/30] libxl: ocaml: support for Arrays in bindings generator."):> No change in generated code because no arrays are currently generated.This patch doesn''t seem to have code for initialising, freeing, etc., arrays. Shouldn''t it ? Ian.
Ian Jackson
2013-Aug-27 15:01 UTC
Re: [PATCH v2-resend 07/30] libxl: ocaml: avoid reserved words in type and field names.
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 07/30] libxl: ocaml: avoid reserved words in type and field names."):> Current just s/type/ty/ and there are no such fields (yet) so no > change to generated code.I think this should be done in a systematic way, and one which is an injection[1]. What if someone later introduces a field called "ty" in the same struct as one called "type" ? I don''t know what a good convention would be in ocaml, but for example you could prefix everything with "idl_" (including names starting "idl_"). [1] http://en.wikipedia.org/wiki/Injection_%28mathematics%29 Ian.
Ian Campbell
2013-Aug-27 15:04 UTC
Re: [PATCH v2-resend 02/30] libxl: idl: allow KeyedUnion members to be empty
On Tue, 2013-08-27 at 15:59 +0100, Ian Jackson wrote:> Ian Campbell writes ("Re: [Xen-devel] [PATCH v2-resend 02/30] libxl: idl: allow KeyedUnion members to be empty"): > > On Tue, 2013-08-27 at 15:53 +0100, Ian Jackson wrote: > > > I assume that the problem here is that the compiler rejects the empty > > > struct. > > > > I don''t recall exactly, but I think so. > > GCC even permits them as an extension.I thought you meant the ocaml compiler, but of course we aren''t at that part of the series yet.> > > > Is it really necessary to do this with a special-cased new "None" type > > > rather than just fixing the empty structs by putting a dummy member in > > > them ? > > > > I''d rather a bit of skaniness in the idl compiler than in the end user > > facing eventual API. > > You are introducing skankiness not in the IDL compiler, but in the IDL > itself. I think it is better to have skankiness in some particular > language''s output than in the IDL input.I think: - ("invalid", Struct(None, [])), + ("invalid", None), is reducing the amount of skank in the IDL, None has a good match with "nothing here", while "Strict(None, [])" is just random placeholder goo, which would be even worse if we were to artificially add a member In hindsight I might even have gone one further and made it: - ("invalid", Struct(None, [])), + ("invalid"), Ian.
Ian Campbell
2013-Aug-27 15:06 UTC
Re: [PATCH v2-resend 06/30] libxl: ocaml: support for Arrays in bindings generator.
On Tue, 2013-08-27 at 15:59 +0100, Ian Jackson wrote:> Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 06/30] libxl: ocaml: support for Arrays in bindings generator."): > > No change in generated code because no arrays are currently generated. > > This patch doesn''t seem to have code for initialising, freeing, etc., > arrays. Shouldn''t it ?There''s a calloc in there, and each element is initialised with a call to c_val (which will already incorporate a libxl_foo_init as necessry), the free is in the call to libxl_foo_dispose which comes from existing bits of the bindings generator. Ian.
Ian Jackson
2013-Aug-27 15:09 UTC
Re: [PATCH v2-resend 08/30] libxl: ocaml: support for KeyedUnion in the bindings generator.
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 08/30] libxl: ocaml: support for KeyedUnion in the bindings generator."):> A KeyedUnion consists of two fields in the containing struct. First an > enum field ("e") used as a descriminator and second a union ("u") > containing potentially anonymous structs associated with each enum > value....> foo = Enumeration("foo", [ > (0, "BAR"), > (1, "BAZ"), > ]) > s = Struct("s", [ > ("u", KeyedUnion(none, foo, "blargle", [ > ("bar", Struct(...xxx...)), > ("baz", Struct(...yyy...)),I think you have some confusion betwwen bar,baz and foo,bar ? At least, I hope so, as otherwise I haven''t understood at all.> and map this to ocaml > > type foo = BAR | BAZ; > module S = struct > type blargle_bar = ...xxx...; > type blargle_baz = ...yyy...; > type blargle__union = Bar of blargle_bar | Baz of blargle_baz; > type t > { > blargle : blargle__union; > } > endIs this indirection (through S.t) really needed ? It seems a bit ugly. But I''m no expert on ocaml syntax or style.> These type names are OK because they are already within the namespace > associated with the struct "s". > > If the struct associated with bar is empty then we don''t bother with > blargle_bar of "of blargle_bar".I''m not sure I follow this observation. I don''t intend to review the actual generator and will instead take on trust that it does what you say :-). Ian.
Ian Jackson
2013-Aug-27 15:12 UTC
Re: [PATCH v2-resend 06/30] libxl: ocaml: support for Arrays in bindings generator.
Ian Campbell writes ("Re: [Xen-devel] [PATCH v2-resend 06/30] libxl: ocaml: support for Arrays in bindings generator."):> On Tue, 2013-08-27 at 15:59 +0100, Ian Jackson wrote: > > Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 06/30] libxl: ocaml: support for Arrays in bindings generator."): > > > No change in generated code because no arrays are currently generated. > > > > This patch doesn''t seem to have code for initialising, freeing, etc., > > arrays. Shouldn''t it ? > > There''s a calloc in there, and each element is initialised with a call > to c_val (which will already incorporate a libxl_foo_init as necessry), > the free is in the call to libxl_foo_dispose which comes from existing > bits of the bindings generator.Oh, I see, we''re just adding support for arrays in ocaml - and half of it is already there, but unused, for some reason. How confusing. Looking at the existing code am I right in thinking that we''re just adding support here for converting arrays from ocaml to C ? Ian.
Ian Campbell
2013-Aug-27 15:13 UTC
Re: [PATCH v2-resend 08/30] libxl: ocaml: support for KeyedUnion in the bindings generator.
On Tue, 2013-08-27 at 16:09 +0100, Ian Jackson wrote:> Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 08/30] libxl: ocaml: support for KeyedUnion in the bindings generator."): > > A KeyedUnion consists of two fields in the containing struct. First an > > enum field ("e") used as a descriminator and second a union ("u") > > containing potentially anonymous structs associated with each enum > > value. > ... > > foo = Enumeration("foo", [ > > (0, "BAR"), > > (1, "BAZ"), > > ]) > > s = Struct("s", [ > > ("u", KeyedUnion(none, foo, "blargle", [ > > ("bar", Struct(...xxx...)), > > ("baz", Struct(...yyy...)), > > I think you have some confusion betwwen bar,baz and foo,bar ? At > least, I hope so, as otherwise I haven''t understood at all.I don''t think so, foo is an enumeration with possible values of "bar" and "baz". The keyed union has a discriminator (called blargle in this example) which is of type "enum foo". There is then an anonymous union with two members, "bar" and "baz" corresponding to the possible values of blargle.> > > and map this to ocaml > > > > type foo = BAR | BAZ; > > module S = struct > > type blargle_bar = ...xxx...; > > type blargle_baz = ...yyy...; > > type blargle__union = Bar of blargle_bar | Baz of blargle_baz; > > type t > > { > > blargle : blargle__union; > > } > > end > > Is this indirection (through S.t) really needed ? It seems a bit > ugly. But I''m no expert on ocaml syntax or style.It''s the common idiom in ocaml, for a reason I cannot remember.> > > These type names are OK because they are already within the namespace > > associated with the struct "s". > > > > If the struct associated with bar is empty then we don''t bother with > > blargle_bar of "of blargle_bar". > > I''m not sure I follow this observation.In the type blargle__union we don''t bother with the "of blargle_bar" case of the corresponding struct is empty.> I don''t intend to review the actual generator and will instead take on > trust that it does what you say :-).Ack!
Ian Jackson
2013-Aug-27 15:20 UTC
Re: [PATCH v2-resend 08/30] libxl: ocaml: support for KeyedUnion in the bindings generator.
Ian Campbell writes ("Re: [Xen-devel] [PATCH v2-resend 08/30] libxl: ocaml: support for KeyedUnion in the bindings generator."):> On Tue, 2013-08-27 at 16:09 +0100, Ian Jackson wrote: > > I think you have some confusion betwwen bar,baz and foo,bar ? At > > least, I hope so, as otherwise I haven''t understood at all. > > I don''t think so, foo is an enumeration with possible values of "bar" > and "baz". > > The keyed union has a discriminator (called blargle in this example) > which is of type "enum foo". There is then an anonymous union with two > members, "bar" and "baz" corresponding to the possible values of > blargle.That''s what I thought. So this part is wrong then ? ] We generate C: ] ] enum { FOO, BAR } foo; ] struct s {> > Is this indirection (through S.t) really needed ? It seems a bit > > ugly. But I''m no expert on ocaml syntax or style. > > It''s the common idiom in ocaml, for a reason I cannot remember.Fair enough.> > > These type names are OK because they are already within the namespace > > > associated with the struct "s". > > > > > > If the struct associated with bar is empty then we don''t bother with > > > blargle_bar of "of blargle_bar". > > > > I''m not sure I follow this observation. > > In the type blargle__union we don''t bother with the "of blargle_bar" > case of the corresponding struct is empty.So we generate type blargle__union = Bar of blargle_bar | Baz; ? If this is legal ocaml syntax, then fine, I guess. (I can''t remember what "of" does here.) Ian.
Ian Jackson
2013-Aug-27 15:21 UTC
Re: [PATCH v2-resend 09/30] libxl: ocaml: add some more builtin types.
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 09/30] libxl: ocaml: add some more builtin types."):> Bitmap_val requires a ctx, so leave it as an abort for now.I''m not qualified to review this patch because I''m not familiar with the ocaml FFI, but I don''t think that''s a blocker for it going in. Ian.
Ian Campbell
2013-Aug-27 15:28 UTC
Re: [PATCH v2-resend 08/30] libxl: ocaml: support for KeyedUnion in the bindings generator.
On Tue, 2013-08-27 at 16:20 +0100, Ian Jackson wrote:> Ian Campbell writes ("Re: [Xen-devel] [PATCH v2-resend 08/30] libxl: ocaml: support for KeyedUnion in the bindings generator."): > > On Tue, 2013-08-27 at 16:09 +0100, Ian Jackson wrote: > > > I think you have some confusion betwwen bar,baz and foo,bar ? At > > > least, I hope so, as otherwise I haven''t understood at all. > > > > I don''t think so, foo is an enumeration with possible values of "bar" > > and "baz". > > > > The keyed union has a discriminator (called blargle in this example) > > which is of type "enum foo". There is then an anonymous union with two > > members, "bar" and "baz" corresponding to the possible values of > > blargle. > > That''s what I thought. So this part is wrong then ?You didn''t quote this part ;-)> ] We generate C: > ] > ] enum { FOO, BAR } foo;I meant "enum foo { BAR, BAZ };" here.> > > > These type names are OK because they are already within the namespace > > > > associated with the struct "s". > > > > > > > > If the struct associated with bar is empty then we don''t bother with > > > > blargle_bar of "of blargle_bar". > > > > > > I''m not sure I follow this observation. > > > > In the type blargle__union we don''t bother with the "of blargle_bar" > > case of the corresponding struct is empty. > > So we generate > type blargle__union = Bar of blargle_bar | Baz; > ? If this is legal ocaml syntax, then fine, I guess.Not just legal but idiomatic too, I think.> (I can''t remember what "of" does here.)I''m not sure what the proper name would be (a KeyedUnion maybe ;-)) it means you can unpick it with: match a_blargle with | Bar of thing -> do stuff with the content of thing | Baz -> do other stuff, not with thing (modulo me not remembering the real syntax, but it''s close) Ian.
Ian Jackson
2013-Aug-27 15:33 UTC
Re: [PATCH v2-resend 10/30] libxc: ocaml: add simple binding for xentoollog (output only).
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 10/30] libxc: ocaml: add simple binding for xentoollog (output only)."):> These bindings allow ocaml code to receive log message via xentoollog > but do not support injecting messages into xentoollog from ocaml. > Receiving log messages from libx{c,l} and forwarding them to ocaml is > the use case which is needed by the following patches....> +type level = Debug > + | Verbose > + | Detail > + | Progress > + | Info > + | Notice > + | Warn > + | Error > + | CriticalThis (and the next two stanzas too) needs to be autogenerated somehow from the list in xentoollog.h. Otherwise people will add levels in xentoollog.h and the ocaml code will go wrong.> +external _create_logger: (string * string) -> handle = "stub_xtl_create_logger" > +external test: handle -> unit = "stub_xtl_test" > + > +let create name cbs : handle > + (* Callback names are supposed to be unique *) > + let suffix = string_of_int (Random.int 1000000) inSurely this can''t be a good way to go about it. (Won''t this fail at least one time in 1E6 ?)> +let stdio_vmessage min_level level errno ctx msg > + let level_str = level_to_string level > + and errno_str = match errno with None -> "" | Some s -> sprintf ": errno=%d" s > + and ctx_str = match ctx with None -> "" | Some s -> sprintf ": %s" s in > + if compare min_level level <= 0 then begin > + printf "%s%s%s: %s\n" level_str ctx_str errno_str msg; > + flush stdout; > + endWhy are you reimplementing in ocaml the stdio logging support from xenttoollog ? Surely you''d want to simply call xtl_createlogger_stdiostream ? (Also, "vfoobar" is a convention used by C programmers to indicate that a function takes a stdarg.h va_list. You probably want to call this function "message".)> diff --git a/tools/ocaml/libs/xentoollog/xentoollog.mli b/tools/ocaml/libs/xentoollog/xentoollog.mli > new file mode 100644...> +type level > + | Debug > + | Verbose > + | Detail > + | Progress (* also used for "progress" messages *) > + | Info > + | Notice > + | Warn > + | Error > + | CriticalWhat, another copy of this ?> diff --git a/tools/ocaml/libs/xentoollog/xentoollog_stubs.c b/tools/ocaml/libs/xentoollog/xentoollog_stubs.c > new file mode 100644 > index 0000000..c6430b1 > --- /dev/null > +++ b/tools/ocaml/libs/xentoollog/xentoollog_stubs.c > @@ -0,0 +1,222 @@...> + switch (c_level) { > + case XTL_NONE: /* Not a real value */ > + caml_raise_sys_error(caml_copy_string("Val_level XTL_NONE")); > + break; > + case XTL_DEBUG: return Val_int(0); > + case XTL_VERBOSE: return Val_int(1); > + case XTL_DETAIL: return Val_int(2); > + case XTL_PROGRESS: return Val_int(3); > + case XTL_INFO: return Val_int(4); > + case XTL_NOTICE: return Val_int(5); > + case XTL_WARN: return Val_int(6); > + case XTL_ERROR: return Val_int(7); > + case XTL_CRITICAL: return Val_int(8); > + case XTL_NUM_LEVELS: /* Not a real value! */_Another_ copy of this! Thanks, Ian.
Ian Jackson
2013-Aug-27 15:38 UTC
Re: [PATCH v2-resend 11/30] libxl: ocaml: allocate a long lived libxl context.
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 11/30] libxl: ocaml: allocate a long lived libxl context."):> Rather than allocating a new context for every libxl call begin to > switch to a model where a context is allocated by the caller and may > then be used for multiple calls down into the library....> @@ -59,6 +65,8 @@ static void log_destroy(struct xentoollog_logger *logger) > lg.logger.vmessage = log_vmessage; \ > lg.logger.destroy = log_destroy; \ > lg.logger.progress = NULL; \ > + lg.log_offset = 0; \ > + memset(&lg.log_buf,0,sizeof(lg.log_buf)); \Is this in the wrong patch ? @@ -77,7 +85,7 @@ static char * dup_String_val(caml_gc *gc, value s)> c = calloc(len + 1, sizeof(char)); > if (!c) > caml_raise_out_of_memory(); > - gc->ptrs[gc->offset++] = c; > + if (gc) gc->ptrs[gc->offset++] = c;I don''t understand this at all. Is it going to become local to call this without a gc and if so what is its function in that case ?> @@ -94,9 +102,41 @@ static void failwith_xl(char *fname, struct caml_logger *lg) > { > char *s; > s = (lg) ? lg->log_buf : fname; > + printf("Error: %s\n", fname); > caml_raise_with_string(*caml_named_value("xl.error"), s); > }I don''t understand why this hunk is in this patch, either. Ian.
Ian Jackson
2013-Aug-27 15:41 UTC
Re: [PATCH v2-resend 12/30] libxl: ocaml: switch all functions over to take a context.
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 12/30] libxl: ocaml: switch all functions over to take a context."):> Since the context has a logger we can get rid of the logger built into these > bindings and use the xentoollog bindings instead.This seems plausible. Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Ian Jackson
2013-Aug-27 15:43 UTC
Re: [PATCH v2-resend 13/30] libxl: ocaml: propagate the libxl return error code in exceptions
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 13/30] libxl: ocaml: propagate the libxl return error code in exceptions"):> -(* @@LIBXL_TYPES@@ *) > +type error > + Nonspecific | > + Version | > + Fail | > + Ni | > + Nomem | > + Inval | > + Badfail | > + Guest_Timedout | > + Timedout | > + Noparavirt | > + Not_Ready | > + Osevent_Reg_Fail | > + Bufferfull | > + Unknown_ChildI''m afraid that you''ll have to make the libxl error type an enum, first, to avoid duplicating (pentuplicating(!)) all this. Otherwise it''s fine... Ian.
Ian Jackson
2013-Aug-27 15:48 UTC
Re: [PATCH v2-resend 14/30] libxl: ocaml: make Val_defbool GC-proof
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 14/30] libxl: ocaml: make Val_defbool GC-proof"):> Signed-off-by: Rob Hoes <rob.hoes@citrix.com>I''m afraid I don''t understand this at all. How does this make a difference ? (Also, these changes...> + bool b; > - bool b = libxl_defbool_val(c_val); > + b = libxl_defbool_val(c_val);... definitely don''t have any purpose.) So, the remaining key change is this: bool b = libxl_defbool_val(c_val);> - v = Val_some(b ? Val_bool(true) : Val_bool(false)); > + v1 = b ? Val_bool(true) : Val_bool(false); > + v2 = Val_some(v1);Assuming that Val_some is a function, I think this has no semantic difference. Can you explain what the difference is ? Ian.
Ian Jackson
2013-Aug-27 15:50 UTC
Re: [PATCH v2-resend 15/30] libxl: ocaml: add domain_build/create_info/config and events to the bindings.
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 15/30] libxl: ocaml: add domain_build/create_info/config and events to the bindings."):> We now have enoguh infrastructure in place to do this trivially.^^^^^^ This is OK (when the prerequisite patches are in). But you should fix the typo :-). Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Ian.
Ian Jackson
2013-Aug-27 16:27 UTC
Re: [PATCH v2-resend 02/30] libxl: idl: allow KeyedUnion members to be empty
Ian Campbell writes ("Re: [Xen-devel] [PATCH v2-resend 02/30] libxl: idl: allow KeyedUnion members to be empty"):> On Tue, 2013-08-27 at 15:59 +0100, Ian Jackson wrote: > > You are introducing skankiness not in the IDL compiler, but in the IDL > > itself. I think it is better to have skankiness in some particular > > language''s output than in the IDL input. > > I think: > - ("invalid", Struct(None, [])), > + ("invalid", None), > > is reducing the amount of skank in the IDL, None has a good match with > "nothing here", while "Strict(None, [])" is just random placeholder goo, > which would be even worse if we were to artificially add a memberWell, I think we should keep the number of primitive types down to the minimum possible. But I think this discussion has gone on long enough and it''s not that important: Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> Ian.
Ian Jackson
2013-Aug-27 17:41 UTC
Re: [PATCH v2-resend 17/30] libxl: ocaml: fix the handling of enums in the bindings generator
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 17/30] libxl: ocaml: fix the handling of enums in the bindings generator"):> Signed-off-by: Rob Hoes <rob.hoes@citrix.com>Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Ian Jackson
2013-Aug-27 17:44 UTC
Re: [PATCH v2-resend 18/30] libxl: ocaml: use the "string option" type for IDL strings
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 18/30] libxl: ocaml: use the "string option" type for IDL strings"):> The libxl IDL is based on C type "char *", and therefore "strings" can > by NULL, or be an actual string. In ocaml, it is common to encode such > things as option types.Can you point me to the existing code this replaces ? I was looking for "Val_string" and "String_val" but couldn''t find them. I think if that code is missing it deserves a note in the commit message at least (and then surely this new code is currently unused?) Thanks, Ian.
Ian Jackson
2013-Aug-27 17:46 UTC
Re: [PATCH v2-resend 19/30] libxl: ocaml: add xen_console_read
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 19/30] libxl: ocaml: add xen_console_read"):> Signed-off-by: Rob Hoes <rob.hoes@citrix.com>Thanks. This code takes the console output and stores it in memory. Is there anything here which would check that the amount of memory to be used is reasonable ? Do we need to worry about the lifetime of this data ? In a garbage-collected language it might hang about. Thanks, Ian.
Ian Jackson
2013-Aug-27 17:49 UTC
Re: [PATCH v2-resend 16/30] libxl: ocaml: add META to list of generated files in Makefile
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 16/30] libxl: ocaml: add META to list of generated files in Makefile"):> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> > Acked-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Ian Jackson
2013-Aug-27 17:51 UTC
Re: [PATCH v2-resend 20/30] libxl: ocaml: add dominfo_list and dominfo_get
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 20/30] libxl: ocaml: add dominfo_list and dominfo_get"):> Signed-off-by: Rob Hoes <rob.hoes@citrix.com>Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Ian Jackson
2013-Aug-27 17:52 UTC
Re: [PATCH v2-resend 21/30] libxl: ocaml: implement some simple tests
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 21/30] libxl: ocaml: implement some simple tests"):> Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > Signed-off-by: Rob Hoes <rob.hoes@citrix.com>Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>
Ian Jackson
2013-Aug-27 17:56 UTC
Re: [PATCH v2-resend 22/30] libxl: ocaml: event management
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: event management"):> Signed-off-by: Rob Hoes <rob.hoes@citrix.com>Can you explain in a bit more detail how you expect to use this ? I''m very surprised that apparently the right interface to provide is one which exposes the poll-based event loop machinery to ocaml. Surely it would be better to plumb that in at a lower level. Ian.
Ian Campbell
2013-Aug-28 08:30 UTC
Re: [PATCH v2-resend 18/30] libxl: ocaml: use the "string option" type for IDL strings
On Tue, 2013-08-27 at 18:44 +0100, Ian Jackson wrote:> Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 18/30] libxl: ocaml: use the "string option" type for IDL strings"): > > The libxl IDL is based on C type "char *", and therefore "strings" can > > by NULL, or be an actual string. In ocaml, it is common to encode such > > things as option types. > > Can you point me to the existing code this replaces ? I was looking > for "Val_string" and "String_val" but couldn''t find them. I think if > that code is missing it deserves a note in the commit message at least > (and then surely this new code is currently unused?)- "char *": ("string", "%(c)s = dup_String_val(%(o)s)", "caml_copy_string(%(c)s)"), + "char *": ("string option", "%(c)s = String_option_val(%(o)s)", "Val_string_option(%(c)s)"), So it is replacing uses of dup_String_val (existing function in tools/ocaml/libs/xl/xenlight_stubs.c) and caml_copy_string (which is an ocaml provided primitive) with newly defined String_option_val and Val_string_option which wrap those original function with the Some/None semantics. Ian.
Ian Jackson
2013-Aug-28 10:33 UTC
Re: [PATCH v2-resend 18/30] libxl: ocaml: use the "string option" type for IDL strings
Ian Campbell writes ("Re: [Xen-devel] [PATCH v2-resend 18/30] libxl: ocaml: use the "string option" type for IDL strings"):> On Tue, 2013-08-27 at 18:44 +0100, Ian Jackson wrote: > > Can you point me to the existing code this replaces ? I was looking > > for "Val_string" and "String_val" but couldn''t find them. I think if > > that code is missing it deserves a note in the commit message at least > > (and then surely this new code is currently unused?) > > - "char *": ("string", "%(c)s = dup_String_val(%(o)s)", "caml_copy_string(%(c)s)"), > + "char *": ("string option", "%(c)s = String_option_val(%(o)s)", "Val_string_option(%(c)s)"), > > So it is replacing uses of dup_String_val (existing function in > tools/ocaml/libs/xl/xenlight_stubs.c) and caml_copy_string (which is an > ocaml provided primitive) with newly defined String_option_val and > Val_string_option which wrap those original function with the Some/None > semantics.I was looking for "String_val", for example. Am I wrote to be looking for that ? Ian.
Ian Campbell
2013-Aug-28 10:41 UTC
Re: [PATCH v2-resend 18/30] libxl: ocaml: use the "string option" type for IDL strings
On Wed, 2013-08-28 at 11:33 +0100, Ian Jackson wrote:> Ian Campbell writes ("Re: [Xen-devel] [PATCH v2-resend 18/30] libxl: ocaml: use the "string option" type for IDL strings"): > > On Tue, 2013-08-27 at 18:44 +0100, Ian Jackson wrote: > > > Can you point me to the existing code this replaces ? I was looking > > > for "Val_string" and "String_val" but couldn''t find them. I think if > > > that code is missing it deserves a note in the commit message at least > > > (and then surely this new code is currently unused?) > > > > - "char *": ("string", "%(c)s = dup_String_val(%(o)s)", "caml_copy_string(%(c)s)"), > > + "char *": ("string option", "%(c)s = String_option_val(%(o)s)", "Val_string_option(%(c)s)"), > > > > So it is replacing uses of dup_String_val (existing function in > > tools/ocaml/libs/xl/xenlight_stubs.c) and caml_copy_string (which is an > > ocaml provided primitive) with newly defined String_option_val and > > Val_string_option which wrap those original function with the Some/None > > semantics. > > I was looking for "String_val", for example. Am I wrote to be looking > for that ?The diff snippet I quoted uses dup_String_val not String_val, so yes I think so. The second and third elements of the tuple are the marshal/unmarshal code for the type. Ian.
Rob Hoes
2013-Aug-28 14:37 UTC
Re: [PATCH v2-resend 06/30] libxl: ocaml: support for Arrays in bindings generator.
> Ian Campbell writes ("Re: [Xen-devel] [PATCH v2-resend 06/30] libxl: ocaml: > support for Arrays in bindings generator."): > > On Tue, 2013-08-27 at 15:59 +0100, Ian Jackson wrote: > > > Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 06/30] libxl: ocaml: > support for Arrays in bindings generator."): > > > > No change in generated code because no arrays are currently > generated. > > > > > > This patch doesn''t seem to have code for initialising, freeing, > > > etc., arrays. Shouldn''t it ? > > > > There''s a calloc in there, and each element is initialised with a call > > to c_val (which will already incorporate a libxl_foo_init as > > necessry), the free is in the call to libxl_foo_dispose which comes > > from existing bits of the bindings generator. > > Oh, I see, we''re just adding support for arrays in ocaml - and half of it is > already there, but unused, for some reason. How confusing. > > Looking at the existing code am I right in thinking that we''re just adding > support here for converting arrays from ocaml to C ?That''s right: the C -> OCaml conversion for arrays was already there (in the ocaml_Val function). Cheers, Rob
Rob Hoes
2013-Aug-28 14:47 UTC
Re: [PATCH v2-resend 08/30] libxl: ocaml: support for KeyedUnion in the bindings generator.
> You didn''t quote this part ;-) > > > ] We generate C: > > ] > > ] enum { FOO, BAR } foo; > > I meant "enum foo { BAR, BAZ };" here.I''ll update the commit message.> > So we generate > > type blargle__union = Bar of blargle_bar | Baz; ? If this is > > legal ocaml syntax, then fine, I guess. > > Not just legal but idiomatic too, I think. > > > (I can''t remember what "of" does here.) > > I''m not sure what the proper name would be (a KeyedUnion maybe ;-)) it > means you can unpick it with: > > match a_blargle with > | Bar of thing -> do stuff with the content of thing | Baz -> do other stuff, > not with thingThat''s right. It is called a "variant type" in OCaml, and it is typically unpacked by pattern matching. See http://caml.inria.fr/pub/docs/manual-ocaml/manual003.html#s:tut-recvariants. Cheers, Rob> (modulo me not remembering the real syntax, but it''s close) > > Ian.
Rob Hoes
2013-Aug-28 14:52 UTC
Re: [PATCH v2-resend 09/30] libxl: ocaml: add some more builtin types.
> Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 09/30] libxl: ocaml: add > some more builtin types."): > > Bitmap_val requires a ctx, so leave it as an abort for now. > > I''m not qualified to review this patch because I''m not familiar with the > ocaml FFI, but I don''t think that''s a blocker for it going in.The Bitmap_val function is actually completed in patch 12 of this series, where the libxl context is made available. Cheers, Rob
Rob Hoes
2013-Aug-28 15:55 UTC
Re: [PATCH v2-resend 11/30] libxl: ocaml: allocate a long lived libxl context.
> Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 11/30] libxl: ocaml: > allocate a long lived libxl context."): > > Rather than allocating a new context for every libxl call begin to > > switch to a model where a context is allocated by the caller and may > > then be used for multiple calls down into the library. > ... > > @@ -59,6 +65,8 @@ static void log_destroy(struct xentoollog_logger > *logger) > > lg.logger.vmessage = log_vmessage; \ > > lg.logger.destroy = log_destroy; \ > > lg.logger.progress = NULL; \ > > + lg.log_offset = 0; \ > > + memset(&lg.log_buf,0,sizeof(lg.log_buf)); \ > > Is this in the wrong patch ? > > @@ -77,7 +85,7 @@ static char * dup_String_val(caml_gc *gc, value s) > > c = calloc(len + 1, sizeof(char)); > > if (!c) > > caml_raise_out_of_memory(); > > - gc->ptrs[gc->offset++] = c; > > + if (gc) gc->ptrs[gc->offset++] = c; > > I don''t understand this at all. Is it going to become local to call this without a > gc and if so what is its function in that case ? > > > @@ -94,9 +102,41 @@ static void failwith_xl(char *fname, struct > > caml_logger *lg) { > > char *s; > > s = (lg) ? lg->log_buf : fname; > > + printf("Error: %s\n", fname); > > caml_raise_with_string(*caml_named_value("xl.error"), s); } > > I don''t understand why this hunk is in this patch, either.None of these hunks should be there. Both the logger and gc bits are removed entirely in the following patch, and that printf is a debugging line I forgot to remove. I probably made some mistakes while reorganising and squashing some patches. I''ll remove those hunks. Cheers, Rob
Rob Hoes
2013-Aug-29 10:29 UTC
Re: [PATCH v2-resend 07/30] libxl: ocaml: avoid reserved words in type and field names.
> Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 07/30] libxl: ocaml: avoid > reserved words in type and field names."): > > Current just s/type/ty/ and there are no such fields (yet) so no > > change to generated code. > > I think this should be done in a systematic way, and one which is an > injection[1]. What if someone later introduces a field called "ty" in the > same struct as one called "type" ? > > I don''t know what a good convention would be in ocaml, but for example > you could prefix everything with "idl_" (including names starting "idl_"). > > [1] http://en.wikipedia.org/wiki/Injection_%28mathematics%29Yes, I see what you mean. I don''t really like to prefix everything, but that is mostly for aesthetic reasons. Although even an injective transformation such as prefixing isn''t always safe: what if we prefix "type" to become "xl_type", and someone adds a keyword "xl_type" to OCaml? I am not sure what the best solution would be in OCaml, but I''ll ask around a bit. Cheers, Rob
Rob Hoes
2013-Aug-29 12:54 UTC
Re: [PATCH v2-resend 10/30] libxc: ocaml: add simple binding for xentoollog (output only).
> Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 10/30] libxc: ocaml: add > simple binding for xentoollog (output only)."): > > These bindings allow ocaml code to receive log message via xentoollog > > but do not support injecting messages into xentoollog from ocaml. > > Receiving log messages from libx{c,l} and forwarding them to ocaml is > > the use case which is needed by the following patches. > ... > > +type level = Debug > > + | Verbose > > + | Detail > > + | Progress > > + | Info > > + | Notice > > + | Warn > > + | Error > > + | Critical > > This (and the next two stanzas too) needs to be autogenerated somehow > from the list in xentoollog.h. Otherwise people will add levels in > xentoollog.h and the ocaml code will go wrong.This would have been quite easy if the debug levels were part of the libxl IDL. Unfortunately they aren''t, because xentoollog is part of libxc. So what options do we have? Adding some sort of IDL to libxc would be one. Or indeed parsing xentoollog.h to derive the log levels, but I think the risk of that going wrong due to changes in xentoollog.h may defeat its purpose. Any update to the OCaml level type would likely require the application that uses the bindings to be modified, so some work will still be needed. Perhaps we could map any new log levels to a well-defined "unknown" value, so that the higher level OCaml code can mark them as such, signalling a need to update the bindings? At least nothing would break horribly in this way.> > +external _create_logger: (string * string) -> handle > "stub_xtl_create_logger" > > +external test: handle -> unit = "stub_xtl_test" > > + > > +let create name cbs : handle > > + (* Callback names are supposed to be unique *) > > + let suffix = string_of_int (Random.int 1000000) in > > Surely this can''t be a good way to go about it. > (Won''t this fail at least one time in 1E6 ?)Most likely this function would be called just once, or at most a few times, in the lifetime of the application, so it won''t be that bad. But it would probably be better to just use a counter instead of a random value, and raise a proper exception when we hit 1e6 (or some other larger number).> > +let stdio_vmessage min_level level errno ctx msg > > + let level_str = level_to_string level > > + and errno_str = match errno with None -> "" | Some s -> sprintf ": > errno=%d" s > > + and ctx_str = match ctx with None -> "" | Some s -> sprintf ": %s" s in > > + if compare min_level level <= 0 then begin > > + printf "%s%s%s: %s\n" level_str ctx_str errno_str msg; > > + flush stdout; > > + end > > Why are you reimplementing in ocaml the stdio logging support from > xenttoollog ? Surely you''d want to simply call > xtl_createlogger_stdiostream ?I suppose we could do that indeed.> (Also, "vfoobar" is a convention used by C programmers to indicate that a > function takes a stdarg.h va_list. You probably want to call this function > "message".)OK. Rob> > diff --git a/tools/ocaml/libs/xentoollog/xentoollog.mli > > b/tools/ocaml/libs/xentoollog/xentoollog.mli > > new file mode 100644 > ... > > +type level > > + | Debug > > + | Verbose > > + | Detail > > + | Progress (* also used for "progress" messages *) > > + | Info > > + | Notice > > + | Warn > > + | Error > > + | Critical > > What, another copy of this ? > > > diff --git a/tools/ocaml/libs/xentoollog/xentoollog_stubs.c > > b/tools/ocaml/libs/xentoollog/xentoollog_stubs.c > > new file mode 100644 > > index 0000000..c6430b1 > > --- /dev/null > > +++ b/tools/ocaml/libs/xentoollog/xentoollog_stubs.c > > @@ -0,0 +1,222 @@ > ... > > + switch (c_level) { > > + case XTL_NONE: /* Not a real value */ > > + caml_raise_sys_error(caml_copy_string("Val_level > XTL_NONE")); > > + break; > > + case XTL_DEBUG: return Val_int(0); > > + case XTL_VERBOSE: return Val_int(1); > > + case XTL_DETAIL: return Val_int(2); > > + case XTL_PROGRESS: return Val_int(3); > > + case XTL_INFO: return Val_int(4); > > + case XTL_NOTICE: return Val_int(5); > > + case XTL_WARN: return Val_int(6); > > + case XTL_ERROR: return Val_int(7); > > + case XTL_CRITICAL: return Val_int(8); > > + case XTL_NUM_LEVELS: /* Not a real value! */ > > _Another_ copy of this! > > Thanks, > Ian.
Ian Campbell
2013-Aug-29 13:12 UTC
Re: [PATCH v2-resend 10/30] libxc: ocaml: add simple binding for xentoollog (output only).
On Thu, 2013-08-29 at 13:54 +0100, Rob Hoes wrote:> > Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 10/30] libxc: ocaml: add > > simple binding for xentoollog (output only)."): > > > These bindings allow ocaml code to receive log message via xentoollog > > > but do not support injecting messages into xentoollog from ocaml. > > > Receiving log messages from libx{c,l} and forwarding them to ocaml is > > > the use case which is needed by the following patches. > > ... > > > +type level = Debug > > > + | Verbose > > > + | Detail > > > + | Progress > > > + | Info > > > + | Notice > > > + | Warn > > > + | Error > > > + | Critical > > > > This (and the next two stanzas too) needs to be autogenerated somehow > > from the list in xentoollog.h. Otherwise people will add levels in > > xentoollog.h and the ocaml code will go wrong. > > This would have been quite easy if the debug levels were part of the > libxl IDL. Unfortunately they aren''t, because xentoollog is part of > libxc. So what options do we have? Adding some sort of IDL to libxc > would be one. Or indeed parsing xentoollog.h to derive the log levels, > but I think the risk of that going wrong due to changes in > xentoollog.h may defeat its purpose.I think with a sufficiently large comment in the vicinity of the enum xentoollog_level we might be able to get away with this. Realistically that header hasn''t changed since 2010 (in fact it only changed once meaningfully since it was added!)> Any update to the OCaml level type would likely require the > application that uses the bindings to be modified, so some work will > still be needed. Perhaps we could map any new log levels to a > well-defined "unknown" value, so that the higher level OCaml code can > mark them as such, signalling a need to update the bindings? At least > nothing would break horribly in this way.This sounds like a good belt and braces thing to do regardless.> > > +external _create_logger: (string * string) -> handle > > "stub_xtl_create_logger" > > > +external test: handle -> unit = "stub_xtl_test" > > > + > > > +let create name cbs : handle > > > + (* Callback names are supposed to be unique *) > > > + let suffix = string_of_int (Random.int 1000000) in > > > > Surely this can''t be a good way to go about it. > > (Won''t this fail at least one time in 1E6 ?) > > Most likely this function would be called just once, or at most a few > times, in the lifetime of the application, so it won''t be that bad. > But it would probably be better to just use a counter instead of a > random value, and raise a proper exception when we hit 1e6 (or some > other larger number).I can''t imagine what I was thinking here! Perhaps I couldn''t figure out how to do the ocaml equivalent of "static int counter" so I bodged it and forgot to come back... I think a counter would be fine. Either that or push it onto the caller to provide something it knows is unique, but that sucks...> > > +let stdio_vmessage min_level level errno ctx msg > > > + let level_str = level_to_string level > > > + and errno_str = match errno with None -> "" | Some s -> sprintf ": > > errno=%d" s > > > + and ctx_str = match ctx with None -> "" | Some s -> sprintf ": %s" s in > > > + if compare min_level level <= 0 then begin > > > + printf "%s%s%s: %s\n" level_str ctx_str errno_str msg; > > > + flush stdout; > > > + end > > > > Why are you reimplementing in ocaml the stdio logging support from > > xenttoollog ? Surely you''d want to simply call > > xtl_createlogger_stdiostream ?It was supposed to serve as a proof of concept for writing an output module in ocaml rather than C, i.e. that the callbacks all worked right etc. It would probably be best moved to the test app. Ian.
Ian Jackson
2013-Aug-29 15:05 UTC
Re: [PATCH v2-resend 10/30] libxc: ocaml: add simple binding for xentoollog (output only).
Rob Hoes writes ("RE: [Xen-devel] [PATCH v2-resend 10/30] libxc: ocaml: add simple binding for xentoollog (output only)."):> [Ian Jackson:] > > Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 10/30] libxc: ocaml: add > > This (and the next two stanzas too) needs to be autogenerated somehow > > from the list in xentoollog.h. Otherwise people will add levels in > > xentoollog.h and the ocaml code will go wrong. > > This would have been quite easy if the debug levels were part of the libxl IDL. Unfortunately they aren''t, because xentoollog is part of libxc. So what options do we have? Adding some sort of IDL to libxc would be one. Or indeed parsing xentoollog.h to derive the log levels, but I think the risk of that going wrong due to changes in xentoollog.h may defeat its purpose.I think we can promise not to break the syntax too badly. Please do parse the information out of xentoollog.h.> > > +let create name cbs : handle > > > + (* Callback names are supposed to be unique *) > > > + let suffix = string_of_int (Random.int 1000000) in > > > > Surely this can''t be a good way to go about it. > > (Won''t this fail at least one time in 1E6 ?) > > Most likely this function would be called just once, or at most a few times, in the lifetime of the application, so it won''t be that bad. But it would probably be better to just use a counter instead of a random value, and raise a proper exception when we hit 1e6 (or some other larger number).Yes. Or one 64-bit counter.> > Why are you reimplementing in ocaml the stdio logging support from > > xenttoollog ? Surely you''d want to simply call > > xtl_createlogger_stdiostream ? > > I suppose we could do that indeed.Yes :-). Unless there''s some reason not to do that, that I''m missing. Thanks, Ia.
Ian Jackson
2013-Aug-29 15:07 UTC
Re: [PATCH v2-resend 10/30] libxc: ocaml: add simple binding for xentoollog (output only).
Ian Campbell writes ("Re: [Xen-devel] [PATCH v2-resend 10/30] libxc: ocaml: add simple binding for xentoollog (output only)."):> > [Ian Jackson:] > > > Why are you reimplementing in ocaml the stdio logging support from > > > xenttoollog ? Surely you''d want to simply call > > > xtl_createlogger_stdiostream ? > > It was supposed to serve as a proof of concept for writing an output > module in ocaml rather than C, i.e. that the callbacks all worked right > etc. It would probably be best moved to the test app.That makes sense. Ian.
Ian Campbell
2013-Sep-10 10:55 UTC
Re: [PATCH v2-resend 01/30] libxl: Add LIBXL_SHUTDOWN_REASON_UNKNOWN
On Tue, 2013-08-27 at 10:54 -0400, Ian Jackson wrote:> Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 01/30] libxl: Add LIBXL_SHUTDOWN_REASON_UNKNOWN"): > > libxl_dominfo.shutdown_reason is valid iff (shutdown||dying). This is a bit > > annoying when generating language bindings since it needs all sorts of special > > casing. Just introduce an explicit value instead. > > Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>Applied, thanks.
Ian Campbell
2013-Sep-10 10:56 UTC
Re: [PATCH v2-resend 03/30] libxl: idl: add domain_type field to libxl_dominfo struct
On Tue, 2013-08-27 at 15:55 +0100, Ian Jackson wrote:> Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 03/30] libxl: idl: add domain_type field to libxl_dominfo struct"): > > This allows a toolstack to find out whether a VM has booted as PV or HVM. > > Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>Applied.
Ian Campbell
2013-Sep-10 10:57 UTC
Re: [PATCH v2-resend 04/30] libxl: idl: complete some enums in the IDL with their defaults
On Tue, 2013-08-27 at 15:56 +0100, Ian Jackson wrote:> Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 04/30] libxl: idl: complete some enums in the IDL with their defaults"): > > There are several enums in the IDL that are initialised to 0, while > > the value 0 is not part of the enum itself. This creates problems for > > language bindings generated from the IDL, such as the OCaml ones. > > > > Added an explicit (0, "UNKNOWN") enum value where appropriate, or used > > init_val to default to a sensible value. > > Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>Applied.> > (I haven''t double checked each of these changes against the context, > but the principle is sound.) > > Ian.
Ian Campbell
2013-Sep-10 10:57 UTC
Re: [PATCH v2-resend 05/30] libxl: ocaml: fix code intended to output comments before definitions
On Tue, 2013-08-27 at 15:57 +0100, Ian Jackson wrote:> Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 05/30] libxl: ocaml: fix code intended to output comments before definitions"): > > I''m not sure how useful these comments actually are but erred on the > > side of fixing rather than removing. > > Acked-by: Ian Jackson <ian.jackson@eu.citrix.com>Applied.
Ian Campbell
2013-Sep-10 10:58 UTC
Re: [PATCH v2-resend 00/30] libxl: ocaml: improve the bindings
On Thu, 2013-08-22 at 11:50 +0100, Rob Hoes wrote:> This is a repost of version 2 of this patch series to fix the OCaml binding to libxl.I picked a few acked patches off the front of this series before I got into unacked territory and stopped. I did: a65b5d3 libxl: ocaml: fix code intended to output comments before definitions 0b157d9 libxl: idl: complete some enums in the IDL with their defaults 60dd846 libxl: idl: add domain_type field to libxl_dominfo struct 8bf5d27 libxl: Add LIBXL_SHUTDOWN_REASON_UNKNOWN Which I think were #1, and #3-#5. #2 was unacked.
Ian Campbell
2013-Sep-10 11:00 UTC
Re: [PATCH v2-resend 03/30] libxl: idl: add domain_type field to libxl_dominfo struct
On Tue, 2013-09-10 at 11:56 +0100, Ian Campbell wrote:> On Tue, 2013-08-27 at 15:55 +0100, Ian Jackson wrote: > > Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 03/30] libxl: idl: add domain_type field to libxl_dominfo struct"): > > > This allows a toolstack to find out whether a VM has booted as PV or HVM. > > > > Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> > > Applied.Although in hindsight this needed a #define LIBXL_HAVE_FOO in libxl.h. #define LIBXL_DOMINFO_HAVE_DOMAINTYPE. Could you follow up with a suitable patch, or add it to the head of the next posting of the series? See libxl.h for some existing examples. Thanks, Ian.
Ian Campbell
2013-Sep-10 11:02 UTC
Re: [PATCH v2-resend 04/30] libxl: idl: complete some enums in the IDL with their defaults
On Tue, 2013-09-10 at 11:57 +0100, Ian Campbell wrote:> On Tue, 2013-08-27 at 15:56 +0100, Ian Jackson wrote: > > Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 04/30] libxl: idl: complete some enums in the IDL with their defaults"): > > > There are several enums in the IDL that are initialised to 0, while > > > the value 0 is not part of the enum itself. This creates problems for > > > language bindings generated from the IDL, such as the OCaml ones. > > > > > > Added an explicit (0, "UNKNOWN") enum value where appropriate, or used > > > init_val to default to a sensible value. > > > > Acked-by: Ian Jackson <ian.jackson@eu.citrix.com> > > Applied.I think we don''t need a raft of LIBXL_HAVE defines in this case, the addition is really for the benefit of autogenerated language bindings, anyone using C who cares about supporting older APIs would just use 0 and not do: #ifdef LIBXL_HAVE_A_THING enum thing foo = LIBXL_HAVE_A_THING #else num thing foo = 0; #endif Ian.
Rob Hoes
2013-Sep-10 11:02 UTC
Re: [PATCH v2-resend 00/30] libxl: ocaml: improve the bindings
Thanks! I think IanJ also acked #2 after some discussion on 27 Aug. I''ll process the remaining issues that came up soon. Cheers, Rob> -----Original Message----- > From: Ian Campbell > Sent: 10 September 2013 11:58 AM > To: Rob Hoes > Cc: xen-devel@lists.xen.org > Subject: Re: [PATCH v2-resend 00/30] libxl: ocaml: improve the bindings > > On Thu, 2013-08-22 at 11:50 +0100, Rob Hoes wrote: > > This is a repost of version 2 of this patch series to fix the OCaml binding to > libxl. > > I picked a few acked patches off the front of this series before I got into > unacked territory and stopped. I did: > > a65b5d3 libxl: ocaml: fix code intended to output comments before > definitions > 0b157d9 libxl: idl: complete some enums in the IDL with their defaults > 60dd846 libxl: idl: add domain_type field to libxl_dominfo struct > 8bf5d27 libxl: Add LIBXL_SHUTDOWN_REASON_UNKNOWN > > Which I think were #1, and #3-#5. #2 was unacked. >
Rob Hoes
2013-Sep-10 11:03 UTC
Re: [PATCH v2-resend 03/30] libxl: idl: add domain_type field to libxl_dominfo struct
> > Applied. > > Although in hindsight this needed a #define LIBXL_HAVE_FOO in libxl.h. > #define LIBXL_DOMINFO_HAVE_DOMAINTYPE. > > Could you follow up with a suitable patch, or add it to the head of the next > posting of the series? See libxl.h for some existing examples.Sure, I''ll do that. Cheers, Rob
Ian Campbell
2013-Sep-10 12:57 UTC
Re: [PATCH v2-resend 00/30] libxl: ocaml: improve the bindings
On Tue, 2013-09-10 at 12:02 +0100, Rob Hoes wrote:> Thanks! I think IanJ also acked #2 after some discussion on 27 Aug.So he did. I''ll try and remember that when I do another pas through my queue.> I''ll process the remaining issues that came up soon.Thanks! There are some important dates in http://article.gmane.org/gmane.comp.emulators.xen.devel/168132 wrt code freezes etc. Do you think we can hit 4.4 with this stuff? Ian.
Rob Hoes
2013-Sep-10 13:06 UTC
Re: [PATCH v2-resend 00/30] libxl: ocaml: improve the bindings
> Thanks! There are some important dates in > http://article.gmane.org/gmane.comp.emulators.xen.devel/168132 wrt > code freezes etc. Do you think we can hit 4.4 with this stuff?Yep. I think it would be quite bad if we won''t... Cheers, Rob
Ian Jackson
2013-Nov-11 14:42 UTC
Re: [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]
Rob Hoes writes ("[PATCH v4 18/27] libxl: ocaml: event management"):> Signed-off-by: Rob Hoes <rob.hoes@citrix.com> > Acked-by: David Scott <dave.scott@eu.citrix.com> > --- > tools/ocaml/libs/xl/xenlight.ml.in | 66 +++++++ > tools/ocaml/libs/xl/xenlight.mli.in | 47 +++++ > tools/ocaml/libs/xl/xenlight_stubs.c | 325 ++++++++++++++++++++++++++++++++++I replied to v2 of this as follows: Ian Jackson writes ("Re: [Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: event management"):> Can you explain in a bit more detail how you expect to use this ? > > I''m very surprised that apparently the right interface to provide is > one which exposes the poll-based event loop machinery to ocaml. > Surely it would be better to plumb that in at a lower level.But I haven''t had an answer. I think that whether this is the right approach depends on how event loops are traditionally done in ocaml. I''m afraid, though, that in the absence of an explanation: Nacked-by: Ian Jackson <ian.jackson@eu.citrix.com> Thanks, Ian. PS Does anyone here know how Mirage handles event loops ?
Rob Hoes
2013-Nov-11 15:39 UTC
Re: [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]
> I replied to v2 of this as follows: > > Ian Jackson writes ("Re: [Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: > event management"): > > Can you explain in a bit more detail how you expect to use this ? > > > > I''m very surprised that apparently the right interface to provide is > > one which exposes the poll-based event loop machinery to ocaml. > > Surely it would be better to plumb that in at a lower level. > > But I haven''t had an answer.Sorry, I had missed this... :(> I think that whether this is the right approach depends on how event loops > are traditionally done in ocaml.Having bindings to the low-level functions libxl_osevent_register_hooks and related, allows us to run an event loop in OCaml; either one we write ourselves, or one that is available elsewhere. We are currently running a straightforward, custom event loop in xenopsd. It simply maintains a list of fds and timeouts, and runs poll in a loop, as you would expect (see https://github.com/xapi-project/xenopsd/blob/master/xl/xenlight_events.ml for the full code). The Lwt cooperative threads library (http://ocsigen.org/lwt/), which is quite popular these days, has an event loop that can be easily extended to poll any additional fds that we get from libxl. Lwt provides a "lightweight" threading model, which does not let you run any other (POSIX) threads in your application, and therefore excludes an event loop implemented in the C bindings. We have not ported xenopsd to use Lwt yet, but there were plans to do so in future. Exposing the low-level event hooks in OCaml gives us the choice to implement either of the above options.> I''m afraid, though, that in the absence of an explanation: > > Nacked-by: Ian Jackson <ian.jackson@eu.citrix.com> > > Thanks, > Ian. > > PS Does anyone here know how Mirage handles event loops ?I believe Mirage uses Lwt, and therefore probably uses its event loop. Cheers, Rob
Ian Jackson
2013-Nov-12 14:56 UTC
Re: [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]
Rob Hoes writes ("RE: [Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]"):> > But I haven''t had an answer. > > Sorry, I had missed this... :(NP.> > I think that whether this is the right approach depends on how > > event loops are traditionally done in ocaml. > > Having bindings to the low-level functions > libxl_osevent_register_hooks and related, allows us to run an event > loop in OCaml; either one we write ourselves, or one that is > available elsewhere.Right.> We are currently running a straightforward, custom event loop in > xenopsd. It simply maintains a list of fds and timeouts, and runs > poll in a loop, as you would expect (see > https://github.com/xapi-project/xenopsd/blob/master/xl/xenlight_events.ml > for the full code).OK, that makes sense.> Exposing the low-level event hooks in OCaml gives us the choice to > implement either of the above options.Right. Good. I have some questions about the details: Firstly, locking. Is all of this code running inside a single big lock which is never released ? If so I think everything is fine. If something more complicated might be happening then there are possible deadlock problems. See the comment on "Lock hierarchy" in libxl_event.h. In particular, I worry about the following scenario: AIUI in your setup the callback might, in principle, call any ocaml function. That ocaml function might call back into some long-running C function which temporarily gives up the ocaml lock. If another thread then takes the ocaml lock, and enters libxl, it will block waiting for the libxl lock. The original thread will presumably at some point come back from the long-running operation and try to acquire the ocaml lock. Deadlock. Have you considered this problem ? Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: event management"):> +/* Event handling */...> +short Poll_val(value event)...> + switch (Int_val(event)) { > + case 0: res = POLLIN; break; > + case 1: res = POLLPRI; break;...> +short Poll_events_val(value event_list)...> + while (event_list != Val_emptylist) { > + events |= Poll_val(Field(event_list, 0)); > + event_list = Field(event_list, 1);This is quite striking. You''re converting a bitfield into a linked list of consed enums. Does ocaml really not have something more resembling a set-of-small-enum type, represeted as a bitfield ? The result is going to be a lot of consing every time libxl scratches its nose. In some cases very frequently. For example, if we''re running the bootloader and copying input and output back and forth, we''re using the datacopier machinery in libxl_aoutils.c. That involves enabling the fd writeability callback on each output fd, every time data is read from the input fd, and then disabling the writeability callback every time the data has been written. So one fd register/deregister pair for every lump of console output. There are probably other examples. ...> +value stub_libxl_event_register_callbacks(value ctx, value user)...> + c_user = malloc(sizeof(*c_user)); > + c_user->user = (void *) user;Shouldn''t you be using some kind of error-handling wrapper for malloc ? Having the program dereference null when malloc fails is rather an unfortunate failure mode. At the very least printing something to stderr would be useful. Thanks, Ian.
David Scott
2013-Nov-12 15:49 UTC
Re: [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]
Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: event management"):>> +/* Event handling */ > ... >> +short Poll_val(value event) > ... >> + switch (Int_val(event)) { >> + case 0: res = POLLIN; break; >> + case 1: res = POLLPRI; break; > ... >> +short Poll_events_val(value event_list) > ... >> + while (event_list != Val_emptylist) { >> + events |= Poll_val(Field(event_list, 0)); >> + event_list = Field(event_list, 1);On 12/11/13 14:56, Ian Jackson wrote:> This is quite striking. You''re converting a bitfield into a linked > list of consed enums. Does ocaml really not have something more > resembling a set-of-small-enum type, represeted as a bitfield ? > > The result is going to be a lot of consing every time libxl scratches > its nose. In some cases very frequently. For example, if we''re > running the bootloader and copying input and output back and forth, > we''re using the datacopier machinery in libxl_aoutils.c. That > involves enabling the fd writeability callback on each output fd, > every time data is read from the input fd, and then disabling the > writeability callback every time the data has been written. So one > fd register/deregister pair for every lump of console output. There > are probably other examples.Unfortunately there''s no direct support for bitfields in OCaml''s heap data representation. The common pattern is to convert bitfields into lists of constructors e.g. https://github.com/ocaml/ocaml/blob/trunk/otherlibs/unix/open.c#L74 On the positive side, the GC is optimised specifically for the case of short-lived small objects, since this is what you get when you write a compiler or a theorem prover. An allocation in the minor heap is simply a pointer bump, and the trash is chucked out pretty often. The rule of thumb is that anything which has the allocation profile of a compiler or a theorem prover usually works pretty well :-) I think if we''re allocating a (shortish) list per "lump" of console I/O we''re probably ok since I assume we''re allocating and deallocating bigger buffers for the console data anyway. For higher throughput channels (vchan, network, disk etc) I''d go for larger, statically-allocated pools of buffers for the data and use a bigger lump-size to amortize the cost of the metadata handling. Cheers, Dave
Ian Jackson
2013-Nov-12 16:41 UTC
Re: [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]
David Scott writes ("Re: [Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]"):> Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: > event management"): > > This is quite striking. You''re converting a bitfield into a linked > > list of consed enums. Does ocaml really not have something more > > resembling a set-of-small-enum type, represeted as a bitfield ?..> Unfortunately there''s no direct support for bitfields in OCaml''s heap > data representation. The common pattern is to convert bitfields into > lists of constructors e.g. > > https://github.com/ocaml/ocaml/blob/trunk/otherlibs/unix/open.c#L74How sad.> On the positive side, the GC is optimised specifically for the case of > short-lived small objects, since this is what you get when you write a > compiler or a theorem prover. An allocation in the minor heap is simply > a pointer bump, and the trash is chucked out pretty often. The rule of > thumb is that anything which has the allocation profile of a compiler or > a theorem prover usually works pretty well :-)OK :-).> I think if we''re allocating a (shortish) list per "lump" of console I/O > we''re probably ok since I assume we''re allocating and deallocating > bigger buffers for the console data anyway. For higher throughput > channels (vchan, network, disk etc) I''d go for larger, > statically-allocated pools of buffers for the data and use a bigger > lump-size to amortize the cost of the metadata handling.libxl doesn''t normally concern itself with the main data path, so vchan, network and disk i/o aren''t a problem. So, I''m reassured on this point. The locking question is more difficult, I think. Ian.
Rob Hoes
2013-Nov-12 17:14 UTC
Re: [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]
> > > I think that whether this is the right approach depends on how event > > > loops are traditionally done in ocaml. > > > > Having bindings to the low-level functions > > libxl_osevent_register_hooks and related, allows us to run an event > > loop in OCaml; either one we write ourselves, or one that is available > > elsewhere. > > Right. > > > We are currently running a straightforward, custom event loop in > > xenopsd. It simply maintains a list of fds and timeouts, and runs poll > > in a loop, as you would expect (see > > https://github.com/xapi- > project/xenopsd/blob/master/xl/xenlight_events > > .ml > > for the full code). > > OK, that makes sense. > > > Exposing the low-level event hooks in OCaml gives us the choice to > > implement either of the above options. > > Right. Good.Thanks. I''ll add a summary of this to the commit message.> I have some questions about the details: > > > Firstly, locking. Is all of this code running inside a single big lock which is > never released ? If so I think everything is fine. If something more > complicated might be happening then there are possible deadlock > problems. > > See the comment on "Lock hierarchy" in libxl_event.h. In particular, I worry > about the following scenario: > > AIUI in your setup the callback might, in principle, call any ocaml function. > That ocaml function might call back into some long-running C function which > temporarily gives up the ocaml lock. If another thread then takes the ocaml > lock, and enters libxl, it will block waiting for the libxl lock. The original > thread will presumably at some point come back from the long-running > operation and try to acquire the ocaml lock. Deadlock. > > Have you considered this problem ?Yes, I have encountered such deadlocks, and got around them by making all calls into libxl mutually exclusive. This should mean that there can be only one thread at a time holding or waiting for the libxl lock, and I think that avoids the deadlock you described. It seems to be running smoothly now in our test setup.> > > Rob Hoes writes ("[Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: event > management"): > > +/* Event handling */ > ... > > +short Poll_val(value event) > ... > > + switch (Int_val(event)) { > > + case 0: res = POLLIN; break; > > + case 1: res = POLLPRI; break; > ... > > +short Poll_events_val(value event_list) > ... > > + while (event_list != Val_emptylist) { > > + events |= Poll_val(Field(event_list, 0)); > > + event_list = Field(event_list, 1); > > This is quite striking. You''re converting a bitfield into a linked list of consed > enums. Does ocaml really not have something more resembling a set-of- > small-enum type, represeted as a bitfield ? > > The result is going to be a lot of consing every time libxl scratches its nose. > In some cases very frequently. For example, if we''re running the > bootloader and copying input and output back and forth, we''re using the > datacopier machinery in libxl_aoutils.c. That involves enabling the fd > writeability callback on each output fd, every time data is read from the > input fd, and then disabling the writeability callback every time the data has > been written. So one fd register/deregister pair for every lump of console > output. There are probably other examples.Dave has already responded to this.> ... > > +value stub_libxl_event_register_callbacks(value ctx, value user) > ... > > + c_user = malloc(sizeof(*c_user)); > > + c_user->user = (void *) user; > > Shouldn''t you be using some kind of error-handling wrapper for malloc ? > Having the program dereference null when malloc fails is rather an > unfortunate failure mode. At the very least printing something to stderr > would be useful.Yes, that would be better. I''ll update the patch. Thanks, Rob
Ian Jackson
2013-Nov-12 17:18 UTC
Re: [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]
Rob Hoes writes ("RE: [Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]"):> [Ian Jackson:] > > Have you considered this problem ? > > Yes, I have encountered such deadlocks, and got around them by > making all calls into libxl mutually exclusive. This should mean > that there can be only one thread at a time holding or waiting for > the libxl lock, and I think that avoids the deadlock you > described. It seems to be running smoothly now in our test setup.I''m not sure how that would help. libxl already has a mutex which it takes on entry, so all calls into libxl are already mututally exclusive. What would happen if your fd registration callback ocaml code tried to make a libxl call ? Ian.
Rob Hoes
2013-Nov-14 17:39 UTC
Re: [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]
[Ian Jackson:]> I''m not sure how that would help. libxl already has a mutex which it takes > on entry, so all calls into libxl are already mututally exclusive. > > What would happen if your fd registration callback ocaml code tried to make > a libxl call ?Ok, what I said was not quite right. You are referring to the fact that libxl keeps hold of its lock in the fd registration callback. A possible deadlock scenario like the following may then occur: Thread 1 Thread 2 ======== ======= xenopsd thread starts . acquire ocaml heap lock . . xenopsd calls libxl . acquire libxl lock . . libxl asks xenopsd to register fd . . xenopsd does blocking write . drop ocaml heap lock . write() . . xenopsd thread starts acquire ocaml heap lock . xenopsd calls libxl acquire libxl lock ==> held by thread 1 acquire ocaml heap lock ==> held by thread 2 The experts here have suggested that the common thing to do is to release the ocaml heap lock when calling libxl functions, and reaquire it when returning or calling back into ocaml. I tried to avoid this, because it complicates things, but it seems I have no choice now :) In this case, the ocaml heap lock is never held together with the libxl lock, except in the registration callbacks. If we then promise to not call any libxl functions inside the callback, I think we can avoid deadlocks. The picture becomes as follows: Thread 1 Thread 2 ======== ======= xenopsd thread starts . acquire ocaml heap lock . . xenopsd calls libxl . drop ocaml heap lock . acquire libxl lock . . libxl asks xenopsd to register fd . acquire ocaml heap lock . . xenopsd does blocking write . drop ocaml heap lock . write() . . xenopsd thread starts acquire ocaml heap lock . xenopsd calls libxl drop ocaml heap lock acquire libxl lock . acquire ocaml heap lock . . return to libxl . drop ocaml heap lock . . return to xenopsd . drop libxl lock . acquire ocaml heap lock . . return to xenopsd drop libxl lock acquire ocaml heap lock ...and all is ok. Does that sound right? How about event_occurs callback, and async callbacks? Is the situation the same? Thanks, Rob
Ian Jackson
2013-Nov-14 18:08 UTC
Re: [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]
Rob Hoes writes ("RE: [Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]"):> [Ian Jackson:] > > I''m not sure how that would help. libxl already has a mutex which it takes > > on entry, so all calls into libxl are already mututally exclusive. > > > > What would happen if your fd registration callback ocaml code tried to make > > a libxl call ? > > Ok, what I said was not quite right. You are referring to the fact > that libxl keeps hold of its lock in the fd registration callback. A > possible deadlock scenario like the following may then occur: > > [diagram]Exactly.> The experts here have suggested that the common thing to do is to > release the ocaml heap lock when calling libxl functions, and > reaquire it when returning or calling back into ocaml. I tried to > avoid this, because it complicates things, but it seems I have no > choice now :)That would be one way to do it. It''s the way it''s done in libvirt. Other possibilities that come to mind are: * Somehow ensure in the ocaml code that a thread processing a libxl fd registration registration never calls any blocking C functions which would drop the ocaml lock. I''m not sure how easy this would be in ocaml. * Have fd and timeout registrations put on a queue in the C code in the ocaml bindings, and process them later with the ocaml lock held. Although if you do this you need to make sure that the queue is looked at before delivering any events, and you would need a way to wake up your event loop in another thread to tell it that there were fd/timeout registrations which it needs to deal with. * Use the beforepoll/afterpoll functions rather than the registration machinery. This would be quite workable from a performance point of view if each of your processes handles a single domain (or only a few).> In this case, the ocaml heap lock is never held together with the > libxl lock, except in the registration callbacks. If we then promise > to not call any libxl functions inside the callback, I think we can > avoid deadlocks.Yes.> The picture becomes as follows: > [diagram]Yes, precisely.> Does that sound right? > > How about event_occurs callback, and async callbacks? Is the situation the same?The event occurs and async completion callbacks are made by libxl with the libxl lock _released_. The libxl machinery queues them up internally to make this possible. So they aren''t affected by these restrictions. Ian.
Rob Hoes
2013-Nov-26 18:03 UTC
Re: [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]
Hi Ian, Sorry for taking so long to get back to you on this.> That would be one way to do it. It''s the way it''s done in libvirt.I have just submitted v5 of the (remaining) patches, where this solution is implemented.> Other possibilities that come to mind are: > > * Somehow ensure in the ocaml code that a thread processing a libxl > fd registration registration never calls any blocking C functions > which would drop the ocaml lock. I''m not sure how easy this would > be in ocaml.Indeed, but it is probably impossible to guarantee this, because it will not let you do much in the callbacks. Especially if we''d run a third-party event loop, we''d have to call library functions inside the callbacks which are not under our control.> * Have fd and timeout registrations put on a queue in the C code in > the ocaml bindings, and process them later with the ocaml lock > held. Although if you do this you need to make sure that the > queue is looked at before delivering any events, and you would > need a way to wake up your event loop in another thread to tell it > that there were fd/timeout registrations which it needs to deal > with. > > * Use the beforepoll/afterpoll functions rather than the > registration machinery. This would be quite workable from a > performance point of view if each of your processes handles a > single domain (or only a few).These are good options indeed, which we could use in xenopsd. However, they would not allow us to run a third-party event loop, for example from Lwt.> > How about event_occurs callback, and async callbacks? Is the situation > the same? > > The event occurs and async completion callbacks are made by libxl with the > libxl lock _released_. The libxl machinery queues them up internally to > make this possible. So they aren''t affected by these restrictions.Good, that is clear. Thanks, Rob
Ian Jackson
2013-Nov-28 16:46 UTC
Re: [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]
Ian Jackson writes ("Re: [Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]"):> > +value stub_libxl_event_register_callbacks(value ctx, value user) > ... > > + c_user = malloc(sizeof(*c_user)); > > + c_user->user = (void *) user; > > Shouldn''t you be using some kind of error-handling wrapper for > malloc ? Having the program dereference null when malloc fails is > rather an unfortunate failure mode. At the very least printing > something to stderr would be useful.There''s some more of this in v6. I don''t think it''s a blocker for inclusion but I thought I''d mention it again since my comment seems to have been overlooked. Thanks, Ian.
Rob Hoes
2013-Nov-28 17:53 UTC
Re: [PATCH v2-resend 22/30] libxl: ocaml: event management [and 1 more messages]
Ian Jackson wrote:> Sent: 28 November 2013 4:47 PM > To: Rob Hoes; xen-devel@lists.xen.org; Ian Campbell > Subject: Re: [Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: event > management [and 1 more messages] > > Ian Jackson writes ("Re: [Xen-devel] [PATCH v2-resend 22/30] libxl: ocaml: > event management [and 1 more messages]"): > > > +value stub_libxl_event_register_callbacks(value ctx, value user) > > ... > > > + c_user = malloc(sizeof(*c_user)); > > > + c_user->user = (void *) user; > > > > Shouldn''t you be using some kind of error-handling wrapper for malloc > > ? Having the program dereference null when malloc fails is rather an > > unfortunate failure mode. At the very least printing something to > > stderr would be useful. > > There''s some more of this in v6. I don''t think it''s a blocker for > inclusion but I thought I''d mention it again since my comment seems to > have been overlooked.Yes, sorry, I missed that :( Thanks, Rob