From 022851aba54d32831feaff13deb3d9943e130eee Mon Sep 17 00:00:00 2001 From: Sebastian Huber Date: Tue, 28 Jan 2014 12:10:08 +0100 Subject: Add thread-local storage (TLS) support Tested and implemented on ARM, m68k, PowerPC and SPARC. Other architectures need more work. --- cpukit/score/Makefile.am | 1 + cpukit/score/cpu/arm/Makefile.am | 2 + cpukit/score/cpu/arm/__aeabi_read_tp.c | 44 +++++ cpukit/score/cpu/arm/__tls_get_addr.c | 35 ++++ cpukit/score/cpu/arm/armv7m-context-initialize.c | 8 +- cpukit/score/cpu/arm/cpu.c | 20 ++- cpukit/score/cpu/arm/cpu_asm.S | 10 ++ cpukit/score/cpu/arm/rtems/score/arm.h | 5 + cpukit/score/cpu/arm/rtems/score/cpu.h | 10 +- cpukit/score/cpu/avr/rtems/score/cpu.h | 3 +- cpukit/score/cpu/bfin/cpu.c | 3 +- cpukit/score/cpu/bfin/rtems/score/cpu.h | 4 +- cpukit/score/cpu/h8300/rtems/score/cpu.h | 2 +- cpukit/score/cpu/i386/rtems/score/cpu.h | 2 +- cpukit/score/cpu/lm32/rtems/score/cpu.h | 2 +- cpukit/score/cpu/m32c/context_init.c | 3 +- cpukit/score/cpu/m32c/rtems/score/cpu.h | 4 +- cpukit/score/cpu/m32r/context_init.c | 3 +- cpukit/score/cpu/m32r/rtems/score/cpu.h | 4 +- cpukit/score/cpu/m68k/Makefile.am | 1 + cpukit/score/cpu/m68k/__m68k_read_tp.c | 36 +++++ cpukit/score/cpu/m68k/cpu.c | 27 ++++ cpukit/score/cpu/m68k/rtems/score/cpu.h | 33 ++-- cpukit/score/cpu/mips/cpu.c | 3 +- cpukit/score/cpu/mips/rtems/score/cpu.h | 3 +- cpukit/score/cpu/moxie/rtems/score/cpu.h | 2 +- cpukit/score/cpu/nios2/nios2-context-initialize.c | 3 +- cpukit/score/cpu/nios2/rtems/score/cpu.h | 4 +- cpukit/score/cpu/no_cpu/rtems/score/cpu.h | 3 +- cpukit/score/cpu/powerpc/rtems/score/cpu.h | 3 +- cpukit/score/cpu/sh/cpu.c | 3 +- cpukit/score/cpu/sh/rtems/score/cpu.h | 3 +- cpukit/score/cpu/sparc/cpu.c | 10 +- cpukit/score/cpu/sparc/rtems/score/cpu.h | 4 +- cpukit/score/cpu/sparc64/cpu.c | 10 +- cpukit/score/cpu/sparc64/rtems/score/cpu.h | 3 +- cpukit/score/cpu/v850/cpu.c | 3 +- cpukit/score/cpu/v850/rtems/score/cpu.h | 4 +- cpukit/score/include/rtems/score/context.h | 7 +- cpukit/score/include/rtems/score/thread.h | 2 + cpukit/score/include/rtems/score/tls.h | 187 ++++++++++++++++++++++ cpukit/score/preinstall.am | 4 + cpukit/score/src/threadclose.c | 2 + cpukit/score/src/threadinitialize.c | 18 +++ cpukit/score/src/threadloadenv.c | 3 +- cpukit/score/src/wkspace.c | 30 ++++ 46 files changed, 521 insertions(+), 55 deletions(-) create mode 100644 cpukit/score/cpu/arm/__aeabi_read_tp.c create mode 100644 cpukit/score/cpu/arm/__tls_get_addr.c create mode 100644 cpukit/score/cpu/m68k/__m68k_read_tp.c create mode 100644 cpukit/score/include/rtems/score/tls.h (limited to 'cpukit') diff --git a/cpukit/score/Makefile.am b/cpukit/score/Makefile.am index 4b221294d2..871d44ea39 100644 --- a/cpukit/score/Makefile.am +++ b/cpukit/score/Makefile.am @@ -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 diff --git a/cpukit/score/cpu/arm/Makefile.am b/cpukit/score/cpu/arm/Makefile.am index edd72480bd..fe97e03e29 100644 --- a/cpukit/score/cpu/arm/Makefile.am +++ b/cpukit/score/cpu/arm/Makefile.am @@ -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 diff --git a/cpukit/score/cpu/arm/__aeabi_read_tp.c b/cpukit/score/cpu/arm/__aeabi_read_tp.c new file mode 100644 index 0000000000..afdfd99d8b --- /dev/null +++ b/cpukit/score/cpu/arm/__aeabi_read_tp.c @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * 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 +#include + +#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 */ diff --git a/cpukit/score/cpu/arm/__tls_get_addr.c b/cpukit/score/cpu/arm/__tls_get_addr.c new file mode 100644 index 0000000000..cd046518e1 --- /dev/null +++ b/cpukit/score/cpu/arm/__tls_get_addr.c @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * 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 +#include + +#include + +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; +} diff --git a/cpukit/score/cpu/arm/armv7m-context-initialize.c b/cpukit/score/cpu/arm/armv7m-context-initialize.c index 892df4d8c8..13aa0a9b19 100644 --- a/cpukit/score/cpu/arm/armv7m-context-initialize.c +++ b/cpukit/score/cpu/arm/armv7m-context-initialize.c @@ -26,6 +26,7 @@ #include #include +#include #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 */ diff --git a/cpukit/score/cpu/arm/cpu.c b/cpukit/score/cpu/arm/cpu.c index 1c1fe5d3de..c3f071df55 100644 --- a/cpukit/score/cpu/arm/cpu.c +++ b/cpukit/score/cpu/arm/cpu.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #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 */ diff --git a/cpukit/score/cpu/arm/cpu_asm.S b/cpukit/score/cpu/arm/cpu_asm.S index 7fb4062d50..1771ddd661 100644 --- a/cpukit/score/cpu/arm/cpu_asm.S +++ b/cpukit/score/cpu/arm/cpu_asm.S @@ -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} diff --git a/cpukit/score/cpu/arm/rtems/score/arm.h b/cpukit/score/cpu/arm/rtems/score/arm.h index 608f753d11..3e428f9201 100644 --- a/cpukit/score/cpu/arm/rtems/score/arm.h +++ b/cpukit/score/cpu/arm/rtems/score/arm.h @@ -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__) diff --git a/cpukit/score/cpu/arm/rtems/score/cpu.h b/cpukit/score/cpu/arm/rtems/score/cpu.h index 2d9b5d50b6..216f39f862 100644 --- a/cpukit/score/cpu/arm/rtems/score/cpu.h +++ b/cpukit/score/cpu/arm/rtems/score/cpu.h @@ -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 ) \ diff --git a/cpukit/score/cpu/avr/rtems/score/cpu.h b/cpukit/score/cpu/avr/rtems/score/cpu.h index b67b2416a5..f82b7637d3 100644 --- a/cpukit/score/cpu/avr/rtems/score/cpu.h +++ b/cpukit/score/cpu/avr/rtems/score/cpu.h @@ -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 ); /* diff --git a/cpukit/score/cpu/bfin/cpu.c b/cpukit/score/cpu/bfin/cpu.c index 05b9243513..268848e02b 100644 --- a/cpukit/score/cpu/bfin/cpu.c +++ b/cpukit/score/cpu/bfin/cpu.c @@ -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 */ diff --git a/cpukit/score/cpu/bfin/rtems/score/cpu.h b/cpukit/score/cpu/bfin/rtems/score/cpu.h index 1af3f81f81..a8c60a5c44 100644 --- a/cpukit/score/cpu/bfin/rtems/score/cpu.h +++ b/cpukit/score/cpu/bfin/rtems/score/cpu.h @@ -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 ); /** diff --git a/cpukit/score/cpu/h8300/rtems/score/cpu.h b/cpukit/score/cpu/h8300/rtems/score/cpu.h index f75f2e5825..66774d4039 100644 --- a/cpukit/score/cpu/h8300/rtems/score/cpu.h +++ b/cpukit/score/cpu/h8300/rtems/score/cpu.h @@ -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; \ diff --git a/cpukit/score/cpu/i386/rtems/score/cpu.h b/cpukit/score/cpu/i386/rtems/score/cpu.h index 43422ed9d7..dd06059853 100644 --- a/cpukit/score/cpu/i386/rtems/score/cpu.h +++ b/cpukit/score/cpu/i386/rtems/score/cpu.h @@ -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; \ \ diff --git a/cpukit/score/cpu/lm32/rtems/score/cpu.h b/cpukit/score/cpu/lm32/rtems/score/cpu.h index 95553efa48..4699c1a226 100644 --- a/cpukit/score/cpu/lm32/rtems/score/cpu.h +++ b/cpukit/score/cpu/lm32/rtems/score/cpu.h @@ -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; \ diff --git a/cpukit/score/cpu/m32c/context_init.c b/cpukit/score/cpu/m32c/context_init.c index d7c1c5dd92..b2edcf8a21 100644 --- a/cpukit/score/cpu/m32c/context_init.c +++ b/cpukit/score/cpu/m32c/context_init.c @@ -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; diff --git a/cpukit/score/cpu/m32c/rtems/score/cpu.h b/cpukit/score/cpu/m32c/rtems/score/cpu.h index 5841885c8e..681fb4bcd0 100644 --- a/cpukit/score/cpu/m32c/rtems/score/cpu.h +++ b/cpukit/score/cpu/m32c/rtems/score/cpu.h @@ -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 ); /** diff --git a/cpukit/score/cpu/m32r/context_init.c b/cpukit/score/cpu/m32r/context_init.c index bdfd758d91..d8ecc5309d 100644 --- a/cpukit/score/cpu/m32r/context_init.c +++ b/cpukit/score/cpu/m32r/context_init.c @@ -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; diff --git a/cpukit/score/cpu/m32r/rtems/score/cpu.h b/cpukit/score/cpu/m32r/rtems/score/cpu.h index 0fea7bdc4b..95a897a1e2 100644 --- a/cpukit/score/cpu/m32r/rtems/score/cpu.h +++ b/cpukit/score/cpu/m32r/rtems/score/cpu.h @@ -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 ); /** diff --git a/cpukit/score/cpu/m68k/Makefile.am b/cpukit/score/cpu/m68k/Makefile.am index 863a071499..9d8d333dab 100644 --- a/cpukit/score/cpu/m68k/Makefile.am +++ b/cpukit/score/cpu/m68k/Makefile.am @@ -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 diff --git a/cpukit/score/cpu/m68k/__m68k_read_tp.c b/cpukit/score/cpu/m68k/__m68k_read_tp.c new file mode 100644 index 0000000000..3e024a84b3 --- /dev/null +++ b/cpukit/score/cpu/m68k/__m68k_read_tp.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2014 embedded brains GmbH. All rights reserved. + * + * embedded brains GmbH + * Obere Lagerstr. 30 + * 82178 Puchheim + * Germany + * + * + * 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 +#include + +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) + ); +} diff --git a/cpukit/score/cpu/m68k/cpu.c b/cpukit/score/cpu/m68k/cpu.c index 3776345769..589d099f9d 100644 --- a/cpukit/score/cpu/m68k/cpu.c +++ b/cpukit/score/cpu/m68k/cpu.c @@ -19,6 +19,7 @@ #include #include +#include #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 ); + } +} diff --git a/cpukit/score/cpu/m68k/rtems/score/cpu.h b/cpukit/score/cpu/m68k/rtems/score/cpu.h index ccec3a6a64..9981f5393d 100644 --- a/cpukit/score/cpu/m68k/rtems/score/cpu.h +++ b/cpukit/score/cpu/m68k/rtems/score/cpu.h @@ -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 */ diff --git a/cpukit/score/cpu/mips/cpu.c b/cpukit/score/cpu/mips/cpu.c index 5f7abeb368..3be5df361a 100644 --- a/cpukit/score/cpu/mips/cpu.c +++ b/cpukit/score/cpu/mips/cpu.c @@ -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; diff --git a/cpukit/score/cpu/mips/rtems/score/cpu.h b/cpukit/score/cpu/mips/rtems/score/cpu.h index 1d1449ce6f..629996117a 100644 --- a/cpukit/score/cpu/mips/rtems/score/cpu.h +++ b/cpukit/score/cpu/mips/rtems/score/cpu.h @@ -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 ); diff --git a/cpukit/score/cpu/moxie/rtems/score/cpu.h b/cpukit/score/cpu/moxie/rtems/score/cpu.h index 309110a399..36a956cdc8 100644 --- a/cpukit/score/cpu/moxie/rtems/score/cpu.h +++ b/cpukit/score/cpu/moxie/rtems/score/cpu.h @@ -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; \ diff --git a/cpukit/score/cpu/nios2/nios2-context-initialize.c b/cpukit/score/cpu/nios2/nios2-context-initialize.c index e74e04f356..6b884d0085 100644 --- a/cpukit/score/cpu/nios2/nios2-context-initialize.c +++ b/cpukit/score/cpu/nios2/nios2-context-initialize.c @@ -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(); diff --git a/cpukit/score/cpu/nios2/rtems/score/cpu.h b/cpukit/score/cpu/nios2/rtems/score/cpu.h index e0dfd9fd36..bdd8f57e96 100644 --- a/cpukit/score/cpu/nios2/rtems/score/cpu.h +++ b/cpukit/score/cpu/nios2/rtems/score/cpu.h @@ -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 ) \ diff --git a/cpukit/score/cpu/no_cpu/rtems/score/cpu.h b/cpukit/score/cpu/no_cpu/rtems/score/cpu.h index f1f02edaf0..783da76dee 100644 --- a/cpukit/score/cpu/no_cpu/rtems/score/cpu.h +++ b/cpukit/score/cpu/no_cpu/rtems/score/cpu.h @@ -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 ) \ { \ } diff --git a/cpukit/score/cpu/powerpc/rtems/score/cpu.h b/cpukit/score/cpu/powerpc/rtems/score/cpu.h index 6263d34fb7..8eb2327b93 100644 --- a/cpukit/score/cpu/powerpc/rtems/score/cpu.h +++ b/cpukit/score/cpu/powerpc/rtems/score/cpu.h @@ -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 ); /* diff --git a/cpukit/score/cpu/sh/cpu.c b/cpukit/score/cpu/sh/cpu.c index 57d6ffc6db..be3fedd04d 100644 --- a/cpukit/score/cpu/sh/cpu.c +++ b/cpukit/score/cpu/sh/cpu.c @@ -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__) diff --git a/cpukit/score/cpu/sh/rtems/score/cpu.h b/cpukit/score/cpu/sh/rtems/score/cpu.h index 41d96384de..ff9ad55ae4 100644 --- a/cpukit/score/cpu/sh/rtems/score/cpu.h +++ b/cpukit/score/cpu/sh/rtems/score/cpu.h @@ -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 diff --git a/cpukit/score/cpu/sparc/cpu.c b/cpukit/score/cpu/sparc/cpu.c index 1865a21ee8..11e31f9d10 100644 --- a/cpukit/score/cpu/sparc/cpu.c +++ b/cpukit/score/cpu/sparc/cpu.c @@ -20,6 +20,7 @@ #include #include #include +#include #include 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; + } } diff --git a/cpukit/score/cpu/sparc/rtems/score/cpu.h b/cpukit/score/cpu/sparc/rtems/score/cpu.h index 690ddcf90c..ae893112f3 100644 --- a/cpukit/score/cpu/sparc/rtems/score/cpu.h +++ b/cpukit/score/cpu/sparc/rtems/score/cpu.h @@ -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 ); /** diff --git a/cpukit/score/cpu/sparc64/cpu.c b/cpukit/score/cpu/sparc64/cpu.c index 94f9340614..d7c2f47904 100644 --- a/cpukit/score/cpu/sparc64/cpu.c +++ b/cpukit/score/cpu/sparc64/cpu.c @@ -20,6 +20,7 @@ #include #include #include +#include #include /* @@ -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; + } } diff --git a/cpukit/score/cpu/sparc64/rtems/score/cpu.h b/cpukit/score/cpu/sparc64/rtems/score/cpu.h index 8d3e27318b..22ec97d17a 100644 --- a/cpukit/score/cpu/sparc64/rtems/score/cpu.h +++ b/cpukit/score/cpu/sparc64/rtems/score/cpu.h @@ -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 ); /* diff --git a/cpukit/score/cpu/v850/cpu.c b/cpukit/score/cpu/v850/cpu.c index 50065b6623..d4022f36a0 100644 --- a/cpukit/score/cpu/v850/cpu.c +++ b/cpukit/score/cpu/v850/cpu.c @@ -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 */ diff --git a/cpukit/score/cpu/v850/rtems/score/cpu.h b/cpukit/score/cpu/v850/rtems/score/cpu.h index 3e110b5776..f41bde0953 100644 --- a/cpukit/score/cpu/v850/rtems/score/cpu.h +++ b/cpukit/score/cpu/v850/rtems/score/cpu.h @@ -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 ); /** diff --git a/cpukit/score/include/rtems/score/context.h b/cpukit/score/include/rtems/score/context.h index 02bcf156dd..ffffe9bb51 100644 --- a/cpukit/score/include/rtems/score/context.h +++ b/cpukit/score/include/rtems/score/context.h @@ -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 diff --git a/cpukit/score/include/rtems/score/thread.h b/cpukit/score/include/rtems/score/thread.h index 33b5244ac7..bf500fe6f5 100644 --- a/cpukit/score/include/rtems/score/thread.h +++ b/cpukit/score/include/rtems/score/thread.h @@ -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; /** diff --git a/cpukit/score/include/rtems/score/tls.h b/cpukit/score/include/rtems/score/tls.h new file mode 100644 index 0000000000..89954d9e48 --- /dev/null +++ b/cpukit/score/include/rtems/score/tls.h @@ -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 + * + * + * 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 + +#include + +#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 */ diff --git a/cpukit/score/preinstall.am b/cpukit/score/preinstall.am index 79a18b5dd1..f43fc9d733 100644 --- a/cpukit/score/preinstall.am +++ b/cpukit/score/preinstall.am @@ -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 diff --git a/cpukit/score/src/threadclose.c b/cpukit/score/src/threadclose.c index df70f508ad..82c4ab4a39 100644 --- a/cpukit/score/src/threadclose.c +++ b/cpukit/score/src/threadclose.c @@ -96,4 +96,6 @@ void _Thread_Close( _Workspace_Free( the_thread->extensions ); the_thread->extensions = NULL; + + _Workspace_Free( the_thread->Start.tls_area ); } diff --git a/cpukit/score/src/threadinitialize.c b/cpukit/score/src/threadinitialize.c index 34198caa80..bc2600afcb 100644 --- a/cpukit/score/src/threadinitialize.c +++ b/cpukit/score/src/threadinitialize.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -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++ ) diff --git a/cpukit/score/src/threadloadenv.c b/cpukit/score/src/threadloadenv.c index eb3cc63ca7..49821b0697 100644 --- a/cpukit/score/src/threadloadenv.c +++ b/cpukit/score/src/threadloadenv.c @@ -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 ); } diff --git a/cpukit/score/src/wkspace.c b/cpukit/score/src/wkspace.c index 65806863c2..f437b885c0 100644 --- a/cpukit/score/src/wkspace.c +++ b/cpukit/score/src/wkspace.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include /* for memset */ @@ -30,6 +32,25 @@ #include #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]; -- cgit v1.2.3