Module: xenomai-3
Branch: next
Commit: d6d8047ecd093bd827026678b3c7619b08dd7dd2
URL:    
http://git.xenomai.org/?p=xenomai-3.git;a=commit;h=d6d8047ecd093bd827026678b3c7619b08dd7dd2

Author: Philippe Gerum <r...@xenomai.org>
Date:   Tue Mar 21 15:20:29 2017 +0100

boilerplate/setup: allow DSO bootstrap modules to coexist with main one

Gluing a PIC bootstrap module to a DSO is a common way to start the
Xenomai services before constructors of static C++ objects
instantiated by the DSO and which depend on such services, are
invoked.

With such module present in the DSO, a Cobalt-based application
process would attach itself to the Cobalt core via the bootstrapping
sequence, enabling the real-time services for the whole process,
including the static C++ constructors which may be invoked when
attaching the shared object.

e.g. in libfoo.so:

class FOO {
protected:
        sem_t sem;
public:
        static FOO bar;
};

...

FOO FOO::bar;

FOO::FOO()
{
        // Initialize a Cobalt semaphore
        sem_init(&sem, 0, 0);
}

However, adding a bootstrap module to a DSO currently prevents from
merging a second bootstrap module aimed at kickstarting the main
program's setup code and early inits, due to conflicting symbols and
the restriction on invoking xenomai_init() only once for any given
process.

The changes introduce a DSO-specific initialization service
(xenomai_init_dso()), which may be called from the context of the
dynamic linker attaching a shared object to the current
executable. The DSO-specific bootstrap module - if present - will call
xenomai_init_dso(), there is no restriction on the number of DSOs
calling this service.

The non-DSO bootstrap module invokes xenomai_init() as previously, for
kickstarting the main program's early inits.

---

 include/boilerplate/setup.h      |    1 +
 include/xenomai/init.h           |    2 +
 lib/boilerplate/init/Makefile.am |    2 +-
 lib/boilerplate/init/bootstrap.c |   28 +++++++---
 lib/boilerplate/setup.c          |  104 ++++++++++++++++++++++++--------------
 5 files changed, 91 insertions(+), 46 deletions(-)

diff --git a/include/boilerplate/setup.h b/include/boilerplate/setup.h
index 374758b..7df3cfe 100644
--- a/include/boilerplate/setup.h
+++ b/include/boilerplate/setup.h
@@ -46,6 +46,7 @@ struct setup_descriptor {
                int opt_start;
                int opt_end;
                struct pvholder next;
+               int done;
        } __reserved;
 };
 
diff --git a/include/xenomai/init.h b/include/xenomai/init.h
index 9adc90d..598bf53 100644
--- a/include/xenomai/init.h
+++ b/include/xenomai/init.h
@@ -27,6 +27,8 @@ extern "C" {
 
 void xenomai_init(int *argcp, char *const **argvp);
 
+void xenomai_init_dso(int *argcp, char *const **argvp);
+
 int xenomai_main(int argc, char *const argv[]);
 
 void xenomai_usage(void);
diff --git a/lib/boilerplate/init/Makefile.am b/lib/boilerplate/init/Makefile.am
index 702c900..b78dd61 100644
--- a/lib/boilerplate/init/Makefile.am
+++ b/lib/boilerplate/init/Makefile.am
@@ -3,7 +3,6 @@ noinst_LIBRARIES = libbootstrap.a
 libbootstrap_a_SOURCES = bootstrap.c
 
 libbootstrap_a_CPPFLAGS =              \
-       -D__INTERCEPT_MAIN__            \
        @XENO_USER_CFLAGS@              \
        -I$(top_srcdir)/include         \
        -I$(top_srcdir)/lib
@@ -13,6 +12,7 @@ noinst_LTLIBRARIES = libbootstrap-pic.la
 libbootstrap_pic_la_SOURCES = bootstrap.c
 
 libbootstrap_pic_la_CPPFLAGS =         \
+       -D__BOOTSTRAP_DSO__             \
        @XENO_USER_CFLAGS@              \
        -I$(top_srcdir)/include         \
        -I$(top_srcdir)/lib
diff --git a/lib/boilerplate/init/bootstrap.c b/lib/boilerplate/init/bootstrap.c
index 54d1c46..e72a7b8 100644
--- a/lib/boilerplate/init/bootstrap.c
+++ b/lib/boilerplate/init/bootstrap.c
@@ -26,8 +26,6 @@ static int early_argc;
 
 static char *const *early_argv;
 
-const int xenomai_auto_bootstrap = 1;
-
 /*
  * The bootstrap module object is built in two forms:
  *
@@ -41,11 +39,22 @@ const int xenomai_auto_bootstrap = 1;
  *   any wrapper to a main() routine - which does not exist - but only
  *   a constructor routine performing the inits.
  *
- * The dedicated macro __INTERCEPT_MAIN__ tells us whether the main()
- * interception code should be present in the relocatable object.
+ * The macro __BOOTSTRAP_DSO__ tells us whether we are building the
+ * bootstrap module to be glued into a dynamic shared object. If not,
+ * the main() interception code should be present in the relocatable
+ * object.
  */
 
-#ifdef __INTERCEPT_MAIN__
+#ifdef __BOOTSTRAP_DSO__
+
+static inline void call_init(int *argcp, char *const **argvp)
+{
+       xenomai_init_dso(argcp, argvp);
+}
+
+#else
+
+const int xenomai_auto_bootstrap = 1;
 
 int __real_main(int argc, char *const argv[]);
 
@@ -62,7 +71,12 @@ int xenomai_main(int argc, char *const argv[])
        return __real_main(argc, argv);
 }
 
-#endif /* !__INTERCEPT_MAIN__ */
+static inline void call_init(int *argcp, char *const **argvp)
+{
+       xenomai_init(argcp, argvp);
+}
+
+#endif /* !__BOOTSTRAP_DSO__ */
 
 __bootstrap_ctor static void xenomai_bootstrap(void)
 {
@@ -123,7 +137,7 @@ __bootstrap_ctor static void xenomai_bootstrap(void)
        argv = v;
        argc = n;
 
-       xenomai_init(&argc, &argv);
+       call_init(&argc, &argv);
        early_argc = argc;
        early_argv = argv;
 }
diff --git a/lib/boilerplate/setup.c b/lib/boilerplate/setup.c
index f1760e6..1992826 100644
--- a/lib/boilerplate/setup.c
+++ b/lib/boilerplate/setup.c
@@ -48,7 +48,7 @@ int __config_done = 0;
 
 const int __weak xenomai_auto_bootstrap = 0;
 
-static int init_done;
+static int base_init_done;
 
 static DEFINE_PRIVATE_LIST(setup_list);
 
@@ -331,26 +331,13 @@ void xenomai_usage(void)
         fprintf(stderr, "--help                                display 
help\n");
 }
 
-static int parse_base_options(int *argcp, char *const **argvp,
-                             int *largcp, char ***uargvp,
+static int parse_base_options(int *argcp, int *largcp, char **uargv,
                              const struct option *options,
                              int base_opt_start)
 {
        int c, lindex, ret, n;
-       char **uargv;
-
-       /*
-        * Prepare a user argument vector we can modify, copying the
-        * one we have been given by the application code in
-        * xenomai_init(). This vector will be expunged from Xenomai
-        * proper options as we discover them.
-        */
-       uargv = prep_args(*argcp, *argvp, largcp);
-       if (uargv == NULL)
-               return -ENOMEM;
 
        __base_setup_data.arg0 = uargv[0];
-       *uargvp = uargv;
        opterr = 0;
 
        /*
@@ -446,7 +433,8 @@ static int parse_setup_options(int *argcp, int largc, char 
**uargv,
                if (lindex == -1)
                        continue; /* Not handled here. */
                pvlist_for_each_entry(setup, &setup_list, __reserved.next) {
-                       if (setup->parse_option == NULL)
+                       if (setup->__reserved.done ||
+                           setup->parse_option == NULL)
                                continue;
                        if (lindex < setup->__reserved.opt_start ||
                            lindex >= setup->__reserved.opt_end)
@@ -472,18 +460,38 @@ static int parse_setup_options(int *argcp, int largc, 
char **uargv,
        return 0;
 }
 
-void xenomai_init(int *argcp, char *const **argvp)
+static void __xenomai_init(int *argcp, char *const **argvp, const char *me)
 {
        int ret, largc, base_opt_start;
        struct setup_descriptor *setup;
        struct option *options;
-       char **uargv = NULL;
        struct service svc;
+       char **uargv;
 
-       if (init_done) {
-               early_warning("duplicate call to %s() ignored", __func__);
-               early_warning("(xeno-config --no-auto-init disables implicit 
call)");
-               return;
+       /*
+        * Build the global option array, merging all option sets.
+        */
+       options = build_option_array(&base_opt_start);
+       if (options == NULL) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       /*
+        * Prepare a user argument vector we can modify, copying the
+        * one we have been given by the bootstrap module. This vector
+        * will be expunged from Xenomai's base options as we discover
+        * them.
+        */
+       uargv = prep_args(*argcp, *argvp, &largc);
+       if (uargv == NULL) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       if (base_init_done) {
+               trace_me("warm init from %s", me);
+               goto setup;
        }
 
        /* Our node id. is the tid of the main thread. */
@@ -496,25 +504,16 @@ void xenomai_init(int *argcp, char *const **argvp)
        CPU_ZERO(&__base_setup_data.cpu_affinity);
 
        /*
-        * Build the global option array, merging all option sets.
-        */
-       options = build_option_array(&base_opt_start);
-       if (options == NULL) {
-               ret = -ENOMEM;
-               goto fail;
-       }
-
-       /*
         * Parse the base options first, to bootstrap the core with
         * the right config values.
         */
-       ret = parse_base_options(argcp, argvp, &largc, &uargv,
+       ret = parse_base_options(argcp, &largc, uargv,
                                 options, base_opt_start);
        if (ret)
                goto fail;
 
-       trace_me("%s() running", __func__);
-
+       trace_me("cold init from %s", me);
+       
 #ifndef CONFIG_SMP
        if (__base_setup_data.no_sanity == 0) {
                ret = get_static_cpu_count();
@@ -541,12 +540,13 @@ void xenomai_init(int *argcp, char *const **argvp)
         * setup handlers for tuning the configuration, then parsing
         * their own options, and eventually doing the init chores.
         */
+setup:
        if (!pvlist_empty(&setup_list)) {
 
                CANCEL_DEFER(svc);
 
                pvlist_for_each_entry(setup, &setup_list, __reserved.next) {
-                       if (setup->tune) {
+                       if (!setup->__reserved.done && setup->tune) {
                                trace_me("%s->tune()", setup->name);
                                ret = setup->tune();
                                if (ret)
@@ -565,11 +565,14 @@ void xenomai_init(int *argcp, char *const **argvp)
                __config_done = 1;
        
                pvlist_for_each_entry(setup, &setup_list, __reserved.next) {
+                       if (setup->__reserved.done)
+                               continue;
                        if (setup->init) {
                                trace_me("%s->init()", setup->name);
                                ret = setup->init();
                                if (ret)
                                        break;
+                               setup->__reserved.done = 1;
                        }
                }
 
@@ -604,14 +607,35 @@ void xenomai_init(int *argcp, char *const **argvp)
         * bail out.
         */
        *argvp = uargv;
-       init_done = 1;
-       trace_me("initialization complete");
+       base_init_done = 1;
 
        return;
 fail:
        early_panic("initialization failed, %s", symerror(ret));
 }
 
+void xenomai_init(int *argcp, char *const **argvp)
+{
+       const char *me = get_program_name();
+       static int init_done;
+
+       if (init_done) {
+               early_warning("duplicate call from main program "
+                             "to %s() ignored", __func__);
+               early_warning("(xeno-config --no-auto-init disables implicit 
call)");
+       }
+
+       __xenomai_init(argcp, argvp, me);
+       init_done = 1;
+       trace_me("%s bootstrap done", me);
+}
+
+void xenomai_init_dso(int *argcp, char *const **argvp)
+{
+       __xenomai_init(argcp, argvp, "DSO");
+       trace_me("DSO bootstrap done");
+}
+
 void __trace_me(const char *fmt, ...)
 {
        va_list ap;
@@ -631,9 +655,13 @@ void __register_setup_call(struct setup_descriptor *p, int 
id)
        /*
         * Trap late registration due to wrong constructor priorities.
         */
-       assert(!init_done);
+       assert(!base_init_done);
        p->__reserved.id = id;
+       p->__reserved.done = 0;
 
+       /*
+        * Insert the new descriptor (highest id first).
+        */
        if (!pvlist_empty(&setup_list)) {
                pvlist_for_each_entry_reverse(pos, &setup_list, 
__reserved.next) {
                        if (id >= pos->__reserved.id) {


_______________________________________________
Xenomai-git mailing list
Xenomai-git@xenomai.org
https://xenomai.org/mailman/listinfo/xenomai-git

Reply via email to