Add thread-local storage (TLS) support

Tested and implemented on ARM, m68k, PowerPC and SPARC.  Other
architectures need more work.
This commit is contained in:
Sebastian Huber
2014-01-28 12:10:08 +01:00
parent 960fd8546f
commit 022851aba5
77 changed files with 1132 additions and 60 deletions

View File

@@ -34,6 +34,7 @@
#include <rtems/score/thread.h>
#include <rtems/score/interr.h>
#include <rtems/score/cpu.h>
#include <rtems/score/tls.h>
#include <rtems/powerpc/powerpc.h>
/* _CPU_Initialize
@@ -62,13 +63,13 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
)
{
ppc_context *the_ppc_context;
uint32_t msr_value;
uint32_t sp;
register uint32_t gpr2 __asm__("2");
sp = (uint32_t)stack_base + size - PPC_MINIMUM_STACK_FRAME_SIZE;
@@ -128,9 +129,18 @@ void _CPU_Context_Initialize(
the_ppc_context->gpr1 = sp;
the_ppc_context->msr = msr_value;
the_ppc_context->lr = (uint32_t) entry_point;
the_ppc_context->gpr2 = gpr2;
#ifdef __ALTIVEC__
_CPU_Context_initialize_altivec( the_ppc_context );
#endif
if ( tls_area != NULL ) {
void *tls_block = _TLS_TCB_before_tls_block_initialize( tls_area );
the_ppc_context->gpr2 = (uint32_t) tls_block + 0x7000;
} else {
register uint32_t gpr2 __asm__("2");
the_ppc_context->gpr2 = gpr2;
}
}

View File

@@ -74,6 +74,7 @@ include_rtems_score_HEADERS += include/rtems/score/threadsync.h
include_rtems_score_HEADERS += include/rtems/score/timespec.h
include_rtems_score_HEADERS += include/rtems/score/timestamp.h
include_rtems_score_HEADERS += include/rtems/score/timestamp64.h
include_rtems_score_HEADERS += include/rtems/score/tls.h
include_rtems_score_HEADERS += include/rtems/score/tod.h
include_rtems_score_HEADERS += include/rtems/score/todimpl.h
include_rtems_score_HEADERS += include/rtems/score/userext.h

View File

@@ -15,6 +15,8 @@ include_rtems_score_HEADERS += rtems/score/cpusmplock.h
noinst_LIBRARIES = libscorecpu.a
libscorecpu_a_CPPFLAGS = $(AM_CPPFLAGS)
libscorecpu_a_SOURCES =
libscorecpu_a_SOURCES += __aeabi_read_tp.c
libscorecpu_a_SOURCES += __tls_get_addr.c
libscorecpu_a_SOURCES += cpu.c
libscorecpu_a_SOURCES += cpu_asm.S
libscorecpu_a_SOURCES += arm-context-validate.S

View File

@@ -0,0 +1,44 @@
/*
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/score/thread.h>
#include <rtems/score/percpu.h>
#ifndef RTEMS_SMP
void __attribute__((naked)) __aeabi_read_tp(void);
void __attribute__((naked)) __aeabi_read_tp(void)
{
__asm__ volatile (
"ldr r0, =_Per_CPU_Information\n"
"ldr r0, [r0, %[executingoff]]\n"
#if defined(__thumb__) && !defined(__thumb2__)
"add r0, %[tlsareaoff]\n"
"ldr r0, [r0]\n"
#else
"ldr r0, [r0, %[tlsareaoff]]\n"
#endif
"bx lr\n"
:
: [executingoff] "I" (offsetof(Per_CPU_Control, executing)),
[tlsareaoff] "I" (offsetof(Thread_Control, Start.tls_area))
);
}
#endif /* RTEMS_SMP */

View File

@@ -0,0 +1,35 @@
/*
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/score/thread.h>
#include <rtems/score/tls.h>
#include <assert.h>
void *__tls_get_addr(const TLS_Index *ti);
void *__tls_get_addr(const TLS_Index *ti)
{
const Thread_Control *executing = _Thread_Get_executing();
void *tls_block = (char *) executing->Start.tls_area
+ _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment );
assert(ti->module == 1);
return (char *) tls_block + ti->offset;
}

View File

@@ -26,6 +26,7 @@
#include <rtems/score/armv7m.h>
#include <rtems/score/thread.h>
#include <rtems/score/tls.h>
#ifdef ARM_MULTILIB_ARCH_V7M
@@ -35,7 +36,8 @@ void _CPU_Context_Initialize(
size_t stack_area_size,
uint32_t new_level,
void (*entry_point)( void ),
bool is_fp
bool is_fp,
void *tls_area
)
{
char *stack_area_end = (char *) stack_area_begin + stack_area_size;
@@ -44,6 +46,10 @@ void _CPU_Context_Initialize(
context->register_lr = entry_point;
context->register_sp = stack_area_end;
if ( tls_area != NULL ) {
_TLS_TCB_at_area_begin_initialize( tls_area );
}
}
#endif /* ARM_MULTILIB_ARCH_V7M */

View File

@@ -32,6 +32,7 @@
#include <rtems/score/isr.h>
#include <rtems/score/wkspace.h>
#include <rtems/score/thread.h>
#include <rtems/score/tls.h>
#include <rtems/score/cpu.h>
#ifdef ARM_MULTILIB_VFP_D32
@@ -41,6 +42,14 @@
);
#endif
#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER
RTEMS_STATIC_ASSERT(
offsetof( Context_Control, thread_id )
== ARM_CONTEXT_CONTROL_THREAD_ID_OFFSET,
ARM_CONTEXT_CONTROL_THREAD_ID_OFFSET
);
#endif
RTEMS_STATIC_ASSERT(
sizeof( CPU_Exception_frame ) == ARM_EXCEPTION_FRAME_SIZE,
ARM_EXCEPTION_FRAME_SIZE
@@ -71,13 +80,22 @@ void _CPU_Context_Initialize(
size_t stack_area_size,
uint32_t new_level,
void (*entry_point)( void ),
bool is_fp
bool is_fp,
void *tls_area
)
{
the_context->register_sp = (uint32_t) stack_area_begin + stack_area_size;
the_context->register_lr = (uint32_t) entry_point;
the_context->register_cpsr = ( ( new_level != 0 ) ? ARM_PSR_I : 0 )
| arm_cpu_mode;
#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER
the_context->thread_id = (uint32_t) tls_area;
#endif
if ( tls_area != NULL ) {
_TLS_TCB_at_area_begin_initialize( tls_area );
}
}
/* Preprocessor magic for stringification of x */

View File

@@ -62,12 +62,22 @@ DEFINE_FUNCTION_ARM(_CPU_Context_switch)
vstm r3, {d8-d15}
#endif
#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER
mrc p15, 0, r3, c13, c0, 3
str r3, [r0, #ARM_CONTEXT_CONTROL_THREAD_ID_OFFSET]
#endif
/* Start restoring context */
_restore:
#ifdef ARM_MULTILIB_HAS_LOAD_STORE_EXCLUSIVE
clrex
#endif
#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER
ldr r3, [r1, #ARM_CONTEXT_CONTROL_THREAD_ID_OFFSET]
mcr p15, 0, r3, c13, c0, 3
#endif
#ifdef ARM_MULTILIB_VFP_D32
add r3, r1, #ARM_CONTEXT_CONTROL_D8_OFFSET
vldm r3, {d8-d15}

View File

@@ -44,6 +44,11 @@ extern "C" {
#define ARM_MULTILIB_HAS_LOAD_STORE_EXCLUSIVE
#endif
#if defined(__ARM_ARCH_7A__) \
|| defined(__ARM_ARCH_7R__)
#define ARM_MULTILIB_HAS_THREAD_ID_REGISTER
#endif
#if defined(__ARM_NEON__)
#define ARM_MULTILIB_VFP_D32
#elif !defined(__SOFTFP__)

View File

@@ -212,6 +212,10 @@
/** @} */
#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER
#define ARM_CONTEXT_CONTROL_THREAD_ID_OFFSET 44
#endif
#ifdef ARM_MULTILIB_VFP_D32
#define ARM_CONTEXT_CONTROL_D8_OFFSET 48
#endif
@@ -267,6 +271,9 @@ typedef struct {
#else
void *register_sp;
#endif
#ifdef ARM_MULTILIB_HAS_THREAD_ID_REGISTER
uint32_t thread_id;
#endif
#ifdef ARM_MULTILIB_VFP_D32
uint64_t register_d8;
uint64_t register_d9;
@@ -400,7 +407,8 @@ void _CPU_Context_Initialize(
size_t stack_area_size,
uint32_t new_level,
void (*entry_point)( void ),
bool is_fp
bool is_fp,
void *tls_area
);
#define _CPU_Context_Get_SP( _context ) \

View File

@@ -963,7 +963,8 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
);
/*

View File

@@ -186,7 +186,8 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
)
{
uint32_t stack_high; /* highest "stack aligned" address */

View File

@@ -817,6 +817,7 @@ uint32_t _CPU_ISR_Get_level( void );
* point thread. This is typically only used on CPUs where the
* FPU may be easily disabled by software such as on the SPARC
* where the PSR contains an enable FPU bit.
* @param[in] tls_area is the thread-local storage (TLS) area
*
* Port Specific Information:
*
@@ -828,7 +829,8 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
);
/**

View File

@@ -756,7 +756,7 @@ uint32_t _CPU_ISR_Get_level( void );
#define CPU_CCR_INTERRUPTS_OFF 0x00
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
_isr, _entry_point, _is_fp ) \
_isr, _entry_point, _is_fp, _tls_area ) \
/* Locate Me */ \
do { \
uintptr_t _stack; \

View File

@@ -443,7 +443,7 @@ uint32_t _CPU_ISR_Get_level( void );
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
_isr, _entry_point, _is_fp ) \
_isr, _entry_point, _is_fp, _tls_area ) \
do { \
uint32_t _stack; \
\

View File

@@ -823,7 +823,7 @@ uint32_t _CPU_ISR_Get_level( void );
extern char _gp[];
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
_isr, _entry_point, _is_fp ) \
_isr, _entry_point, _is_fp, _tls_area ) \
do { \
uint32_t _stack = (uint32_t)(_stack_base) + (_size) - 4; \
(_the_context)->gp = (uint32_t)_gp; \

View File

@@ -50,7 +50,8 @@ void _CPU_Context_Initialize(
size_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
)
{
void *stackEnd = stack_base;

View File

@@ -809,6 +809,7 @@ uint32_t _CPU_ISR_Get_level( void );
* point thread. This is typically only used on CPUs where the
* FPU may be easily disabled by software such as on the SPARC
* where the PSR contains an enable FPU bit.
* @param[in] tls_area is the thread-local storage (TLS) area
*
* Port Specific Information:
*
@@ -820,7 +821,8 @@ void _CPU_Context_Initialize(
size_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
);
/**

View File

@@ -33,7 +33,8 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
)
{
void *stackEnd = stack_base;

View File

@@ -828,6 +828,7 @@ uint32_t _CPU_ISR_Get_level( void );
* point thread. This is typically only used on CPUs where the
* FPU may be easily disabled by software such as on the SPARC
* where the PSR contains an enable FPU bit.
* @param[in] tls_area is the thread-local storage (TLS) area
*
* Port Specific Information:
*
@@ -839,7 +840,8 @@ void _CPU_Context_Initialize(
size_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
);
/**

View File

@@ -20,6 +20,7 @@ include_rtems_score_HEADERS += rtems/score/cpuatomic.h
libscorecpu_a_SOURCES = cpu.c cpu_asm.S
libscorecpu_a_SOURCES += m68k-exception-frame-print.c
libscorecpu_a_SOURCES += __m68k_read_tp.c
include $(srcdir)/preinstall.am
include $(top_srcdir)/automake/local.am

View File

@@ -0,0 +1,36 @@
/*
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Obere Lagerstr. 30
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <rtems/score/thread.h>
#include <rtems/score/tls.h>
void __m68k_read_tp(void);
void __m68k_read_tp(void)
{
const Thread_Control *executing = _Thread_Get_executing();
void *tp = (char *) executing->Start.tls_area +
_TLS_Get_thread_control_block_area_size((uintptr_t) _TLS_Alignment)
+ 0x7000;
__asm__ volatile (
"move.l %0, %%a0"
:
: "d" (tp)
);
}

View File

@@ -19,6 +19,7 @@
#include <rtems/system.h>
#include <rtems/score/isr.h>
#include <rtems/score/tls.h>
#if defined( __mcoldfire__ ) && ( M68K_HAS_FPU == 1 )
uint32_t _CPU_cacr_shadow;
@@ -181,3 +182,29 @@ void _CPU_Context_restore_fp (Context_Control_fp **fp_context_ptr)
_fpCCR = *fp;
}
#endif
void _CPU_Context_Initialize(
Context_Control *the_context,
void *stack_area_begin,
size_t stack_area_size,
uint32_t new_level,
void (*entry_point)( void ),
bool is_fp,
void *tls_area
)
{
uint32_t stack;
the_context->sr = 0x3000 | (new_level << 8);
stack = (uint32_t)stack_area_begin + stack_area_size - 4;
the_context->a7_msp = (void *)stack;
*(void **)stack = (void *)entry_point;
#if (defined(__mcoldfire__) && ( M68K_HAS_FPU == 1 ))
the_context->fpu_dis = is_fp ? 0x00 : 0x10;
#endif
if ( tls_area != NULL ) {
_TLS_TCB_before_tls_block_initialize( tls_area );
}
}

View File

@@ -448,30 +448,15 @@ uint32_t _CPU_ISR_Get_level( void );
* + initialize an FP context area
*/
#if (defined(__mcoldfire__) && ( M68K_HAS_FPU == 1 ))
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
_isr, _entry_point, _is_fp ) \
do { \
uint32_t _stack; \
\
(_the_context)->sr = 0x3000 | ((_isr) << 8); \
_stack = (uint32_t)(_stack_base) + (_size) - 4; \
(_the_context)->a7_msp = (void *)_stack; \
*(void **)_stack = (void *)(_entry_point); \
(_the_context)->fpu_dis = (_is_fp == TRUE) ? 0x00 : 0x10; \
} while ( 0 )
#else
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
_isr, _entry_point, _is_fp ) \
do { \
uint32_t _stack; \
\
(_the_context)->sr = 0x3000 | ((_isr) << 8); \
_stack = (uint32_t)(_stack_base) + (_size) - 4; \
(_the_context)->a7_msp = (void *)_stack; \
*(void **)_stack = (void *)(_entry_point); \
} while ( 0 )
#endif
void _CPU_Context_Initialize(
Context_Control *the_context,
void *stack_area_begin,
size_t stack_area_size,
uint32_t new_level,
void (*entry_point)( void ),
bool is_fp,
void *tls_area
);
/* end of Context handler macros */

View File

@@ -173,7 +173,8 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
)
{
uintptr_t stack_tmp;

View File

@@ -858,7 +858,8 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
);

View File

@@ -651,7 +651,7 @@ uint32_t _CPU_ISR_Get_level( void );
#define CPU_CCR_INTERRUPTS_OFF 0x00
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
_isr, _entry_point, _is_fp ) \
_isr, _entry_point, _is_fp, _tls_area ) \
/* Locate Me */ \
do { \
uintptr_t _stack; \

View File

@@ -27,7 +27,8 @@ void _CPU_Context_Initialize(
size_t stack_area_size,
uint32_t new_level,
void (*entry_point)( void ),
bool is_fp
bool is_fp,
void *tls_area
)
{
const Nios2_MPU_Configuration *mpu_config = _Nios2_MPU_Get_configuration();

View File

@@ -295,6 +295,7 @@ uint32_t _CPU_ISR_Get_level( void );
* @param[in] new_level is the interrupt level for the task
* @param[in] entry_point is the task's entry point
* @param[in] is_fp is set to @c true if the task is a floating point task
* @param[in] tls_area is the thread-local storage (TLS) area
*/
void _CPU_Context_Initialize(
Context_Control *context,
@@ -302,7 +303,8 @@ void _CPU_Context_Initialize(
size_t stack_area_size,
uint32_t new_level,
void (*entry_point)( void ),
bool is_fp
bool is_fp,
void *tls_area
);
#define _CPU_Context_Restart_self( _the_context ) \

View File

@@ -932,13 +932,14 @@ uint32_t _CPU_ISR_Get_level( void );
* point thread. This is typically only used on CPUs where the
* FPU may be easily disabled by software such as on the SPARC
* where the PSR contains an enable FPU bit.
* @param[in] _tls_area The thread-local storage (TLS) area.
*
* Port Specific Information:
*
* XXX document implementation including references if appropriate
*/
#define _CPU_Context_Initialize( _the_context, _stack_base, _size, \
_isr, _entry_point, _is_fp ) \
_isr, _entry_point, _is_fp, _tls_area ) \
{ \
}

View File

@@ -797,7 +797,8 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
);
/*

View File

@@ -211,7 +211,8 @@ void _CPU_Context_Initialize(
uint32_t _size,
uint32_t _isr,
void (*_entry_point)(void),
int _is_fp )
int _is_fp,
void *_tls_base)
{
_the_context->r15 = (uint32_t *) ((uint32_t) (_stack_base) + (_size) );
#if defined(__sh1__) || defined(__sh2__) || defined(__SH2E__)

View File

@@ -603,7 +603,8 @@ SCORE_EXTERN void _CPU_Context_Initialize(
uint32_t _size,
uint32_t _isr,
void (*_entry_point)(void),
int _is_fp );
int _is_fp,
void *_tls_area );
/*
* This routine is responsible for somehow restarting the currently

View File

@@ -20,6 +20,7 @@
#include <rtems/system.h>
#include <rtems/score/isr.h>
#include <rtems/score/percpu.h>
#include <rtems/score/tls.h>
#include <rtems/rtems/cache.h>
RTEMS_STATIC_ASSERT(
@@ -232,7 +233,8 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
)
{
uint32_t stack_high; /* highest "stack aligned" address */
@@ -285,4 +287,10 @@ void _CPU_Context_Initialize(
* thread can have an _ISR_Dispatch stack frame on its stack.
*/
the_context->isr_dispatch_disable = 0;
if ( tls_area != NULL ) {
void *tcb = _TLS_TCB_after_tls_block_initialize( tls_area );
the_context->g7 = (uintptr_t) tcb;
}
}

View File

@@ -1019,6 +1019,7 @@ uint32_t _CPU_ISR_Get_level( void );
* @param[in] new_level is the interrupt level for the task
* @param[in] entry_point is the task's entry point
* @param[in] is_fp is set to TRUE if the task is a floating point task
* @param[in] tls_area is the thread-local storage (TLS) area
*
* NOTE: Implemented as a subroutine for the SPARC port.
*/
@@ -1028,7 +1029,8 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
);
/**

View File

@@ -20,6 +20,7 @@
#include <rtems/system.h>
#include <rtems/asm.h>
#include <rtems/score/isr.h>
#include <rtems/score/tls.h>
#include <rtems/rtems/cache.h>
/*
@@ -65,7 +66,8 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
)
{
uint64_t stack_high; /* highest "stack aligned" address */
@@ -99,4 +101,10 @@ void _CPU_Context_Initialize(
* thread can have an _ISR_Dispatch stack frame on its stack.
*/
the_context->isr_dispatch_disable = 0;
if ( tls_area != NULL ) {
void *tcb = _TLS_TCB_after_tls_block_initialize( tls_area );
the_context->g7 = (uintptr_t) tcb;
}
}

View File

@@ -838,7 +838,8 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
);
/*

View File

@@ -61,7 +61,8 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
)
{
uint32_t stack_high; /* highest "stack aligned" address */

View File

@@ -790,6 +790,7 @@ uint32_t _CPU_ISR_Get_level( void );
* point thread. This is typically only used on CPUs where the
* FPU may be easily disabled by software such as on the SPARC
* where the PSR contains an enable FPU bit.
* @param[in] tls_area is the thread-local storage (TLS) area
*
* Port Specific Information:
*
@@ -801,7 +802,8 @@ void _CPU_Context_Initialize(
uint32_t size,
uint32_t new_level,
void *entry_point,
bool is_fp
bool is_fp,
void *tls_area
);
/**

View File

@@ -60,9 +60,12 @@ extern "C" {
* @param[in] _entry is this thread's entry point
* @param[in] _is_fp is set to true if this thread has floating point
* enabled
* @param[in] _tls_area The thread-local storage (TLS) area begin.
*/
#define _Context_Initialize(_the_context, _stack, _size, _isr, _entry, _is_fp) \
_CPU_Context_Initialize( _the_context, _stack, _size, _isr, _entry, _is_fp )
#define _Context_Initialize( _the_context, _stack, _size, _isr, _entry, \
_is_fp, _tls_area ) \
_CPU_Context_Initialize( _the_context, _stack, _size, _isr, _entry, \
_is_fp, _tls_area )
/**
* This macro is invoked from _Thread_Handler to do whatever CPU

View File

@@ -229,6 +229,8 @@ typedef struct {
#endif
/** This field is the initial stack area address. */
void *stack;
/** The thread-local storage (TLS) area */
void *tls_area;
} Thread_Start_information;
/**

View File

@@ -0,0 +1,187 @@
/**
* @file
*
* @ingroup ScoreTLS
*
* @brief Thread-Local Storage (TLS)
*/
/*
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#ifndef _RTEMS_SCORE_TLS_H
#define _RTEMS_SCORE_TLS_H
#include <rtems/score/cpu.h>
#include <string.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/**
* @defgroup ScoreTLS Thread-Local Storage (TLS)
*
* @ingroup Score
*
* @brief Thread-local storage (TLS) support.
*
* Variants I and II are according to Ulrich Drepper, "ELF Handling For
* Thread-Local Storage".
*
* @{
*/
extern char _TLS_Data_begin[];
extern char _TLS_Data_end[];
extern char _TLS_Data_size[];
extern char _TLS_BSS_begin[];
extern char _TLS_BSS_end[];
extern char _TLS_BSS_size[];
extern char _TLS_Size[];
extern char _TLS_Alignment[];
typedef struct {
/*
* FIXME: Not sure if the generation number type is correct for all
* architectures.
*/
uint32_t generation_number;
void *tls_blocks[1];
} TLS_Dynamic_thread_vector;
typedef struct {
TLS_Dynamic_thread_vector *dtv;
uintptr_t reserved;
} TLS_Thread_control_block;
typedef struct {
uintptr_t module;
uintptr_t offset;
} TLS_Index;
static inline uintptr_t _TLS_Heap_align_up( uintptr_t val )
{
uintptr_t msk = CPU_HEAP_ALIGNMENT - 1;
return (val + msk) & ~msk;
}
static inline uintptr_t _TLS_Get_thread_control_block_area_size(
uintptr_t alignment
)
{
return alignment <= sizeof(TLS_Thread_control_block) ?
sizeof(TLS_Thread_control_block) : alignment;
}
static inline uintptr_t _TLS_Get_allocation_size(
uintptr_t size,
uintptr_t alignment
)
{
uintptr_t aligned_size = _TLS_Heap_align_up( size );
return _TLS_Get_thread_control_block_area_size( alignment )
+ aligned_size + sizeof(TLS_Dynamic_thread_vector);
}
static inline void *_TLS_Copy_and_clear( void *tls_area )
{
tls_area = memcpy( tls_area, _TLS_Data_begin, (size_t) _TLS_Data_size );
memset(
(char *) tls_area + (size_t) _TLS_BSS_begin - (size_t) _TLS_Data_begin,
0,
(size_t) _TLS_BSS_size
);
return tls_area;
}
static inline void *_TLS_Initialize(
void *tls_block,
TLS_Thread_control_block *tcb,
TLS_Dynamic_thread_vector *dtv
)
{
tcb->dtv = dtv;
dtv->generation_number = 1;
dtv->tls_blocks[0] = tls_block;
return _TLS_Copy_and_clear( tls_block );
}
/* Use Variant I, TLS offsets emitted by linker takes the TCB into account */
static inline void *_TLS_TCB_at_area_begin_initialize( void *tls_area )
{
void *tls_block = (char *) tls_area
+ _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment );
TLS_Thread_control_block *tcb = tls_area;
uintptr_t aligned_size = _TLS_Heap_align_up( (uintptr_t) _TLS_Size );
TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
((char *) tls_block + aligned_size);
return _TLS_Initialize( tls_block, tcb, dtv );
}
/* Use Variant I, TLS offsets emitted by linker neglects the TCB */
static inline void *_TLS_TCB_before_tls_block_initialize( void *tls_area )
{
void *tls_block = (char *) tls_area
+ _TLS_Get_thread_control_block_area_size( (uintptr_t) _TLS_Alignment );
TLS_Thread_control_block *tcb = (TLS_Thread_control_block *)
((char *) tls_block - sizeof(*tcb));
uintptr_t aligned_size = _TLS_Heap_align_up( (uintptr_t) _TLS_Size );
TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
((char *) tls_block + aligned_size);
return _TLS_Initialize( tls_block, tcb, dtv );
}
/* Use Variant II */
static inline void *_TLS_TCB_after_tls_block_initialize( void *tls_area )
{
uintptr_t size = (uintptr_t) _TLS_Size;
uintptr_t tls_align = (uintptr_t) _TLS_Alignment;
uintptr_t tls_mask = tls_align - 1;
uintptr_t heap_align = _TLS_Heap_align_up( tls_align );
uintptr_t heap_mask = heap_align - 1;
TLS_Thread_control_block *tcb = (TLS_Thread_control_block *)
((char *) tls_area + ((size + heap_mask) & ~heap_mask));
void *tls_block = (char *) tcb - ((size + tls_mask) & ~tls_mask);
TLS_Dynamic_thread_vector *dtv = (TLS_Dynamic_thread_vector *)
((char *) tcb + sizeof(*tcb));
_TLS_Initialize( tls_block, tcb, dtv );
return tcb;
}
/** @} */
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* _RTEMS_SCORE_TLS_H */

View File

@@ -279,6 +279,10 @@ $(PROJECT_INCLUDE)/rtems/score/timestamp64.h: include/rtems/score/timestamp64.h
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/timestamp64.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/timestamp64.h
$(PROJECT_INCLUDE)/rtems/score/tls.h: include/rtems/score/tls.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/tls.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/tls.h
$(PROJECT_INCLUDE)/rtems/score/tod.h: include/rtems/score/tod.h $(PROJECT_INCLUDE)/rtems/score/$(dirstamp)
$(INSTALL_DATA) $< $(PROJECT_INCLUDE)/rtems/score/tod.h
PREINSTALL_FILES += $(PROJECT_INCLUDE)/rtems/score/tod.h

View File

@@ -96,4 +96,6 @@ void _Thread_Close(
_Workspace_Free( the_thread->extensions );
the_thread->extensions = NULL;
_Workspace_Free( the_thread->Start.tls_area );
}

View File

@@ -20,6 +20,7 @@
#include <rtems/score/threadimpl.h>
#include <rtems/score/schedulerimpl.h>
#include <rtems/score/stackimpl.h>
#include <rtems/score/tls.h>
#include <rtems/score/userextimpl.h>
#include <rtems/score/watchdogimpl.h>
#include <rtems/score/wkspace.h>
@@ -48,6 +49,7 @@ bool _Thread_Initialize(
void *extensions_area;
bool extension_status;
int i;
uintptr_t tls_size = (uintptr_t) _TLS_Size;
#if defined( RTEMS_SMP )
if ( rtems_configuration_is_smp_enabled() && !is_preemptible ) {
@@ -70,6 +72,7 @@ bool _Thread_Initialize(
extensions_area = NULL;
the_thread->libc_reent = NULL;
the_thread->Start.tls_area = NULL;
#if ( CPU_HARDWARE_FP == TRUE ) || ( CPU_SOFTWARE_FP == TRUE )
fp_area = NULL;
@@ -105,6 +108,19 @@ bool _Thread_Initialize(
actual_stack_size
);
/* Thread-local storage (TLS) area allocation */
if ( tls_size > 0 ) {
uintptr_t tls_align = _TLS_Heap_align_up( (uintptr_t) _TLS_Alignment );
uintptr_t tls_alloc = _TLS_Get_allocation_size( tls_size, tls_align );
the_thread->Start.tls_area =
_Workspace_Allocate_aligned( tls_alloc, tls_align );
if ( the_thread->Start.tls_area == NULL ) {
goto failed;
}
}
/*
* Allocate the floating point area for this thread
*/
@@ -223,6 +239,8 @@ bool _Thread_Initialize(
return true;
failed:
_Workspace_Free( the_thread->Start.tls_area );
_Workspace_Free( the_thread->libc_reent );
for ( i=0 ; i <= THREAD_API_LAST ; i++ )

View File

@@ -58,7 +58,8 @@ void _Thread_Load_environment(
the_thread->Start.Initial_stack.size,
isr_level,
_Thread_Handler,
is_fp
is_fp,
the_thread->Start.tls_area
);
}

View File

@@ -21,6 +21,8 @@
#include <rtems/score/wkspace.h>
#include <rtems/score/heapimpl.h>
#include <rtems/score/interr.h>
#include <rtems/score/threadimpl.h>
#include <rtems/score/tls.h>
#include <rtems/config.h>
#include <string.h> /* for memset */
@@ -30,6 +32,25 @@
#include <rtems/bspIo.h>
#endif
static uint32_t _Get_maximum_thread_count(void)
{
uint32_t thread_count = 0;
thread_count += _Thread_Get_maximum_internal_threads();
thread_count += rtems_resource_maximum_per_allocation(
Configuration_RTEMS_API.maximum_tasks
);
#if defined(RTEMS_POSIX_API)
thread_count += rtems_resource_maximum_per_allocation(
Configuration_POSIX_API.maximum_threads
);
#endif
return thread_count;
}
void _Workspace_Handler_initialization(
Heap_Area *areas,
size_t area_count,
@@ -42,8 +63,17 @@ void _Workspace_Handler_initialization(
bool unified = rtems_configuration_get_unified_work_area();
uintptr_t page_size = CPU_HEAP_ALIGNMENT;
uintptr_t overhead = _Heap_Area_overhead( page_size );
uintptr_t tls_size = (uintptr_t) _TLS_Size;
size_t i;
if ( tls_size > 0 ) {
uintptr_t tls_alignment = (uintptr_t) _TLS_Alignment;
uintptr_t tls_alloc = _TLS_Get_allocation_size( tls_size, tls_alignment );
remaining += _Get_maximum_thread_count()
* _Heap_Size_with_overhead( page_size, tls_alloc, tls_alignment );
}
for (i = 0; i < area_count; ++i) {
Heap_Area *area = &areas [i];

View File

@@ -10,8 +10,25 @@ include $(top_srcdir)/main.am
REPLACE2 = $(PERL) $(top_srcdir)/tools/word-replace2
GENERATED_FILES = general.texi arm.texi avr.texi bfin.texi i386.texi lm32.texi \
m68k.texi mips.texi powerpc.texi sh.texi sparc.texi sparc64.texi v850.texi
GENERATED_FILES =
GENERATED_FILES += general.texi
GENERATED_FILES += arm.texi
GENERATED_FILES += avr.texi
GENERATED_FILES += bfin.texi
GENERATED_FILES += h8300.texi
GENERATED_FILES += i386.texi
GENERATED_FILES += lm32.texi
GENERATED_FILES += m32c.texi
GENERATED_FILES += m32r.texi
GENERATED_FILES += m68k.texi
GENERATED_FILES += microblaze.texi
GENERATED_FILES += mips.texi
GENERATED_FILES += powerpc.texi
GENERATED_FILES += nios2.texi
GENERATED_FILES += sh.texi
GENERATED_FILES += sparc.texi
GENERATED_FILES += sparc64.texi
GENERATED_FILES += v850.texi
COMMON_FILES += $(top_srcdir)/common/cpright.texi
@@ -44,11 +61,26 @@ bfin.texi: bfin.t
-u "Top" \
-n "" < $< > $@
h8300.texi: h8300.t
$(BMENU2) -p "" \
-u "Top" \
-n "" < $< > $@
i386.texi: i386.t
$(BMENU2) -p "" \
-u "Top" \
-n "" < $< > $@
m32c.texi: m32c.t
$(BMENU2) -p "" \
-u "Top" \
-n "" < $< > $@
m32r.texi: m32r.t
$(BMENU2) -p "" \
-u "Top" \
-n "" < $< > $@
lm32.texi: lm32.t
$(BMENU2) -p "" \
-u "Top" \
@@ -59,6 +91,11 @@ m68k.texi: m68k.t
-u "Top" \
-n "" < $< > $@
microblaze.texi: microblaze.t
$(BMENU2) -p "" \
-u "Top" \
-n "" < $< > $@
mips.texi: mips.t
$(BMENU2) -p "" \
-u "Top" \
@@ -69,6 +106,11 @@ powerpc.texi: powerpc.t
-u "Top" \
-n "" < $< > $@
nios2.texi: nios2.t
$(BMENU2) -p "" \
-u "Top" \
-n "" < $< > $@
sh.texi: sh.t
$(BMENU2) -p "" \
-u "Top" \

View File

@@ -97,3 +97,7 @@ following actions:
@item places the error code in @code{r0}, and
@item executes an infinite loop to simulate a halt processor instruction.
@end itemize
@section Thread-Local Storage
Thread-local storage is supported.

View File

@@ -117,6 +117,10 @@ actions:
simulate a halt processor instruction.
@end itemize
@section Thread-Local Storage
Thread-local storage is not supported due to a broken tool chain.
@section Board Support Packages

View File

@@ -130,6 +130,10 @@ actions:
simulate a halt processor instruction.
@end itemize
@section Thread-Local Storage
Thread-local storage is not implemented.
@section Board Support Packages

View File

@@ -65,10 +65,15 @@
* ARM Specific Information::
* Atmel AVR Specific Information::
* Blackfin Specific Information::
* Renesas H8/300 Specific Information::
* Intel/AMD x86 Specific Information::
* Lattice Mico32 Specific Information::
* Renesas M32C Specific Information::
* Renesas M32R Specific Information::
* M68xxx and Coldfire Specific Information::
* Xilinx MicroBlaze Specific Information::
* MIPS Specific Information::
* Altera Nios II Specific Information::
* PowerPC Specific Information::
* SuperH Specific Information::
* SPARC Specific Information::
@@ -83,10 +88,15 @@
@include arm.texi
@include avr.texi
@include bfin.texi
@include h8300.texi
@include i386.texi
@include lm32.texi
@include m32c.texi
@include m32r.texi
@include m68k.texi
@include microblaze.texi
@include mips.texi
@include nios2.texi
@include powerpc.texi
@include sh.texi
@include sparc.texi

View File

@@ -314,6 +314,33 @@ interrupts and halts the processor.
In each of the architecture specific chapters, this describes the precise
operations of the default CPU specific fatal error handler.
@section Thread-Local Storage
In order to support thread-local storage (TLS) the CPU port must implement the
facilities mandated by the application binary interface (ABI) of the CPU
architecture. The CPU port must initialize the TLS area in the
@code{_CPU_Context_Initialize} function.
The board support package (BSP) must provide the following sections and symbols
in its linker command file:
@example
.tdata : @{
_TLS_Data_begin = .;
*(.tdata .tdata.* .gnu.linkonce.td.*)
_TLS_Data_end = .;
@}
.tbss : @{
_TLS_BSS_begin = .;
*(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon)
_TLS_BSS_end = .;
@}
_TLS_Data_size = _TLS_Data_end - _TLS_Data_begin;
_TLS_BSS_size = _TLS_BSS_end - _TLS_BSS_begin;
_TLS_Size = _TLS_BSS_end - _TLS_Data_begin;
_TLS_Alignment = ALIGNOF (.tdata);
@end example
@c
@c
@c

View File

@@ -0,0 +1,7 @@
@c Copyright (c) 2014 embedded brains GmbH. All rights reserved.
@chapter Renesas H8/300 Specific Information
@section Thread-Local Storage
Thread-local storage is not implemented.

View File

@@ -266,6 +266,10 @@ The default fatal error handler for this architecture disables processor
interrupts, places the error code in EAX, and executes a HLT instruction
to halt the processor.
@section Thread-Local Storage
Thread-local storage is not implemented.
@c
@c
@c

View File

@@ -163,6 +163,10 @@ interrupts and halts the processor.
In each of the architecture specific chapters, this describes the precise
operations of the default CPU specific fatal error handler.
@section Thread-Local Storage
Thread-local storage is not implemented.
@c
@c
@c

View File

@@ -0,0 +1,7 @@
@c Copyright (c) 2014 embedded brains GmbH. All rights reserved.
@chapter Renesas M32C Specific Information
@section Thread-Local Storage
Thread-local storage is not implemented.

View File

@@ -0,0 +1,7 @@
@c Copyright (c) 2014 embedded brains GmbH. All rights reserved.
@chapter Renesas M32R Specific Information
@section Thread-Local Storage
Thread-local storage is not implemented.

View File

@@ -357,6 +357,10 @@ The default fatal error handler for this architecture disables processor
interrupts to level 7, places the error code in D0, and executes a
@code{stop} instruction to simulate a halt processor instruction.
@section Thread-Local Storage
Thread-local storage is supported.
@c
@c
@c

View File

@@ -0,0 +1,7 @@
@c Copyright (c) 2014 embedded brains GmbH. All rights reserved.
@chapter Xilinx MicroBlaze Specific Information
@section Thread-Local Storage
Thread-local storage is not implemented.

View File

@@ -122,6 +122,10 @@ The default fatal error handler for this target architecture disables
processor interrupts, places the error code in @b{XXX}, and executes a
@code{XXX} instruction to simulate a halt processor instruction.
@section Thread-Local Storage
Thread-local storage is not implemented.
@c
@c
@c

View File

@@ -0,0 +1,7 @@
@c Copyright (c) 2014 embedded brains GmbH. All rights reserved.
@chapter Altera Nios II Specific Information
@section Thread-Local Storage
Thread-local storage is not implemented.

View File

@@ -623,6 +623,10 @@ If the Program Exception returns, then the following actions are performed:
@end itemize
@section Thread-Local Storage
Thread-local storage is supported.
@c
@c
@c

View File

@@ -139,6 +139,10 @@ The default fatal error handler for this architecture disables processor
interrupts, places the error code in @b{XXX}, and executes a @code{XXX}
instruction to simulate a halt processor instruction.
@section Thread-Local Storage
Thread-local storage is not implemented.
@c
@c
@c

View File

@@ -917,6 +917,9 @@ default fatal error handler disables processor interrupts to
level 15, places the error code in g1, and goes into an infinite
loop to simulate a halt processor instruction.
@section Thread-Local Storage
Thread-local storage is supported.
@c
@c COPYRIGHT (c) 1988-2002.

View File

@@ -773,6 +773,9 @@ default fatal error handler disables processor interrupts to
level 15, places the error code in g1, and goes into an infinite
loop to simulate a halt processor instruction.
@section Thread-Local Storage
Thread-local storage is supported.
@c
@c COPYRIGHT (c) 1988-2002.

View File

@@ -102,3 +102,7 @@ following actions:
@item places the error code in @code{r10}, and
@item executes a halt processor instruction.
@end itemize
@section Thread-Local Storage
Thread-local storage is not implemented.

View File

@@ -30,6 +30,10 @@ SUBDIRS = \
spsimplesched03 spnsext01 spedfsched01 spedfsched02 spedfsched03 \
spcbssched01 spcbssched02 spcbssched03 spqreslib sptimespec01 \
spregion_err01 sppartition_err01
if HAS_CPLUSPLUS
SUBDIRS += sptls02
endif
SUBDIRS += sptls01
SUBDIRS += spintrcritical20
SUBDIRS += spintrcritical19
SUBDIRS += spcontext01

View File

@@ -11,16 +11,21 @@ RTEMS_CANONICAL_TARGET_CPU
AM_INIT_AUTOMAKE([no-define foreign 1.12.2])
AM_MAINTAINER_MODE
RTEMS_ENABLE_CXX
RTEMS_ENV_RTEMSBSP
RTEMS_CHECK_RTEMS_TEST_NO_PAUSE
RTEMS_PROJECT_ROOT
RTEMS_PROG_CC_FOR_TARGET
RTEMS_PROG_CXX_FOR_TARGET
RTEMS_CANONICALIZE_TOOLS
RTEMS_CHECK_CUSTOM_BSP(RTEMS_BSP)
RTEMS_CHECK_CXX(RTEMS_BSP)
AM_CONDITIONAL([HAS_CPLUSPLUS],[test $HAS_CPLUSPLUS = "yes"])
# FIXME: We should get rid of this. It's a cludge.
AC_CHECK_SIZEOF([time_t])
@@ -31,6 +36,8 @@ AM_CONDITIONAL(HAS_CPUSET,test x"${ac_cv_header_sys_cpuset_h}" = x"yes")
# Explicitly list all Makefiles here
AC_CONFIG_FILES([Makefile
sptls02/Makefile
sptls01/Makefile
spintrcritical20/Makefile
spintrcritical19/Makefile
spcontext01/Makefile

View File

@@ -0,0 +1,19 @@
rtems_tests_PROGRAMS = sptls01
sptls01_SOURCES = init.c
dist_rtems_tests_DATA = sptls01.scn sptls01.doc
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(top_srcdir)/../automake/compile.am
include $(top_srcdir)/../automake/leaf.am
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
LINK_OBJS = $(sptls01_OBJECTS)
LINK_LIBS = $(sptls01_LDLIBS)
sptls01$(EXEEXT): $(sptls01_OBJECTS) $(sptls01_DEPENDENCIES)
@rm -f sptls01$(EXEEXT)
$(make-exe)
include $(top_srcdir)/../automake/local.am

View File

@@ -0,0 +1,98 @@
/*
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include "tmacros.h"
static rtems_id master_task;
static __thread volatile char tls_item = 123;
static void check_tls_item(int expected)
{
printf("TLS item = %i\n", tls_item);
rtems_test_assert(tls_item == expected);
}
static void task(rtems_task_argument arg)
{
rtems_status_code sc;
check_tls_item(123);
sc = rtems_event_transient_send(master_task);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_suspend(RTEMS_SELF);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
}
static void test(void)
{
rtems_id id;
rtems_status_code sc;
master_task = rtems_task_self();
check_tls_item(123);
tls_item = 5;
sc = rtems_task_create(
rtems_build_name('T', 'A', 'S', 'K'),
RTEMS_MINIMUM_PRIORITY,
RTEMS_MINIMUM_STACK_SIZE,
RTEMS_DEFAULT_MODES,
RTEMS_DEFAULT_ATTRIBUTES,
&id
);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_start(id, task, 0);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_delete(id);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
check_tls_item(5);
}
static void Init(rtems_task_argument arg)
{
puts("\n\n*** TEST SPTLS 1 ***");
test();
puts("*** END OF TEST SPTLS 1 ***");
rtems_test_exit(0);
}
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_MAXIMUM_TASKS 2
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_INIT
#include <rtems/confdefs.h>

View File

@@ -0,0 +1,11 @@
This file describes the directives and concepts tested by this test set.
test set name: sptls01
directives:
- None
concepts:
- Ensure that thread-local storage (TLS) works minimum alignment requirements.

View File

@@ -0,0 +1,5 @@
*** TEST SPTLS 1 ***
TLS item = 123
TLS item = 123
TLS item = 5
*** END OF TEST SPTLS 1 ***

View File

@@ -0,0 +1,20 @@
rtems_tests_PROGRAMS = sptls02
sptls02_SOURCES = init.cc
dist_rtems_tests_DATA = sptls02.scn sptls02.doc
include $(RTEMS_ROOT)/make/custom/@RTEMS_BSP@.cfg
include $(top_srcdir)/../automake/compile.am
include $(top_srcdir)/../automake/leaf.am
AM_CPPFLAGS += -I$(top_srcdir)/../support/include
AM_CXXFLAGS += -std=c++11 -ftls-model=local-exec
LINK_OBJS = $(sptls02_OBJECTS)
LINK_LIBS = $(sptls02_LDLIBS)
sptls02$(EXEEXT): $(sptls02_OBJECTS) $(sptls02_DEPENDENCIES)
@rm -f sptls02$(EXEEXT)
$(make-cxx-exe)
include $(top_srcdir)/../automake/local.am

View File

@@ -0,0 +1,256 @@
/*
* Copyright (c) 2014 embedded brains GmbH. All rights reserved.
*
* embedded brains GmbH
* Dornierstr. 4
* 82178 Puchheim
* Germany
* <rtems@embedded-brains.de>
*
* The license and distribution terms for this file may be
* found in the file LICENSE in this distribution or at
* http://www.rtems.com/license/LICENSE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <rtems.h>
#include <rtems/libcsupport.h>
#include "tmacros.h"
static thread_local long i123 = 123;
alignas(256) static thread_local long a256 = 256;
static thread_local long i0;
alignas(512) static thread_local long a512;
static void clobber()
{
i123 = 0xdead0001;
a256 = 0xdead0002;
i0 = 0xdead0003;
a512 = 0xdead0004;
}
static long f456(bool clobber)
{
static thread_local long fi456 = 456;
if (clobber) {
fi456 = 0xdead0003;
}
return fi456;
}
static long f0(bool clobber)
{
static thread_local long fi0;
if (clobber) {
fi0 = 0xdead0004;
}
return fi0;
}
class C {
public:
static long c789()
{
return ci789;
}
static long c0()
{
return ci0;
}
static void clobber()
{
ci789 = 0xdead0005;
ci0 = 0xdead0006;
}
private:
static thread_local long ci789;
static thread_local long ci0;
};
thread_local long C::ci789 = 789;
thread_local long C::ci0;
class A {
public:
A(long i)
: ii(i), c(gc)
{
++gc;
}
~A()
{
--gc;
}
long i() const
{
return ii;
}
void clobber()
{
ii = ~ii;
c = ~c;
}
long counter() const
{
return c;
}
static long globalCounter()
{
return gc;
}
private:
static long gc;
long ii;
long c;
};
long A::gc;
static volatile long mc;
static thread_local A a1(mc + 1);
static thread_local A a2(mc + 2);
static thread_local A a3(mc + 3);
static void checkTLSValues()
{
rtems_test_assert(i123 == 123);
rtems_test_assert(a256 == 256);
rtems_test_assert((a256 & 255) == 0);
rtems_test_assert(i0 == 0);
rtems_test_assert(a512 == 0);
rtems_test_assert((a512 & 511) == 0);
rtems_test_assert(f456(false) == 456);
rtems_test_assert(f0(false) == 0);
rtems_test_assert(C::c789() == 789);
rtems_test_assert(C::c0() == 0);
rtems_test_assert(a1.i() == 1);
rtems_test_assert(a2.i() == 2);
rtems_test_assert(a3.i() == 3);
}
static rtems_id masterTask;
static void task(rtems_task_argument arg)
{
checkTLSValues();
const long gc = static_cast<long>(arg);
rtems_test_assert(A::globalCounter() == gc + 3);
rtems_test_assert(a1.counter() == gc + 0);
rtems_test_assert(a2.counter() == gc + 1);
rtems_test_assert(a3.counter() == gc + 2);
clobber();
f456(true);
f0(true);
C::clobber();
a1.clobber();
a2.clobber();
a3.clobber();
rtems_status_code sc = rtems_event_transient_send(masterTask);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_suspend(RTEMS_SELF);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
}
static void testTask()
{
checkTLSValues();
rtems_id id;
rtems_status_code sc = rtems_task_create(
rtems_build_name('T', 'A', 'S', 'K'),
RTEMS_MINIMUM_PRIORITY,
RTEMS_MINIMUM_STACK_SIZE,
RTEMS_DEFAULT_MODES,
RTEMS_DEFAULT_ATTRIBUTES,
&id
);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
const long gc = A::globalCounter();
sc = rtems_task_start(id, task, gc);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_event_transient_receive(RTEMS_WAIT, RTEMS_NO_TIMEOUT);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
sc = rtems_task_delete(id);
rtems_test_assert(sc == RTEMS_SUCCESSFUL);
rtems_test_assert(A::globalCounter() == gc);
checkTLSValues();
}
extern "C" void Init(rtems_task_argument arg)
{
puts("\n\n*** TEST SPTLS 2 ***");
printf("A::globalCounter() = %li\n", A::globalCounter());
checkTLSValues();
printf("A::globalCounter() = %li\n", A::globalCounter());
masterTask = rtems_task_self();
testTask();
rtems_resource_snapshot snapshot;
rtems_resource_snapshot_take(&snapshot);
testTask();
rtems_test_assert(rtems_resource_snapshot_check(&snapshot));
puts("*** END OF TEST SPTLS 2 ***");
exit(0);
}
#define CONFIGURE_APPLICATION_NEEDS_CLOCK_DRIVER
#define CONFIGURE_APPLICATION_NEEDS_CONSOLE_DRIVER
#define CONFIGURE_MAXIMUM_TASKS 2
#define CONFIGURE_MAXIMUM_SEMAPHORES 3
#define CONFIGURE_RTEMS_INIT_TASKS_TABLE
#define CONFIGURE_INIT
#include <rtems/confdefs.h>

View File

@@ -0,0 +1,12 @@
This file describes the directives and concepts tested by this test set.
test set name: sptls02
directives:
- None
concepts:
- Ensure thread-local storage (TLS) alignment requirements.
- Ensure thread-local storage (TLS) object construction and destruction.

View File

@@ -0,0 +1,4 @@
*** TEST SPTLS 2 ***
A::globalCounter() = 0
A::globalCounter() = 3
*** END OF TEST SPTLS 2 ***