Based on librtprint, this is an attempt to unintrusively (/wrt timing)
instrument Xenomai syscalls inside the user space libs.

The support is compiled into the skin libs if --enable-debug was passed
to configure. To switch rt-syscall tracing on for an RT application, the
environment variable XNTRACE_SYS has to be defined (to whatever). Output
happens to stderr so far. Here is a demo trace of the rtprint example
from the previous patch:

> # XNTRACE_SYS= examples/native/rtprint
> [b7df36c0 Task 1] ENTER rt_task_shadow(task=0xbfd55aa8, name=Task 1, prio=10, 
> mode=0x0)
> [b7df36c0 Task 1]  EXIT rt_task_shadow() = 0
> [b7df36c0 Task 1] ENTER rt_task_create(task=0xbfd55aa0, name=Task 2, 
> stksize=0, prio=11, mode=0x0)
> [b7df36c0 Task 1]  EXIT rt_task_create() = 0
> [b7df36c0 Task 1] ENTER rt_task_start(task=0xbfd55aa0, entry=0x8048754, 
> cookie=(nil))
> [b7f65b90 Task 2] ENTER rt_task_trampoline(cookie=(nil))
> This triggers auto-init of rt_print for the calling thread.
> A last switch to secondary mode can occure here, but future invocations of 
> rt_printf are safe.
> [b7f65b90 Task 2] ENTER rt_task_sleep(delay=3333333)
> [b7df36c0 Task 1]  EXIT rt_task_start() = 0
> [b7df36c0 Task 1] ENTER rt_task_sleep(delay=5000000)
> [b7f65b90 Task 2]  EXIT rt_task_sleep() = 0
> b7f65b90 Task 2: #1 Yet another RT printer - but to stderr.
> [b7f65b90 Task 2] ENTER rt_task_sleep(delay=3333333)
> [b7df36c0 Task 1]  EXIT rt_task_sleep() = 0
...

Besides introducing the generic bits of rt-syscall tracing, this patch
also instruments very few functions of the native and the posix skin. As
I said earlier, full instrumentation like this requires a) a consensus
that we want this and b) quite some typing work which could luckily
happen step by step.

Yet further ideas to enhance this approach:
 o Time stamping based on cheap TSCs could be added.
 o A lib-internal handler for SIGXCHG could be installed, and the
   related mode switch signal could be forced on. That way the tracing
   back-end would become aware of switches from primary to secondary
   mode and could report this automatically.
 o Support to dump the trace to a file could be provided (already
   possibly via redirection "2>output-file", but may contain stderr
   stuff from the traced program).

OK, looking forward to any feedback.

Jan
---
 configure.in                    |   20 ++++++++---
 include/asm-generic/Makefile.am |    2 -
 include/asm-generic/bits/bind.h |   12 +++++++
 include/asm-generic/usystrace.h |   59 ++++++++++++++++++++++++++++++++++
 src/skins/native/Makefile.am    |    2 -
 src/skins/native/init.c         |    3 +
 src/skins/native/task.c         |   68 ++++++++++++++++++++++++++++++++--------
 src/skins/posix/Makefile.am     |    2 -
 src/skins/posix/clock.c         |   26 ++++++++++++---
 src/skins/posix/init.c          |    3 +
 src/skins/posix/mutex.c         |   21 +++++++++++-
 src/skins/posix/thread.c        |   15 ++++++--
 12 files changed, 200 insertions(+), 33 deletions(-)

Index: xenomai/configure.in
===================================================================
--- xenomai.orig/configure.in
+++ xenomai/configure.in
@@ -111,15 +111,22 @@ dnl
 
 dnl Debug build (default: off)
 
-debug_symbols=
-AC_MSG_CHECKING(for debug symbols)
+CONFIG_DEBUG=
+AC_MSG_CHECKING(for debug support)
 AC_ARG_ENABLE(debug,
 	AS_HELP_STRING([--enable-debug], [Enable debug support in nucleus and debug symbols in programs]),
 	[case "$enableval" in
-	y | yes) debug_symbols=y ;;
-	*) unset debug_symbols ;;
+	y | yes) CONFIG_DEBUG=y ;;
+	*) unset CONFIG_DEBUG ;;
 	esac])
-AC_MSG_RESULT(${debug_symbols:-no})
+AC_MSG_RESULT(${CONFIG_DEBUG:-no})
+
+if test x$CONFIG_DEBUG = xy ; then
+	SYSTRACE_LIB="-L\$(top_builddir)/src/rtprint -lrtprint"
+else
+	unset SYSTRACE_LIB
+fi
+AC_SUBST(SYSTRACE_LIB)
 
 dnl SMP support (default: off)
 
@@ -419,6 +426,7 @@ dnl don't need to make particular cases 
 dnl also be compiled in user-space libs.
 dnl
 
+test x$CONFIG_DEBUG = xy && AC_DEFINE(CONFIG_DEBUG,1,[config])
 test x$CONFIG_XENO_X86_SEP = xy && AC_DEFINE(CONFIG_XENO_X86_SEP,1,[config])
 test x$CONFIG_SMP = xy && AC_DEFINE(CONFIG_SMP,1,[config])
 test x$CONFIG_X86_TSC = xy && AC_DEFINE(CONFIG_X86_TSC,1,[config])
@@ -531,7 +539,7 @@ case $XENO_TARGET_ARCH in
         ;;
 esac
 
-if test x$debug_symbols = xy; then
+if test x$CONFIG_DEBUG = xy; then
    XENO_USER_CFLAGS="-g $XENO_USER_CFLAGS"
 else
    XENO_USER_CFLAGS="-O2 $XENO_USER_CFLAGS"
Index: xenomai/include/asm-generic/Makefile.am
===================================================================
--- xenomai.orig/include/asm-generic/Makefile.am
+++ xenomai/include/asm-generic/Makefile.am
@@ -1,5 +1,5 @@
 includedir = $(prefix)/include/asm-generic
 
-include_HEADERS = features.h hal.h syscall.h system.h wrappers.h
+include_HEADERS = features.h hal.h syscall.h system.h usystrace.h wrappers.h
 
 SUBDIRS = bits
Index: xenomai/include/asm-generic/bits/bind.h
===================================================================
--- xenomai.orig/include/asm-generic/bits/bind.h
+++ xenomai/include/asm-generic/bits/bind.h
@@ -8,6 +8,10 @@
 #include <signal.h>
 #include <asm/xenomai/syscall.h>
 
+#ifdef CONFIG_DEBUG
+int __xeno_systrace;
+#endif /* CONFIG_DEBUG */
+
 void xeno_handle_mlock_alert(int sig);
 
 static inline int
@@ -21,6 +25,10 @@ xeno_bind_skin(unsigned skin_magic, cons
 	xeno_arch_features_check();
 #endif /* xeno_arch_features_check */
 
+#ifdef CONFIG_DEBUG
+	__xeno_systrace = !!getenv("XNTRACE_SYS");
+#endif /* CONFIG_DEBUG */
+
 	muxid = XENOMAI_SYSBIND(skin_magic,
 				XENOMAI_FEAT_DEP, XENOMAI_ABI_REV, &finfo);
 	switch (muxid) {
@@ -75,6 +83,10 @@ xeno_bind_skin_opt(unsigned skin_magic, 
 	xeno_arch_features_check();
 #endif /* xeno_arch_features_check */
 
+#ifdef CONFIG_DEBUG
+	__xeno_systrace = !!getenv("XNTRACE_SYS");
+#endif /* CONFIG_DEBUG */
+
 	muxid = XENOMAI_SYSBIND(skin_magic,
 				XENOMAI_FEAT_DEP, XENOMAI_ABI_REV, &finfo);
 	switch (muxid) {
Index: xenomai/include/asm-generic/usystrace.h
===================================================================
--- /dev/null
+++ xenomai/include/asm-generic/usystrace.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 Jan Kiszka <[EMAIL PROTECTED]>.
+ *
+ * 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 _XENO_ASM_GENERIC_USYSTRACE_H
+#define _XENO_ASM_GENERIC_USYSTRACE_H
+
+#include <xeno_config.h>
+#include <rtprint.h>
+
+#define SYSTRACE_VOID				"<void>"
+
+#define systrace_str(string)			(string) ? string : "(nil)"
+
+#ifdef CONFIG_DEBUG
+
+extern int __xeno_systrace;
+
+#define systrace_init()				rt_print_auto_init(1)
+#define systrace_init_thread(name)		rt_print_init(0, name)
+
+#define systrace_enter(func, arg_format, ...) \
+do { \
+	if (__xeno_systrace) \
+		rt_fprintf(stderr, "[%s] ENTER %s(" arg_format ")\n", \
+			   rt_print_buffer_name(), func, ##__VA_ARGS__); \
+} while (0)
+
+#define systrace_exit(func, ret_format, ...) \
+do { \
+	if (__xeno_systrace) \
+		rt_fprintf(stderr, "[%s]  EXIT %s() = " ret_format "\n", \
+			   rt_print_buffer_name(), func, ##__VA_ARGS__); \
+} while (0)
+
+#else /* !CONFIG_DEBUG */
+
+#define systrace_init()				do { } while (0)
+#define systrace_init_thread(name)		do { } while (0)
+#define systrace_enter(func, arg_format, ...)	do { } while (0)
+#define systrace_exit(func, ret_format, ...)	do { } while (0)
+
+#endif /* !CONFIG_DEBUG */
+
+#endif /* !_XENO_ASM_GENERIC_USYSTRACE_H */
Index: xenomai/src/skins/native/Makefile.am
===================================================================
--- xenomai.orig/src/skins/native/Makefile.am
+++ xenomai/src/skins/native/Makefile.am
@@ -1,6 +1,6 @@
 lib_LTLIBRARIES = libnative.la
 
-libnative_la_LDFLAGS = -version-info 0:0:0 -lpthread
+libnative_la_LDFLAGS = -version-info 0:0:0 -lpthread @SYSTRACE_LIB@
 
 libnative_la_SOURCES = \
 	alarm.c \
Index: xenomai/src/skins/native/init.c
===================================================================
--- xenomai.orig/src/skins/native/init.c
+++ xenomai/src/skins/native/init.c
@@ -26,6 +26,7 @@
 #include <native/task.h>
 #include <asm-generic/bits/bind.h>
 #include <asm-generic/bits/mlock_alert.h>
+#include <asm-generic/usystrace.h>
 
 pthread_key_t __native_tskey;
 
@@ -49,4 +50,6 @@ void __init_xeno_interface(void)
 		fprintf(stderr, "Xenomai: failed to allocate new TSD key?!\n");
 		exit(1);
 	}
+
+	systrace_init();
 }
Index: xenomai/src/skins/native/task.c
===================================================================
--- xenomai.orig/src/skins/native/task.c
+++ xenomai/src/skins/native/task.c
@@ -26,6 +26,7 @@
 #include <limits.h>
 #include <native/syscall.h>
 #include <native/task.h>
+#include <asm-generic/usystrace.h>
 
 extern pthread_key_t __native_tskey;
 
@@ -54,6 +55,8 @@ static void *rt_task_trampoline(void *co
 	struct rt_arg_bulk bulk;
 	long err;
 
+	systrace_init_thread(iargs->name);
+
 	if (iargs->prio > 0) {
 		/* Ok, this looks like weird, but we need this. */
 		param.sched_priority = sched_get_priority_max(SCHED_FIFO);
@@ -85,8 +88,11 @@ static void *rt_task_trampoline(void *co
 		err = XENOMAI_SYSCALL2(__xn_sys_barrier, &entry, &cookie);
 	while (err == -EINTR);
 
-	if (!err)
+	if (!err) {
+		systrace_enter(__FUNCTION__, "cookie=%p", cookie);
 		entry(cookie);
+		systrace_exit(__FUNCTION__, SYSTRACE_VOID);
+	}
 
       fail:
 
@@ -103,6 +109,10 @@ int rt_task_create(RT_TASK *task,
 	pthread_t thid;
 	int err;
 
+	systrace_enter(__FUNCTION__, "task=%p, name=%s, stksize=%d, "
+		       "prio=%d, mode=0x%x", task, systrace_str(name),
+		       stksize, prio, mode);
+
 	/* Migrate this thread to the Linux domain since we are about to
 	   issue a series of regular kernel syscalls in order to create
 	   the new Linux thread, which in turn will be mapped to a
@@ -135,24 +145,39 @@ int rt_task_create(RT_TASK *task,
 	}
 	pthread_attr_setschedparam(&thattr, &param);
 
-	err = pthread_create(&thid, &thattr, &rt_task_trampoline, &iargs);
+	err = -pthread_create(&thid, &thattr, &rt_task_trampoline, &iargs);
 
-	if (err)
-		return -err;
+	if (!err) {
+		/* Wait for sync with rt_task_trampoline() */
+		err = XENOMAI_SYSCALL1(__xn_sys_completion, &completion);
+	}
 
-	/* Wait for sync with rt_task_trampoline() */
-	return XENOMAI_SYSCALL1(__xn_sys_completion, &completion);
+	systrace_exit(__FUNCTION__, "%d", err);
+	return err;
 }
 
 int rt_task_start(RT_TASK *task, void (*entry) (void *cookie), void *cookie)
 {
-	return XENOMAI_SKINCALL3(__native_muxid,
-				 __native_task_start, task, entry, cookie);
+	int err;
+
+	systrace_enter(__FUNCTION__, "task=%p, entry=%p, cookie=%p",
+		       task, entry, cookie);
+
+	err = XENOMAI_SKINCALL3(__native_muxid,
+				__native_task_start, task, entry, cookie);
+
+	systrace_exit(__FUNCTION__, "%d", err);
+	return err;
 }
 
 int rt_task_shadow(RT_TASK *task, const char *name, int prio, int mode)
 {
 	struct rt_arg_bulk bulk;
+	int err;
+
+	systrace_init_thread(name);
+	systrace_enter(__FUNCTION__, "task=%p, name=%s, prio=%d, mode=0x%x",
+		       task, systrace_str(name), prio, mode);
 
 	/* rt_task_delete requires asynchronous cancellation */
 	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
@@ -165,8 +190,11 @@ int rt_task_shadow(RT_TASK *task, const 
 	bulk.a4 = (u_long)mode;
 	bulk.a5 = (u_long)pthread_self();
 
-	return XENOMAI_SKINCALL2(__native_muxid, __native_task_create, &bulk,
-				 NULL);
+	err = XENOMAI_SKINCALL2(__native_muxid, __native_task_create, &bulk,
+				NULL);
+
+	systrace_exit(__FUNCTION__, "%d", err);
+	return err;
 }
 
 int rt_task_bind(RT_TASK *task, const char *name, RTIME timeout)
@@ -216,8 +244,16 @@ int rt_task_set_periodic(RT_TASK *task, 
 
 int rt_task_wait_period(unsigned long *overruns_r)
 {
-	return XENOMAI_SKINCALL1(__native_muxid,
-				 __native_task_wait_period, overruns_r);
+	int err;
+
+	systrace_enter(__FUNCTION__, "overruns_r=%p", overruns_r);
+
+	err = XENOMAI_SKINCALL1(__native_muxid,
+				__native_task_wait_period, overruns_r);
+
+	systrace_exit(__FUNCTION__, "%d, *overruns_r=%d", err,
+		      (overruns_r) ? *overruns_r : 0);
+	return err;
 }
 
 int rt_task_set_priority(RT_TASK *task, int prio)
@@ -228,8 +264,14 @@ int rt_task_set_priority(RT_TASK *task, 
 
 int rt_task_sleep(RTIME delay)
 {
-	return XENOMAI_SKINCALL1(__native_muxid, __native_task_sleep, &delay);
+	int err;
 
+	systrace_enter(__FUNCTION__, "delay=%llu", delay);
+
+	err = XENOMAI_SKINCALL1(__native_muxid, __native_task_sleep, &delay);
+
+	systrace_exit(__FUNCTION__, "%d", err);
+	return err;
 }
 
 int rt_task_sleep_until(RTIME date)
Index: xenomai/src/skins/posix/Makefile.am
===================================================================
--- xenomai.orig/src/skins/posix/Makefile.am
+++ xenomai/src/skins/posix/Makefile.am
@@ -2,7 +2,7 @@ includedir = $(prefix)/include/posix
 
 lib_LTLIBRARIES = libpthread_rt.la
 
-libpthread_rt_la_LDFLAGS = -version-info 0:0:0 -lpthread
+libpthread_rt_la_LDFLAGS = -version-info 0:0:0 -lpthread @SYSTRACE_LIB@
 
 libpthread_rt_la_SOURCES = \
 	init.c \
Index: xenomai/src/skins/posix/clock.c
===================================================================
--- xenomai.orig/src/skins/posix/clock.c
+++ xenomai/src/skins/posix/clock.c
@@ -20,6 +20,7 @@
 #include <pthread.h>		/* For pthread_setcanceltype. */
 #include <posix/syscall.h>
 #include <time.h>
+#include <asm-generic/xenomai/usystrace.h>
 
 extern int __pse51_muxid;
 
@@ -39,15 +40,22 @@ int __wrap_clock_getres(clockid_t clock_
 
 int __wrap_clock_gettime(clockid_t clock_id, struct timespec *tp)
 {
-	int err = -XENOMAI_SKINCALL2(__pse51_muxid,
-				     __pse51_clock_gettime,
-				     clock_id,
-				     tp);
+	int err;
+
+	systrace_enter("clock_gettime", "clock_id=%d, tp=%p", clock_id, tp);
+
+	err = XENOMAI_SKINCALL2(__pse51_muxid,
+				 __pse51_clock_gettime,
+				 clock_id,
+				 tp);
+
+	systrace_exit("clock_gettime", "%d, tp={%d, %d}", err,
+		      tp ? tp->tv_sec : 0, tp ? tp->tv_nsec : 0);
 
 	if (!err)
 		return 0;
 
-	errno = err;
+	errno = -err;
 	return -1;
 }
 
@@ -71,6 +79,11 @@ int __wrap_clock_nanosleep(clockid_t clo
 {
 	int err, oldtype;
 
+	systrace_enter("clock_nanosleep", "clock_id=%d, flags=0x%x, "
+		       "rqtp=%p {%d, %d}, rmtp=%p", clock_id, flags, rqtp,
+		       rqtp ? rqtp->tv_sec : 0, rqtp ? rqtp->tv_nsec : 0,
+		       rmtp);
+
 	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldtype);
 
 	err = -XENOMAI_SKINCALL4(__pse51_muxid,
@@ -79,6 +92,9 @@ int __wrap_clock_nanosleep(clockid_t clo
 
 	pthread_setcanceltype(oldtype, NULL);
 
+	systrace_exit("clock_nanosleep", "%d, rmtp={%d, %d}", err,
+		      rmtp ? rmtp->tv_sec : 0, rmtp ? rmtp->tv_nsec : 0);
+
 	return err;
 }
 
Index: xenomai/src/skins/posix/init.c
===================================================================
--- xenomai.orig/src/skins/posix/init.c
+++ xenomai/src/skins/posix/init.c
@@ -28,6 +28,7 @@
 #include <rtdm/syscall.h>
 #include <asm-generic/bits/bind.h>
 #include <asm-generic/bits/mlock_alert.h>
+#include <asm-generic/xenomai/usystrace.h>
 
 int __pse51_muxid = -1;
 int __rtdm_muxid = -1;
@@ -85,4 +86,6 @@ void __init_posix_interface(void)
 		}
 		fork_handler_registered = 1;
 	}
+
+	systrace_init();
 }
Index: xenomai/src/skins/posix/mutex.c
===================================================================
--- xenomai.orig/src/skins/posix/mutex.c
+++ xenomai/src/skins/posix/mutex.c
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <posix/syscall.h>
 #include <pthread.h>
+#include <asm-generic/xenomai/usystrace.h>
 
 extern int __pse51_muxid;
 
@@ -97,12 +98,16 @@ int __wrap_pthread_mutex_lock(pthread_mu
 	union __xeno_mutex *_mutex = (union __xeno_mutex *)mutex;
 	int err;
 
+	systrace_enter("pthread_mutex_lock", "mutex=%p", mutex);
+
 	do {
 		err = XENOMAI_SKINCALL1(__pse51_muxid,
 					__pse51_mutex_lock,
 					&_mutex->shadow_mutex);
 	} while (err == -EINTR);
 
+	systrace_exit("pthread_mutex_lock", "%d", -err);
+
 	return -err;
 }
 
@@ -112,12 +117,17 @@ int __wrap_pthread_mutex_timedlock(pthre
 	union __xeno_mutex *_mutex = (union __xeno_mutex *)mutex;
 	int err;
 
+	systrace_enter("pthread_mutex_timedlock", "mutex=%p, to=%p {%d, %d}",
+		       mutex, to, to ? to->tv_sec : 0, to ? to->tv_nsec : 0);
+
 	do {
 		err = XENOMAI_SKINCALL2(__pse51_muxid,
 					__pse51_mutex_timedlock,
 					&_mutex->shadow_mutex, to);
 	} while (err == -EINTR);
 
+	systrace_exit("pthread_mutex_timedlock", "%d", -err);
+
 	return -err;
 }
 
@@ -132,7 +142,14 @@ int __wrap_pthread_mutex_trylock(pthread
 int __wrap_pthread_mutex_unlock(pthread_mutex_t * mutex)
 {
 	union __xeno_mutex *_mutex = (union __xeno_mutex *)mutex;
+	int err;
 
-	return -XENOMAI_SKINCALL1(__pse51_muxid,
-				  __pse51_mutex_unlock, &_mutex->shadow_mutex);
+	systrace_enter("pthread_mutex_unlock", "mutex=%p", mutex);
+
+	err = -XENOMAI_SKINCALL1(__pse51_muxid,
+				 __pse51_mutex_unlock, &_mutex->shadow_mutex);
+
+	systrace_exit("pthread_mutex_unlock", "%d", err);
+
+	return err;
 }
Index: xenomai/src/skins/posix/thread.c
===================================================================
--- xenomai.orig/src/skins/posix/thread.c
+++ xenomai/src/skins/posix/thread.c
@@ -22,6 +22,7 @@
 #include <pthread.h>
 #include <semaphore.h>
 #include <posix/syscall.h>
+#include <asm-generic/xenomai/usystrace.h>
 
 extern int __pse51_muxid;
 
@@ -36,18 +37,22 @@ int __wrap_pthread_setschedparam(pthread
 	pthread_t myself = pthread_self();
 	int err, promoted;
 
+	systrace_enter("pthread_setschedparam", "pthread=%p, policy=%d, "
+		       "param=%p {%d}", thread, policy, param,
+		       param ? param->sched_priority : 0);
+
 	err = -XENOMAI_SKINCALL5(__pse51_muxid,
 				 __pse51_thread_setschedparam,
 				 thread, policy, param, myself, &promoted);
 
-	if (err == EPERM)
-		return __real_pthread_setschedparam(thread, policy, param);
-
 	if (!err && promoted) {
 		signal(SIGHARDEN, &__pthread_sigharden_handler);
 		if (policy != SCHED_OTHER)
 			XENOMAI_SYSCALL1(__xn_sys_migrate, XENOMAI_XENO_DOMAIN);
-	}
+	} else if (err == EPERM)
+		err = __real_pthread_setschedparam(thread, policy, param);
+
+	systrace_exit("pthread_setschedparam", "%d%", err);
 
 	return err;
 }
@@ -114,7 +119,9 @@ static void *__pthread_trampoline(void *
 	if (!err) {
 		if (policy != SCHED_OTHER)
 			XENOMAI_SYSCALL1(__xn_sys_migrate, XENOMAI_XENO_DOMAIN);
+		systrace_enter("pthread_trampoline", "cookie=%p", cookie);
 		status = start(cookie);
+		systrace_exit("pthread_trampoline", "%p", status);
 	} else
 		status = (void *)-err;
 

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
Xenomai-core mailing list
Xenomai-core@gna.org
https://mail.gna.org/listinfo/xenomai-core

Reply via email to