Add thread-local storage (TLS) support

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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