forked from Imagelibrary/rtems
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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
44
cpukit/score/cpu/arm/__aeabi_read_tp.c
Normal file
44
cpukit/score/cpu/arm/__aeabi_read_tp.c
Normal 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 */
|
||||
35
cpukit/score/cpu/arm/__tls_get_addr.c
Normal file
35
cpukit/score/cpu/arm/__tls_get_addr.c
Normal 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;
|
||||
}
|
||||
@@ -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 */
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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__)
|
||||
|
||||
@@ -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 ) \
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
/*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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; \
|
||||
|
||||
@@ -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; \
|
||||
\
|
||||
|
||||
@@ -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; \
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
36
cpukit/score/cpu/m68k/__m68k_read_tp.c
Normal file
36
cpukit/score/cpu/m68k/__m68k_read_tp.c
Normal 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)
|
||||
);
|
||||
}
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -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; \
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 ) \
|
||||
|
||||
@@ -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 ) \
|
||||
{ \
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
/*
|
||||
|
||||
@@ -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__)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
/*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
/**
|
||||
|
||||
187
cpukit/score/include/rtems/score/tls.h
Normal file
187
cpukit/score/include/rtems/score/tls.h
Normal 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 */
|
||||
@@ -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
|
||||
|
||||
@@ -96,4 +96,6 @@ void _Thread_Close(
|
||||
|
||||
_Workspace_Free( the_thread->extensions );
|
||||
the_thread->extensions = NULL;
|
||||
|
||||
_Workspace_Free( the_thread->Start.tls_area );
|
||||
}
|
||||
|
||||
@@ -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++ )
|
||||
|
||||
@@ -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
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
|
||||
@@ -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" \
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
7
doc/cpu_supplement/h8300.t
Normal file
7
doc/cpu_supplement/h8300.t
Normal 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.
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
7
doc/cpu_supplement/m32c.t
Normal file
7
doc/cpu_supplement/m32c.t
Normal 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.
|
||||
7
doc/cpu_supplement/m32r.t
Normal file
7
doc/cpu_supplement/m32r.t
Normal 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.
|
||||
@@ -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
|
||||
|
||||
7
doc/cpu_supplement/microblaze.t
Normal file
7
doc/cpu_supplement/microblaze.t
Normal 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.
|
||||
@@ -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
|
||||
|
||||
7
doc/cpu_supplement/nios2.t
Normal file
7
doc/cpu_supplement/nios2.t
Normal 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.
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
19
testsuites/sptests/sptls01/Makefile.am
Normal file
19
testsuites/sptests/sptls01/Makefile.am
Normal 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
|
||||
98
testsuites/sptests/sptls01/init.c
Normal file
98
testsuites/sptests/sptls01/init.c
Normal 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>
|
||||
11
testsuites/sptests/sptls01/sptls01.doc
Normal file
11
testsuites/sptests/sptls01/sptls01.doc
Normal 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.
|
||||
5
testsuites/sptests/sptls01/sptls01.scn
Normal file
5
testsuites/sptests/sptls01/sptls01.scn
Normal file
@@ -0,0 +1,5 @@
|
||||
*** TEST SPTLS 1 ***
|
||||
TLS item = 123
|
||||
TLS item = 123
|
||||
TLS item = 5
|
||||
*** END OF TEST SPTLS 1 ***
|
||||
20
testsuites/sptests/sptls02/Makefile.am
Normal file
20
testsuites/sptests/sptls02/Makefile.am
Normal 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
|
||||
256
testsuites/sptests/sptls02/init.cc
Normal file
256
testsuites/sptests/sptls02/init.cc
Normal 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>
|
||||
12
testsuites/sptests/sptls02/sptls02.doc
Normal file
12
testsuites/sptests/sptls02/sptls02.doc
Normal 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.
|
||||
4
testsuites/sptests/sptls02/sptls02.scn
Normal file
4
testsuites/sptests/sptls02/sptls02.scn
Normal file
@@ -0,0 +1,4 @@
|
||||
*** TEST SPTLS 2 ***
|
||||
A::globalCounter() = 0
|
||||
A::globalCounter() = 3
|
||||
*** END OF TEST SPTLS 2 ***
|
||||
Reference in New Issue
Block a user