Resent-To: xenomai-core Resent-Message-Id: <48F8B484.90305@domain.hid> Message-Id: <20081017154601.082404492@domain.hid> Date: Fri, 17 Oct 2008 17:46:09 +0200 From: Jan Kiszka References: <20081017154559.420723261@domain.hid> Subject: [Xenomai-core] [PATCH 10/13] Optionally replace pthread_getspecific with TLS variables List-Id: "Xenomai life and development \(bug reports, patches, discussions\)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: xenomai@xenomai.org Cc: Jan Kiszka On architectures that support the __thread storage class and the initial-exec TLS model, several use cases of pthread_get/setspecific can be optimized. On x86, e.g., we are able to implement xeno_get_current() via just two instructions instead of a call into glibc and all the included pthread_key lookup. The minor downside of initial-exec TLS is that libraries using such variables are excluded from dlopen. This patch adds the required check to configure, also installing a switch (--without-__thread) in order to disable the support if dlopen compatibility should be required. It adds a __thread-variant for xeno_get_current and self-references of the current Native, VRTX and VxWorks tasks. RTDK's rt_printf services are intentionally not converted as they are heavy-weighted anyway and depend on the pthread_key destructor mechanism. Signed-off-by: Jan Kiszka --- configure.in | 23 ++++++++++++++++++++ include/asm-generic/bits/bind.h | 41 +++++++++++++++++++++++++------------ include/asm-generic/bits/current.h | 14 ++++++++++-- src/skins/native/init.c | 23 ++++++++++++-------- src/skins/native/task.c | 21 ++++++++++++++++++ src/skins/vrtx/init.c | 20 +++++++++++------- src/skins/vrtx/task.c | 14 +++++++++++- src/skins/vxworks/init.c | 20 +++++++++++------- src/skins/vxworks/taskLib.c | 20 +++++++++++++++++- 9 files changed, 156 insertions(+), 40 deletions(-) Index: b/configure.in =================================================================== --- a/configure.in +++ b/configure.in @@ -762,6 +762,29 @@ LIBS="$LIBS -lrt" AC_CHECK_FUNCS([shm_open shm_unlink]) LIBS="$save_LIBS" +AC_ARG_WITH([__thread], + AC_HELP_STRING([--without-__thread], + [do not use TLS features (allows for dlopen'ing Xenomai libs)]), + [use__thread=$withval], + [use__thread=yes]) + +dnl Check whether the compiler supports the __thread keyword. +if test "x$use__thread" != xno; then + AC_CACHE_CHECK([for __thread], libc_cv_gcc___thread, + [cat > conftest.c <<\EOF +__thread int a __attribute__ ((tls_model ("initial-exec"))) = 42; +EOF + if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -c -Werror conftest.c >&AS_MESSAGE_LOG_FD]); then + libc_cv_gcc___thread=yes + else + libc_cv_gcc___thread=no + fi + rm -f conftest*]) + if test "$libc_cv_gcc___thread" = yes; then + AC_DEFINE(HAVE___THREAD,1,[config]) + fi +fi + dnl dnl Build the Makefiles dnl Index: b/include/asm-generic/bits/bind.h =================================================================== --- a/include/asm-generic/bits/bind.h +++ b/include/asm-generic/bits/bind.h @@ -11,24 +11,23 @@ #include #include #include +#include #include -__attribute__ ((weak)) -pthread_key_t xeno_current_key; +#ifdef HAVE___THREAD +__thread xnhandle_t xeno_current __attribute__ ((tls_model ("initial-exec"))) = + XN_NO_HANDLE; -__attribute__ ((weak)) -void xeno_set_current(void) +static inline void __xeno_set_current(xnhandle_t current) { - void *kthread_cb; - int err; + xeno_current = current; +} +#else /* !HAVE___THREAD */ +pthread_key_t xeno_current_key; - err = XENOMAI_SYSCALL1(__xn_sys_current, &kthread_cb); - if (err) { - fprintf(stderr, "Xenomai: error obtaining handle for current " - "thread: %s\n", strerror(err)); - exit(1); - } - pthread_setspecific(xeno_current_key, kthread_cb); +static inline void __xeno_set_current(xnhandle_t current) +{ + pthread_setspecific(xeno_current_key, (void *)current); } static __attribute__ ((constructor)) @@ -41,6 +40,22 @@ void init_current_key(void) exit(1); } } +#endif /* !HAVE___THREAD */ + +__attribute__ ((weak)) +void xeno_set_current(void) +{ + xnhandle_t current; + int err; + + err = XENOMAI_SYSCALL1(__xn_sys_current, ¤t); + if (err) { + fprintf(stderr, "Xenomai: error obtaining handle for current " + "thread: %s\n", strerror(err)); + exit(1); + } + __xeno_set_current(current); +} #ifdef CONFIG_XENO_FASTSYNCH __attribute__ ((weak)) Index: b/include/asm-generic/bits/current.h =================================================================== --- a/include/asm-generic/bits/current.h +++ b/include/asm-generic/bits/current.h @@ -4,9 +4,16 @@ #include #include -extern pthread_key_t xeno_current_key; +#ifdef HAVE___THREAD +extern __thread xnhandle_t xeno_current __attribute__ ((tls_model ("initial-exec"))); -extern void xeno_set_current(void); +static inline xnhandle_t xeno_get_current(void) +{ + return xeno_current; +} + +#else /* ! HAVE___THREAD */ +extern pthread_key_t xeno_current_key; static inline xnhandle_t xeno_get_current(void) { @@ -17,5 +24,8 @@ static inline xnhandle_t xeno_get_curren return (xnhandle_t)val; } +#endif /* ! HAVE___THREAD */ + +void xeno_set_current(void); #endif /* _XENO_ASM_GENERIC_CURRENT_H */ Index: b/src/skins/native/init.c =================================================================== --- a/src/skins/native/init.c +++ b/src/skins/native/init.c @@ -27,11 +27,12 @@ #include #include -pthread_key_t __native_tskey; - int __native_muxid = -1; void native_timer_init(int); +#ifndef HAVE___THREAD +pthread_key_t __native_tskey; + static void __flush_tsd(void *tsd) { /* Free the task descriptor allocated by rt_task_self(). */ @@ -39,6 +40,17 @@ static void __flush_tsd(void *tsd) } static __attribute__ ((constructor)) +void __init_native_tskey(void) + /* Allocate a TSD key for indexing self task pointers. */ + + if (pthread_key_create(&__native_tskey, &__flush_tsd) != 0) { + fprintf(stderr, "Xenomai: failed to allocate new TSD key?!\n"); + exit(1); + } +} +#endif /* !HAVE___THREAD */ + +static __attribute__ ((constructor)) void __init_xeno_interface(void) { __native_muxid = @@ -49,11 +61,4 @@ void __init_xeno_interface(void) #endif /* CONFIG_XENO_HW_DIRECT_TSC */ __native_muxid = __xn_mux_shifted_id(__native_muxid); - - /* Allocate a TSD key for indexing self task pointers. */ - - if (pthread_key_create(&__native_tskey, &__flush_tsd) != 0) { - fprintf(stderr, "Xenomai: failed to allocate new TSD key?!\n"); - exit(1); - } } Index: b/src/skins/native/task.c =================================================================== --- a/src/skins/native/task.c +++ b/src/skins/native/task.c @@ -29,7 +29,14 @@ #include #include "wrappers.h" +#ifdef HAVE___THREAD +__thread RT_TASK __native_self __attribute__ ((tls_model ("initial-exec"))) = { + .opaque = XN_NO_HANDLE, + .opaque2 = 0 +}; +#else /* !HAVE___THREAD */ extern pthread_key_t __native_tskey; +#endif /* !HAVE___THREAD */ extern int __native_muxid; @@ -91,6 +98,10 @@ static void *rt_task_trampoline(void *co xeno_set_current(); +#ifdef HAVE___THREAD + __native_self = *iargs->task; +#endif /* HAVE___THREAD */ + /* Wait on the barrier for the task to be started. The barrier could be released in order to process Linux signals while the Xenomai shadow is still dormant; in such a case, resume wait. */ @@ -316,6 +327,15 @@ RT_TASK *rt_task_self(void) { RT_TASK *self; +#ifdef HAVE___THREAD + self = &__native_self; + + if (self->opaque == XN_NO_HANDLE) + return NULL; + +#else /* !HAVE___THREAD */ + RT_TASK *self; + self = (RT_TASK *)pthread_getspecific(__native_tskey); if (self) @@ -330,6 +350,7 @@ RT_TASK *rt_task_self(void) } pthread_setspecific(__native_tskey, self); +#endif /* !HAVE___THREAD */ return self; } Index: b/src/skins/vxworks/init.c =================================================================== --- a/src/skins/vxworks/init.c +++ b/src/skins/vxworks/init.c @@ -26,10 +26,11 @@ #include #include -pthread_key_t __vxworks_tskey; - int __vxworks_muxid = -1; +#ifndef HAVE___THREAD +pthread_key_t __vxworks_tskey; + static void __flush_tsd(void *tsd) { /* Free the task descriptor allocated by taskIdSelf(). */ @@ -37,12 +38,8 @@ static void __flush_tsd(void *tsd) } static __attribute__ ((constructor)) -void __init_xeno_interface(void) +void __init_vxworks_tskey(void) { - __vxworks_muxid = xeno_bind_skin(VXWORKS_SKIN_MAGIC, - "vxworks", "xeno_vxworks"); - __vxworks_muxid = __xn_mux_shifted_id(__vxworks_muxid); - /* Allocate a TSD key for indexing self task pointers. */ if (pthread_key_create(&__vxworks_tskey, &__flush_tsd) != 0) { @@ -50,3 +47,12 @@ void __init_xeno_interface(void) exit(1); } } +#endif /* !HAVE___THREAD */ + +static __attribute__ ((constructor)) +void __init_xeno_interface(void) +{ + __vxworks_muxid = xeno_bind_skin(VXWORKS_SKIN_MAGIC, + "vxworks", "xeno_vxworks"); + __vxworks_muxid = __xn_mux_shifted_id(__vxworks_muxid); +} Index: b/src/skins/vxworks/taskLib.c =================================================================== --- a/src/skins/vxworks/taskLib.c +++ b/src/skins/vxworks/taskLib.c @@ -30,7 +30,14 @@ #include #include "wrappers.h" +#ifdef HAVE___THREAD +__thread WIND_TCB +__vxworks_self __attribute__ ((tls_model ("initial-exec"))) = { + .handle = XN_NO_HANDLE +}; +#else /* !HAVE___THREAD */ extern pthread_key_t __vxworks_tskey; +#endif /* !HAVE___THREAD */ extern int __vxworks_muxid; @@ -120,6 +127,10 @@ static void *wind_task_trampoline(void * xeno_set_current(); +#ifdef HAVE___THREAD + __vxworks_self = *iargs->pTcb; +#endif /* HAVE___THREAD */ + /* Wait on the barrier for the task to be started. The barrier could be released in order to process Linux signals while the Xenomai shadow is still dormant; in such a case, resume wait. */ @@ -309,9 +320,15 @@ STATUS taskResume(TASK_ID task_id) TASK_ID taskIdSelf(void) { - WIND_TCB *self = (WIND_TCB *)pthread_getspecific(__vxworks_tskey); +#ifdef HAVE___THREAD + return __vxworks_self.handle; + +#else /* !HAVE___THREAD */ + WIND_TCB *self; int err; + self = (WIND_TCB *)pthread_getspecific(__vxworks_tskey); + if (self) return self->handle; @@ -332,6 +349,7 @@ TASK_ID taskIdSelf(void) pthread_setspecific(__vxworks_tskey, self); return self->handle; +#endif /* !HAVE___THREAD */ } STATUS taskPrioritySet(TASK_ID task_id, int prio) Index: b/src/skins/vrtx/init.c =================================================================== --- a/src/skins/vrtx/init.c +++ b/src/skins/vrtx/init.c @@ -26,10 +26,11 @@ #include #include -pthread_key_t __vrtx_tskey; - int __vrtx_muxid = -1; +#ifndef HAVE___THREAD +pthread_key_t __vrtx_tskey; + static void __flush_tsd(void *tsd) { /* Free the TCB struct. */ @@ -37,12 +38,8 @@ static void __flush_tsd(void *tsd) } static __attribute__ ((constructor)) -void __init_xeno_interface(void) +void __init_vrtx_tskey(void) { - __vrtx_muxid = - xeno_bind_skin(VRTX_SKIN_MAGIC, "vrtx", "xeno_vrtx"); - __vrtx_muxid = __xn_mux_shifted_id(__vrtx_muxid); - /* Allocate a TSD key for indexing self task pointers. */ if (pthread_key_create(&__vrtx_tskey, &__flush_tsd) != 0) { @@ -50,3 +47,12 @@ void __init_xeno_interface(void) exit(1); } } +#endif /* !HAVE___THREAD */ + +static __attribute__ ((constructor)) +void __init_xeno_interface(void) +{ + __vrtx_muxid = + xeno_bind_skin(VRTX_SKIN_MAGIC, "vrtx", "xeno_vrtx"); + __vrtx_muxid = __xn_mux_shifted_id(__vrtx_muxid); +} Index: b/src/skins/vrtx/task.c =================================================================== --- a/src/skins/vrtx/task.c +++ b/src/skins/vrtx/task.c @@ -29,7 +29,11 @@ #include #include +#ifdef HAVE___THREAD +__thread TCB __vrtx_tcb __attribute__ ((tls_model ("initial-exec"))); +#else /* !HAVE___THREAD */ extern pthread_key_t __vrtx_tskey; +#endif /* !HAVE___THREAD */ extern int __vrtx_muxid; @@ -81,7 +85,9 @@ static void *vrtx_task_trampoline(void * struct sched_param param; int policy; long err; +#ifndef HAVE___THREAD TCB *tcb; +#endif /* !HAVE___THREAD */ /* Backup the arg struct, it might vanish after completion. */ memcpy(&_iargs, iargs, sizeof(_iargs)); @@ -96,6 +102,7 @@ static void *vrtx_task_trampoline(void * /* vrtx_task_delete requires asynchronous cancellation */ pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); +#ifndef HAVE___THREAD tcb = (TCB *) malloc(sizeof(*tcb)); if (tcb == NULL) { fprintf(stderr, "Xenomai: failed to allocate local TCB?!\n"); @@ -104,6 +111,7 @@ static void *vrtx_task_trampoline(void * } pthread_setspecific(__vrtx_tskey, tcb); +#endif /* !HAVE___THREAD */ old_sigharden_handler = signal(SIGHARDEN, &vrtx_task_sigharden); @@ -224,7 +232,11 @@ TCB *sc_tinquiry(int pinfo[], int tid, i { TCB *tcb; - tcb = (TCB *) pthread_getspecific(__vrtx_tskey); /* Cannot fail. */ +#ifdef HAVE___THREAD + tcb = &__vrtx_tcb; +#else /* !HAVE___THREAD */ + tcb = (TCB *) pthread_getspecific(__vrtx_tskey); /* Cannot fail. */ +#endif /* !HAVE___THREAD */ *errp = XENOMAI_SKINCALL3(__vrtx_muxid, __vrtx_tinquiry, pinfo, tcb, tid);