>From a48b47852985f04881315225a2095c6d67697b50 Mon Sep 17 00:00:00 2001 From: Stef Walter Date: Fri, 10 Jan 2014 08:54:41 +0100 Subject: [PATCH 2/6] sbus: Add sbus_vtable and update codegen to support it Each interface is a vtable structure derived from sbus_vtable, in the sense that it has an sbus_vtable struct as its first argument. This lets us upcast the interface vtable structure to an sbus_vtable and dispatch to it dynamically and cleanly. The interface metadata contains information about which vtable offset in the interface metadata should be dispatched to for a given function. This is a common scheme, not only among dbus implementations, but also compiled languages. Currently all the vtable functions are of type sbus_msg_handler_fn. These are the handlers we are familiar with and perform raw processing of the message. Later commits will introduce type safe handlers that levelage compile checking and automatic argument packing/unpacking. Although this may seem contrived now, the remainder of the dbus infrastructure work will build on this, including ofd.Properties, ofd.ObjectManager, ofd.Introspect, compiler checked type safe unpacking/packing, etc. The codegen now generates vtable structures for each interface along-side the metadata, and fills in vtable offsets appropriately. It is obviously still possible to hand-craft such vtables and metadata if needed for a special case. Once again examples output can be found at: src/tests/sbus_codegen_tests_generated.h --- Makefile.am | 2 +- src/sbus/sbus_codegen | 41 ++++++++++++++++++++++++++++++-- src/sbus/sssd_dbus.h | 15 ++++++++++++ src/sbus/sssd_dbus_meta.h | 1 + src/tests/sbus_codegen_tests.c | 33 +++++++++++++++++++++++++ src/tests/sbus_codegen_tests.xml | 5 ++++ src/tests/sbus_codegen_tests_generated.c | 8 +++++++ src/tests/sbus_codegen_tests_generated.h | 19 +++++++++++++++ 8 files changed, 121 insertions(+), 3 deletions(-) diff --git a/Makefile.am b/Makefile.am index 8f1e6f24615a57f27b63ac391dd4aa5e6564212d..836f2067e54ab3a24f23e9a081d6e7159adc59b1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -672,7 +672,7 @@ SUFFIXES = .xml _generated.h _generated.c .xml_generated.h: $(srcdir)/$(SBUS_CODEGEN) --mode=header --output=$@ $< .xml_generated.c: - $(srcdir)/$(SBUS_CODEGEN) --mode=source --output=$@ $< + $(srcdir)/$(SBUS_CODEGEN) --mode=source --include=$(@:.c=.h) --output=$@ $< # Regenerate when codegen changes CODEGEN_CODE = \ diff --git a/src/sbus/sbus_codegen b/src/sbus/sbus_codegen index 9c0147e2b95141f5434445b1cac8827962580a35..6d26d1867750d38e4f70c25fd43ee7fe1abccb58 100755 --- a/src/sbus/sbus_codegen +++ b/src/sbus/sbus_codegen @@ -181,6 +181,7 @@ def source_methods(iface, methods): print " %s__out," % meth.fq_c_name() else: print " NULL, /* no out_args */" + print " offsetof(struct %s, %s)," % (iface.c_name(), meth.c_name()) print " }," print " { NULL, }" print "};" @@ -249,7 +250,7 @@ def source_interface(iface): print "};" print -def generate_source(ifaces, filename): +def generate_source(ifaces, filename, include_header=None): basename = os.path.basename(filename) print "/* The following definitions are auto-generated from %s */" % basename @@ -258,6 +259,8 @@ def generate_source(ifaces, filename): print "#include \"util/util.h\"" print "#include \"sbus/sssd_dbus.h\"" print "#include \"sbus/sssd_dbus_meta.h\"" + if include_header: + print "#include \"%s\"" % include_header print for iface in ifaces: @@ -277,6 +280,20 @@ def generate_source(ifaces, filename): # The sbus_interface structure source_interface(iface) +def header_vtable(iface, methods): + print "/* vtable for %s */" % iface.name + print "struct %s {" % iface.c_name() + print " struct sbus_vtable vtable; /* derive from sbus_vtable */" + + # All methods + for meth in iface.methods: + print " sbus_msg_handler_fn %s;" % meth.c_name() + + # TODO: Property getters and setters will go here + + print "};" + print + def generate_header(ifaces, filename): basename = os.path.basename(filename) guard = "__%s__" % re.sub(r'([^_A-Z0-9])', "_", basename.upper()) @@ -290,6 +307,22 @@ def generate_header(ifaces, filename): print print "/* ------------------------------------------------------------------------" + print " * DBus Vtable handler structures" + print " *" + print " * These structures are filled in by implementors of the different" + print " * dbus interfaces to handle method calls." + print " *" + print " * Handler functions of type sbus_msg_handler_fn accept raw messages," + print " * other handlers will be typed appropriately. If a handler that is" + print " * set to NULL is invoked it will result in a" + print " * org.freedesktop.DBus.Error.NotSupported error for the caller." + print " */" + print + for iface in ifaces: + if iface.methods: + header_vtable(iface, iface.methods) + + print "/* ------------------------------------------------------------------------" print " * DBus Interface Metadata" print " *" print " * These structure definitions are filled in with the information about" @@ -465,6 +498,10 @@ def parse_options(): dest="output", default=None, help="Set output file name (default: stdout)", metavar="FILE") + parser.add_option("--include", + dest="include", default=None, + help="name of a header to #include", + metavar="HEADER") (options, args) = parser.parse_args() if not args: @@ -488,7 +525,7 @@ def main(): if options.mode == "header": generate_header(parser.parsed_interfaces, filename) elif options.mode == "source": - generate_source(parser.parsed_interfaces, filename) + generate_source(parser.parsed_interfaces, filename, options.include) else: assert False, "should not be reached" diff --git a/src/sbus/sssd_dbus.h b/src/sbus/sssd_dbus.h index 7604797c1f8ef74deacacec2251606650ee2402d..e9e7c98672e17c1a90bf688b1edfbc243392632e 100644 --- a/src/sbus/sssd_dbus.h +++ b/src/sbus/sssd_dbus.h @@ -55,6 +55,21 @@ enum { SBUS_RECONNECT_ERROR }; +/* + * This represents vtable of interface handlers for methods and + * properties and so on. The actual vtable structs derive from this struct + * (ie: have this struct as their first member). + * + * The offsets for matching vtable function pointers are in sbus_method_meta + * These are used to dynamically dispatch the method invocations. + */ +struct sbus_vtable { + const struct sbus_interface_meta *meta; + int flags; /* unused for now */ + + /* derived structs place function pointers here. */ +}; + /* Special interface and method for D-BUS introspection */ #define DBUS_INTROSPECT_INTERFACE "org.freedesktop.DBus.Introspectable" #define DBUS_INTROSPECT_METHOD "Introspect" diff --git a/src/sbus/sssd_dbus_meta.h b/src/sbus/sssd_dbus_meta.h index 17ea7a5076ba8ed960b954035ab584ebd1bd4f88..abc992137811be6c6930ff86831a03f7b43fb485 100644 --- a/src/sbus/sssd_dbus_meta.h +++ b/src/sbus/sssd_dbus_meta.h @@ -42,6 +42,7 @@ struct sbus_method_meta { const char *name; const struct sbus_arg_meta *in_args; const struct sbus_arg_meta *out_args; + size_t vtable_offset; }; enum { diff --git a/src/tests/sbus_codegen_tests.c b/src/tests/sbus_codegen_tests.c index c098799872425b03a0c8c8b616da906b02f68722..36ce6fbaf3d8916d815d73fdfcb5844ca73c1a3c 100644 --- a/src/tests/sbus_codegen_tests.c +++ b/src/tests/sbus_codegen_tests.c @@ -115,6 +115,38 @@ START_TEST(test_signals) } END_TEST +static int +mock_move_universe(DBusMessage *msg, struct sbus_connection *conn) +{ + /* not called */ + return 0; +} + +static int +mock_crash_now(DBusMessage *msg, struct sbus_connection *conn) +{ + /* not called */ + return 0; +} + +START_TEST(test_vtable) +{ + struct com_planetexpress_Ship vtable = { + { &com_planetexpress_Ship_meta, 0 }, + mock_move_universe, + mock_crash_now, + }; + + /* + * These are not silly tests: + * - Will fail compilation if c-symbol name was not respected + * - Will fail if method order was not respected + */ + ck_assert(vtable.crash_now == mock_crash_now); + ck_assert(vtable.MoveUniverse == mock_move_universe); +} +END_TEST + Suite *create_suite(void) { Suite *s = suite_create("sbus_codegen"); @@ -126,6 +158,7 @@ Suite *create_suite(void) tcase_add_test(tc, test_methods); tcase_add_test(tc, test_properties); tcase_add_test(tc, test_signals); + tcase_add_test(tc, test_vtable); /* Add all test cases to the test suite */ suite_add_tcase(s, tc); diff --git a/src/tests/sbus_codegen_tests.xml b/src/tests/sbus_codegen_tests.xml index 0def3585a973ef1d7fdef198d8ed8bf5e84c209c..e571dbc17b9e5c0e065d2ab87fb37458072f10b0 100755 --- a/src/tests/sbus_codegen_tests.xml +++ b/src/tests/sbus_codegen_tests.xml @@ -29,6 +29,11 @@ + + + + +