Commit 83b0f189 authored by Philippe Gerum's avatar Philippe Gerum

lib: share the common setup and bootstrap code

Make pure POSIX applications and Copperplate-based ones share the same
auto-init mechanism. This means that all applications now
automatically recognize a set of base common options, which is
currently:

--cpu-affinity=<cpuset>, --[no-]sanity, --quiet[=level], --silent and
--version.

Applications which do not want Xenomai to interpose on the main()
routine transparently for handling these options and bootstrapping the
service libraries may disable this feature by passing the
--no-auto-init switch to xeno-config when collecting the linker
flags. In this configuration, the system must be bootstrapped manually
by a call to xenomai_init() from the application code though.

This change is C++ friendly, since it also enables the Xenomai high
level services (e.g. VxWorks, pSOS) before the static constructors
run, by default.
parent 6ce16cb0
......@@ -864,9 +864,12 @@ dnl in-tree executables which require POSIX symbol wrapping.
AC_SUBST([CONFIG_STATUS_DEPENDENCIES], ["$cobalt_wrappers"])
fi
XENO_AUTOINIT_LDFLAGS="-Wl,--wrap=main -Wl,--dynamic-list=$topdir/scripts/dynlist.ld"
XENO_AUTOINIT_LDFLAGS='$(top_builddir)/lib/boilerplate/init/bootstrap.o'" -Wl,--wrap=main -Wl,--dynamic-list=$topdir/scripts/dynlist.ld"
AC_SUBST(XENO_AUTOINIT_LDFLAGS)
XENO_CORE_LIB=$rtcore_type/lib${rtcore_type}.la
AC_SUBST(XENO_CORE_LIB)
dnl
dnl Build the Makefiles
dnl
......@@ -905,6 +908,7 @@ AC_CONFIG_FILES([ \
scripts/xeno \
lib/Makefile \
lib/boilerplate/Makefile \
lib/boilerplate/init/Makefile \
lib/cobalt/Makefile \
lib/cobalt/arch/Makefile \
lib/cobalt/arch/arm/Makefile \
......@@ -931,6 +935,7 @@ AC_CONFIG_FILES([ \
lib/cobalt/arch/sh/include/Makefile \
lib/cobalt/arch/sh/include/asm/Makefile \
lib/cobalt/arch/sh/include/asm/xenomai/Makefile \
lib/mercury/Makefile \
lib/copperplate/Makefile \
lib/copperplate/regd/Makefile \
lib/alchemy/Makefile \
......@@ -999,6 +1004,7 @@ AC_CONFIG_FILES([ \
include/trank/posix/Makefile \
include/trank/native/Makefile \
include/trank/rtdm/Makefile \
include/xenomai/Makefile \
doc/Makefile \
doc/doxygen/Makefile \
doc/doxygen/xeno3prm-common.conf \
......
......@@ -2,9 +2,7 @@ demodir = @XENO_DEMO_DIR@
demo_PROGRAMS = altency
core_libs =
if XENO_COBALT
core_libs += ../../lib/cobalt/libcobalt.la
SUBDIRS = cobalt
endif
......@@ -15,7 +13,7 @@ cppflags = \
ldadd = \
../../lib/alchemy/libalchemy.la \
../../lib/copperplate/libcopperplate.la \
$(core_libs) \
../../lib/@XENO_CORE_LIB@ \
@XENO_USER_LDADD@
altency_SOURCES = altency.c
......
......@@ -12,6 +12,7 @@ ldadd = \
../../../lib/alchemy/libalchemy.la \
../../../lib/copperplate/libcopperplate.la \
../../../lib/cobalt/libcobalt.la \
@XENO_AUTOINIT_LDFLAGS@ \
$(XENO_POSIX_WRAPPERS) \
@XENO_USER_LDADD@ \
-lpthread -lrt
......
demodir = @XENO_DEMO_DIR@
CCLD = $(top_srcdir)/scripts/wrap-link.sh $(CC)
core_libs =
if XENO_COBALT
SUBDIRS = cobalt
core_libs += ../../lib/cobalt/libcobalt.la
endif
demo_PROGRAMS = \
can-rtt
demo_PROGRAMS = can-rtt
cppflags = \
$(XENO_USER_CFLAGS) \
-I$(top_srcdir)/include
ldflags = $(XENO_POSIX_WRAPPERS)
ldflags = @XENO_AUTOINIT_LDFLAGS@ $(XENO_POSIX_WRAPPERS)
ldadd = \
$(core_libs) \
../../lib/@XENO_CORE_LIB@ \
@XENO_USER_LDADD@ \
-lpthread -lrt
......
......@@ -15,7 +15,7 @@ cppflags = \
$(XENO_USER_CFLAGS) \
-I$(top_srcdir)/include
ldflags = $(XENO_POSIX_WRAPPERS)
ldflags = @XENO_AUTOINIT_LDFLAGS@ $(XENO_POSIX_WRAPPERS)
ldadd = \
../../../lib/cobalt/libcobalt.la \
......
......@@ -104,8 +104,9 @@ to eliminate irregular delays which tend to appear on fully idle
systems. Therefore, keeping the load generation enabled most often
leads to a more accurate estimation.
*--quiet*::
Tame down verbosity of the auto-tuner.
*--quiet[=level]*::
Tame down verbosity of the auto-tuner. --quiet[=2] means fully quiet,
quiet=1 means almost quiet.
*--help*::
Display a short help.
......
......@@ -9,7 +9,8 @@ SUBDIRS = \
alchemy \
psos \
trank \
vxworks
vxworks \
xenomai
if XENO_COBALT
SUBDIRS += \
......@@ -29,4 +30,5 @@ DIST_SUBDIRS = \
rtdm \
smokey \
trank \
vxworks
vxworks \
xenomai
......@@ -26,8 +26,6 @@
#include <boilerplate/compiler.h>
#include <boilerplate/atomic.h>
extern struct timespec __init_date;
extern pthread_mutex_t __printlock;
struct error_frame;
......@@ -58,7 +56,13 @@ void __namecpy_requires_character_array_as_destination(void);
__dst[sizeof(__dst) - 1] = '\0'; \
__dst; \
})
#define early_panic(__fmt, __args...) \
__early_panic(__func__, __fmt, ##__args)
#define panic(__fmt, __args...) \
__panic(__func__, __fmt, ##__args)
#ifdef __cplusplus
extern "C" {
#endif
......@@ -69,12 +73,15 @@ void __printout(const char *name,
const char *header,
const char *fmt, va_list ap);
void __noreturn __panic(const char *name,
const char *fmt, va_list ap);
void __noreturn __early_panic(const char *fn,
const char *fmt, ...);
void early_panic(const char *fmt, ...);
void __noreturn ___panic(const char *fn,
const char *name,
const char *fmt, va_list ap);
void __noreturn panic(const char *fmt, ...);
void __noreturn __panic(const char *fn,
const char *fmt, ...);
void __warning(const char *name,
const char *fmt, va_list ap);
......@@ -90,6 +97,8 @@ void early_notice(const char *fmt, ...);
void notice(const char *fmt, ...);
void __boilerplate_init(void);
const char *symerror(int errnum);
char *generate_name(char *buf, const char *radix,
......@@ -97,8 +106,6 @@ char *generate_name(char *buf, const char *radix,
void error_hook(struct error_frame *ef);
void boilerplate_init(void);
int get_static_cpu_count(void);
pid_t get_thread_pid(void);
......
......@@ -67,7 +67,7 @@ void __debug(const char *name, const char *fmt, ...);
char *__get_error_buf(size_t *sizep);
int debug_init(void);
void debug_init(void);
#ifdef __cplusplus
}
......@@ -118,7 +118,7 @@ struct backtrace_data {
__buf; \
})
#define debug_init() ({ 0; })
#define debug_init() do { } while (0)
#endif /* !CONFIG_XENO_DEBUG */
......
......@@ -19,52 +19,82 @@
#define _BOILERPLATE_SETUP_H
#include <boilerplate/list.h>
#include <boilerplate/wrappers.h>
#include <sched.h>
struct base_setup_data {
cpu_set_t cpu_affinity;
int no_mlock;
int no_sanity;
int silent_mode;
int quiet_mode;
const char *arg0;
};
struct option;
struct skin_descriptor {
struct setup_descriptor {
const char *name;
int (*init)(void);
const struct option *options;
int (*parse_option)(int optnum, const char *optarg);
void (*help)(void);
struct {
int id;
int opt_start;
int opt_end;
struct pvholder next;
} __reserved;
};
#define DECLARE_SKIN(__name, __priority) \
static __attribute__ ((constructor(__priority))) \
void __declare_ ## __name(void) \
/*
* We have three pre-defined constructor priorities:
*
* - One for setup calls (__setup_ctor), which are guaranteed to run
* prior to the bootstrap code. You should use setup calls for
* implementing initialization hooks which depend on a particular call
* order. Each Xenomai interface layer is initialized via a dedicated
* setup call.
*
* - A second priority is assigned to early init calls (__early_ctor),
* which are also guaranteed to run prior to the bootstrap
* code. Whether such early code runs before OR after any setup code
* is __UNSPECIFIED__. By design, such code may not invoke any Xenomai
* service, and generally speaking, should have no dependencies on
* anything else.
*
* - The last priority level is used for the bootstrap code
* (__bootstrap_ctor), which is guaranteed to run after any
* setup/early code.
*
* The guarantees on the init order don't go beyond what is stated
* here, do NOT assume more than this.
*/
#define __setup_ctor __attribute__ ((constructor(200)))
#define __early_ctor __attribute__ ((constructor(210)))
#define __bootstrap_ctor __attribute__ ((constructor(220)))
#define __setup_call(__name, __id) \
static __setup_ctor void __declare_ ## __name(void) \
{ \
__register_skin(&(__name)); \
__register_setup_call(&(__name), __id); \
}
#define core_setup_call(__name) __setup_call(__name, 0)
#define boilerplate_setup_call(__name) __setup_call(__name, 1)
#define copperplate_setup_call(__name) __setup_call(__name, 2)
#define interface_setup_call(__name) __setup_call(__name, 3)
#define post_setup_call(__name) __setup_call(__name, 4)
#ifdef __cplusplus
extern "C" {
#endif
void __register_skin(struct skin_descriptor *p);
void xenomai_init(int *argcp, char *const **argvp);
void __register_setup_call(struct setup_descriptor *p, int id);
extern pid_t __node_id;
extern struct base_setup_data __base_setup_data;
extern const char *xenomai_version_string;
#ifdef __cplusplus
}
#endif
......
......@@ -38,12 +38,6 @@
#include <cobalt/uapi/cond.h>
#include <cobalt/uapi/sem.h>
#define report_error(fmt, args...) \
__STD(fprintf(stderr, "Xenomai/cobalt: %s(): " fmt "\n", __func__, ##args))
#define report_error_cont(fmt, args...) \
__STD(fprintf(stderr, " " fmt "\n", ##args))
#define cobalt_commit_memory(p) __cobalt_commit_memory(p, sizeof(*p))
struct cobalt_tsd_hook {
......@@ -135,10 +129,6 @@ int cobalt_sched_weighted_prio(int policy,
void cobalt_register_tsd_hook(struct cobalt_tsd_hook *th);
void __libcobalt_init(void);
extern int __cobalt_defer_init;
extern int __cobalt_no_shadow;
extern int __cobalt_control_bind;
......
......@@ -6,7 +6,6 @@ includesub_HEADERS = \
debug.h \
eventobj.h \
heapobj.h \
init.h \
reference.h \
registry.h \
semobj.h \
......
......@@ -20,7 +20,6 @@
#define _COPPERPLATE_CLUSTER_H
#include <boilerplate/hash.h>
#include <copperplate/init.h>
#include <copperplate/syncobj.h>
#ifdef CONFIG_XENO_PSHARED
......
......@@ -25,7 +25,6 @@
#include <boilerplate/list.h>
#include <boilerplate/hash.h>
#include <boilerplate/obstack.h>
#include <copperplate/init.h>
struct fsobj;
......
......@@ -21,6 +21,7 @@
#include <boilerplate/list.h>
#include <boilerplate/libc.h>
#include <copperplate/clockobj.h>
#include <xenomai/init.h>
#define SMOKEY_INT(__name) { \
.name = # __name, \
......@@ -71,8 +72,6 @@ struct smokey_test {
#define for_each_smokey_test(__pos) \
pvlist_for_each_entry((__pos), &smokey_test_list, __reserved.next)
#define __SMOKEYPLUG_CTOR_PRIO 310
#define __smokey_arg_count(__args) \
(sizeof(__args) / sizeof(__args[0]))
......@@ -86,8 +85,7 @@ struct smokey_test {
.description = (__desc), \
.run = run_ ## __plugin, \
}; \
void smokey_plugin_ ## __plugin(void); \
__attribute__((constructor(__SMOKEYPLUG_CTOR_PRIO))) \
__early_ctor void smokey_plugin_ ## __plugin(void); \
void smokey_plugin_ ## __plugin(void) \
{ \
smokey_register_plugin(&(__plugin)); \
......
includesubdir = $(includedir)/xenomai
includesub_HEADERS = \
init.h
......@@ -15,26 +15,23 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef _XENOMAI_XENOMAI_INIT_H
#define _XENOMAI_XENOMAI_INIT_H
#ifndef _COPPERPLATE_INIT_H
#define _COPPERPLATE_INIT_H
#include <stdarg.h>
#include <sched.h>
#include <boilerplate/trace.h>
#include <boilerplate/ancillaries.h>
#include <boilerplate/setup.h>
#define __LIBCOPPERPLATE_CTOR_PRIO 250
#ifdef __cplusplus
extern "C" {
#endif
int copperplate_main(int argc, char *const argv[]);
void xenomai_init(int *argcp, char *const **argvp);
int xenomai_main(int argc, char *const argv[]);
extern const char *xenomai_version_string;
#ifdef __cplusplus
}
#endif
#endif /* _COPPERPLATE_INIT_H */
#endif /* _XENOMAI_XENOMAI_INIT_H */
......@@ -5,6 +5,8 @@ SUBDIRS += \
cobalt \
analogy \
trank
else
SUBDIRS += mercury
endif
SUBDIRS += \
......
......@@ -4,7 +4,6 @@ libalchemy_la_LDFLAGS = @XENO_LIB_LDFLAGS@ -version-info 0:0:0
libalchemy_la_SOURCES = \
init.c \
init.h \
internal.c \
internal.h \
reference.h \
......
......@@ -21,8 +21,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <copperplate/init.h>
#include "init.h"
#include <xenomai/init.h>
#include "timer.h"
#include "task.h"
#include "sem.h"
......@@ -78,7 +77,7 @@ static int alchemy_parse_option(int optnum, const char *optarg)
static void alchemy_help(void)
{
fprintf(stderr, "--alchemy-clock-resolution=<ns> tick value (default 1ns, tickless)\n");
fprintf(stderr, "--alchemy-clock-resolution=<ns> tick value (default 1ns, tickless)\n");
}
#ifdef CONFIG_XENO_COBALT
......@@ -132,7 +131,7 @@ static int alchemy_init(void)
return 0;
}
static struct skin_descriptor alchemy_skin = {
static struct setup_descriptor alchemy_skin = {
.name = "alchemy",
.init = alchemy_init,
.options = alchemy_options,
......@@ -140,4 +139,4 @@ static struct skin_descriptor alchemy_skin = {
.help = alchemy_help,
};
DECLARE_SKIN(alchemy_skin, __LIBALCHEMY_CTOR_PRIO);
interface_setup_call(alchemy_skin);
/*
* Copyright (C) 2014 Philippe Gerum <rpm@xenomai.org>.
*
* This library 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; either
* version 2 of the License, or (at your option) any later version.
*
* This library 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.
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
*/
#ifndef _ALCHEMY_INIT_H
#define _ALCHEMY_INIT_H
#define __LIBALCHEMY_CTOR_PRIO 300
#endif /* _ALCHEMY_INIT_H */
......@@ -19,8 +19,3 @@ libanalogy_la_CPPFLAGS = \
@XENO_USER_CFLAGS@ \
-I$(top_srcdir)/include \
-I$(top_srcdir)/lib/boilerplate
libanalogy_la_LIBADD = \
../boilerplate/libboilerplate.la \
-lm
......@@ -8,7 +8,8 @@ libboilerplate_la_SOURCES = \
hash.c \
obstack.c \
setup.c \
time.c
time.c \
wrappers.c
if XENO_DEBUG
libboilerplate_la_SOURCES += debug.c
......@@ -83,6 +84,8 @@ libtlsf_la_CPPFLAGS = \
-I$(top_srcdir)/include \
-DTLSF_USE_LOCKS=1 -DUSE_MMAP=1 -DTLSF_STATISTIC=1
SUBDIRS = init
EXTRA_DIST += tlsf/README
SPARSE = sparse
......
......@@ -29,30 +29,24 @@
#include "boilerplate/lock.h"
#include "boilerplate/time.h"
#include "boilerplate/scope.h"
#include "boilerplate/setup.h"
#include "boilerplate/debug.h"
#include "boilerplate/ancillaries.h"
#include "xenomai/init.h"
pthread_mutex_t __printlock;
struct timespec __init_date;
static struct timespec init_date;
void __printout(const char *name, const char *header,
const char *fmt, va_list ap)
static int init_done;
static void __do_printout(const char *name, const char *header,
unsigned int ms, unsigned int us,
const char *fmt, va_list ap)
{
unsigned long long ms, us, ns;
struct timespec now, delta;
FILE *fp = stderr;
__RT(clock_gettime(CLOCK_MONOTONIC, &now));
timespec_sub(&delta, &now, &__init_date);
ns = delta.tv_sec * 1000000000ULL;
ns += delta.tv_nsec;
ms = ns / 1000000ULL;
us = (ns % 1000000ULL) / 1000ULL;
SIGSAFE_LOCK_ENTRY(&__printlock);
fprintf(fp, "%4d\"%.3d.%.3d| ",
(int)ms / 1000, (int)ms % 1000, (int)us);
fprintf(fp, "%4u\"%.3u.%.3u| ", ms / 1000, ms % 1000, us);
if (header)
fputs(header, fp);
......@@ -61,7 +55,34 @@ void __printout(const char *name, const char *header,
vfprintf(fp, fmt, ap);
fputc('\n', fp);
fflush(fp);
}
void __printout(const char *name, const char *header,
const char *fmt, va_list ap)
{
struct timespec now, delta;
unsigned long long ns;
unsigned int ms, us;
/*
* Catch early printouts, when the init sequence is not
* completed yet. In such event, we don't care for serializing
* output, since we must be running over the main thread
* uncontended.
*/
if (!init_done) {
__do_printout(name, header, 0, 0, fmt, ap);
return;
}
__RT(clock_gettime(CLOCK_MONOTONIC, &now));
timespec_sub(&delta, &now, &init_date);
ns = delta.tv_sec * 1000000000ULL;
ns += delta.tv_nsec;
ms = ns / 1000000ULL;
us = (ns % 1000000ULL) / 1000ULL;
SIGSAFE_LOCK_ENTRY(&__printlock);
__do_printout(name, header, ms, us, fmt, ap);
SIGSAFE_LOCK_EXIT(&__printlock);
}
......@@ -75,9 +96,14 @@ void __notice(const char *name, const char *fmt, va_list ap)
__printout(name, NULL, fmt, ap);
}
void __panic(const char *name, const char *fmt, va_list ap)
void ___panic(const char *fn, const char *name,
const char *fmt, va_list ap)
{
__printout(name, "BUG: ", fmt, ap);
char *p;
if (asprintf(&p, "BUG in %s(): ", fn) < 0)
p = "BUG: ";
__printout(name, p, fmt, ap);
exit(1);
}
......@@ -153,17 +179,17 @@ void __run_cleanup_block(struct cleanup_block *cb)
cb->handler(cb->arg);
}
void early_panic(const char *fmt, ...)
void __early_panic(const char *fn, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
__panic(NULL, fmt, ap);
___panic(fn, NULL, fmt, ap);
va_end(ap);
}
void panic(const char *fmt, ...)
__attribute__((alias("early_panic"), weak));