Module: xenomai-3 Branch: stable-3.0.x 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