mirror of
https://github.com/genodelabs/genode.git
synced 2025-02-20 17:52:52 +00:00
parent
2c47cd5c94
commit
ab017607a2
@ -1,4 +1,4 @@
|
||||
CXX_SRC_CC += misc.cc new_delete.cc malloc_free.cc exception.cc guard.cc
|
||||
CXX_SRC_CC += misc.cc new_delete.cc malloc_free.cc exception.cc guard.cc emutls.cc
|
||||
INC_DIR += $(REP_DIR)/src/include
|
||||
# We need the libsupc++ include directory
|
||||
STDINC = yes
|
||||
|
@ -638,6 +638,7 @@ __cxa_throw_bad_array_length T
|
||||
__cxa_throw_bad_array_new_length T
|
||||
__cxa_type_match T
|
||||
__dynamic_cast T
|
||||
__emutls_get_address T
|
||||
__gxx_personality_v0 T
|
||||
__stack_chk_fail W
|
||||
__stack_chk_guard B 8
|
||||
|
1
repos/base/recipes/pkg/test-tls/README
Normal file
1
repos/base/recipes/pkg/test-tls/README
Normal file
@ -0,0 +1 @@
|
||||
Scenario that tests thread-local storage using the 'thread_local' keyword
|
2
repos/base/recipes/pkg/test-tls/archives
Normal file
2
repos/base/recipes/pkg/test-tls/archives
Normal file
@ -0,0 +1,2 @@
|
||||
_/src/init
|
||||
_/src/test-tls
|
1
repos/base/recipes/pkg/test-tls/hash
Normal file
1
repos/base/recipes/pkg/test-tls/hash
Normal file
@ -0,0 +1 @@
|
||||
2019-06-14-a 32cef2fb399ad2ead392710f70908d02ca0cfcb0
|
35
repos/base/recipes/pkg/test-tls/runtime
Normal file
35
repos/base/recipes/pkg/test-tls/runtime
Normal file
@ -0,0 +1,35 @@
|
||||
<runtime ram="32M" caps="1000" binary="init">
|
||||
|
||||
<events>
|
||||
<timeout meaning="failed" sec="20" />
|
||||
<log meaning="succeeded">
|
||||
[init -> test-tls] main initial: x: -1, y: 0
|
||||
[init -> test-tls] thread 0 initial: x: -1, y: 0
|
||||
[init -> test-tls] thread 0 : x: 1, y: 2
|
||||
[init -> test-tls] thread 1 initial: x: -1, y: 0
|
||||
[init -> test-tls] thread 1 : x: 3, y: 4
|
||||
[init -> test-tls] main : x: 5, y: 6
|
||||
</log>
|
||||
</events>
|
||||
|
||||
<content>
|
||||
<rom label="ld.lib.so"/>
|
||||
<rom label="test-tls"/>
|
||||
</content>
|
||||
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="LOG"/>
|
||||
<service name="PD"/>
|
||||
<service name="CPU"/>
|
||||
<service name="ROM"/>
|
||||
</parent-provides>
|
||||
<default-route>
|
||||
<any-service> <parent/> </any-service>
|
||||
</default-route>
|
||||
<default caps="50"/>
|
||||
<start name="test-tls">
|
||||
<resource name="RAM" quantum="10M"/>
|
||||
</start>
|
||||
</config>
|
||||
</runtime>
|
2
repos/base/recipes/src/test-tls/content.mk
Normal file
2
repos/base/recipes/src/test-tls/content.mk
Normal file
@ -0,0 +1,2 @@
|
||||
SRC_DIR = src/test/tls
|
||||
include $(GENODE_DIR)/repos/base/recipes/src/content.inc
|
1
repos/base/recipes/src/test-tls/hash
Normal file
1
repos/base/recipes/src/test-tls/hash
Normal file
@ -0,0 +1 @@
|
||||
2019-06-14 a9faa56873451803a1cd0f4df0ad175bd4e4731b
|
1
repos/base/recipes/src/test-tls/used_apis
Normal file
1
repos/base/recipes/src/test-tls/used_apis
Normal file
@ -0,0 +1 @@
|
||||
base
|
@ -47,6 +47,7 @@ namespace Genode {
|
||||
|
||||
void cxx_demangle(char const*, char*, size_t);
|
||||
void cxx_current_exception(char *out, size_t size);
|
||||
void cxx_free_tls(void *thread);
|
||||
|
||||
Id_space<Parent::Client> &env_session_id_space();
|
||||
Env &internal_env();
|
||||
|
@ -251,6 +251,8 @@ Thread::~Thread()
|
||||
_deinit_platform_thread();
|
||||
_free_stack(_stack);
|
||||
|
||||
cxx_free_tls(this);
|
||||
|
||||
/*
|
||||
* We have to detach the trace control dataspace last because
|
||||
* we cannot invalidate the pointer used by the Trace::Logger
|
||||
|
196
repos/base/src/lib/cxx/emutls.cc
Normal file
196
repos/base/src/lib/cxx/emutls.cc
Normal file
@ -0,0 +1,196 @@
|
||||
/*
|
||||
* \brief TLS support ('emutls')
|
||||
* \author Christian Prochaska
|
||||
* \date 2019-06-13
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2019 Genode Labs GmbH
|
||||
*
|
||||
* This file is part of the Genode OS framework, which is distributed
|
||||
* under the terms of the GNU Affero General Public License version 3.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/heap.h>
|
||||
#include <base/log.h>
|
||||
#include <base/thread.h>
|
||||
|
||||
/* base-internal includes */
|
||||
#include <base/internal/globals.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
/* implemented in 'malloc_free.cc' */
|
||||
extern Heap &cxx_heap();
|
||||
|
||||
static constexpr bool _verbose = false;
|
||||
|
||||
|
||||
/*
|
||||
* An emutls object describes the properties of a thread-local variable.
|
||||
* Structure layout as defined in libgcc's 'emutls.c'.
|
||||
*/
|
||||
struct __emutls_object
|
||||
{
|
||||
size_t const size; /* size of the variable */
|
||||
size_t const align; /* alignment of the variable */
|
||||
void *ptr; /* used in this implementation for an AVL tree with
|
||||
references to all the thread-local instances */
|
||||
void const *templ; /* template for initializing a thread-local instance */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* AVL node referencing the thread-local variable instance of a specific thread
|
||||
*/
|
||||
class Tls_node : public Avl_node<Tls_node>
|
||||
{
|
||||
private:
|
||||
|
||||
void *_thread; /* key */
|
||||
void *_address; /* value */
|
||||
|
||||
/* Noncopyable */
|
||||
Tls_node(const Tls_node&);
|
||||
void operator=(const Tls_node&);
|
||||
|
||||
public:
|
||||
|
||||
Tls_node(void *thread, void *address)
|
||||
: _thread(thread), _address(address) { }
|
||||
|
||||
void *address() { return _address; }
|
||||
|
||||
bool higher(Tls_node *other)
|
||||
{
|
||||
return (other->_thread > _thread);
|
||||
}
|
||||
|
||||
Tls_node *find_by_thread(void *thread)
|
||||
{
|
||||
if (thread == _thread) return this;
|
||||
|
||||
Tls_node *c = child(thread > _thread);
|
||||
return c ? c->find_by_thread(thread) : nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct Tls_tree : Avl_tree<Tls_node>, List<Tls_tree>::Element { };
|
||||
|
||||
|
||||
/*
|
||||
* List referencing all AVL trees.
|
||||
* Needed for freeing all allocated variable instances of a thread.
|
||||
*/
|
||||
static List<Tls_tree> &_tls_tree_list()
|
||||
{
|
||||
static List<Tls_tree> instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
static Lock &_emutls_lock()
|
||||
{
|
||||
static Lock instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free all thread-local variable instances of the given thread
|
||||
*/
|
||||
void Genode::cxx_free_tls(void *thread)
|
||||
{
|
||||
Lock::Guard lock_guard(_emutls_lock());
|
||||
|
||||
for (Tls_tree *tls_tree = _tls_tree_list().first();
|
||||
tls_tree; tls_tree = tls_tree->next()) {
|
||||
|
||||
if (tls_tree->first()) {
|
||||
|
||||
Tls_node *tls_node = tls_tree->first()->find_by_thread(thread);
|
||||
|
||||
if (tls_node) {
|
||||
tls_tree->remove(tls_node);
|
||||
cxx_heap().free(tls_node->address(), 0);
|
||||
destroy(cxx_heap(), tls_node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function is called when a thread-local variable is accessed.
|
||||
* It returns the address of the variable for the current thread and
|
||||
* allocates and initializes the variable when it is accessed for the
|
||||
* first time by this thread.
|
||||
*/
|
||||
extern "C" void *__emutls_get_address(void *obj)
|
||||
{
|
||||
Lock::Guard lock_guard(_emutls_lock());
|
||||
|
||||
__emutls_object *emutls_object = reinterpret_cast<__emutls_object*>(obj);
|
||||
|
||||
if (_verbose)
|
||||
log(__func__, ": emutls_object: ", emutls_object,
|
||||
", size: ", emutls_object->size,
|
||||
", align: ", emutls_object->align,
|
||||
", ptr: ", emutls_object->ptr,
|
||||
", templ: ", emutls_object->templ);
|
||||
|
||||
if (!emutls_object->ptr) {
|
||||
/*
|
||||
* The variable is accessed for the first time by any thread.
|
||||
* Create an AVL tree which keeps track of all instances of this
|
||||
* variable.
|
||||
*/
|
||||
Tls_tree *tls_tree = new (cxx_heap()) Tls_tree;
|
||||
_tls_tree_list().insert(tls_tree);
|
||||
emutls_object->ptr = tls_tree;
|
||||
}
|
||||
|
||||
Tls_tree *tls_tree = static_cast<Tls_tree*>(emutls_object->ptr);
|
||||
|
||||
Thread *myself = Thread::myself();
|
||||
|
||||
Tls_node *tls_node = nullptr;
|
||||
|
||||
if (tls_tree->first())
|
||||
tls_node = tls_tree->first()->find_by_thread(myself);
|
||||
|
||||
if (!tls_node) {
|
||||
|
||||
/*
|
||||
* The variable is accessed for the first time by this thread.
|
||||
* Allocate and initialize a new variable instance and store a
|
||||
* reference in the AVL tree.
|
||||
*/
|
||||
|
||||
/* the heap allocates 16-byte aligned */
|
||||
if ((16 % emutls_object->align) != 0)
|
||||
Genode::warning(__func__, ": cannot ensure alignment of ",
|
||||
emutls_object->align, " bytes");
|
||||
|
||||
void *address = nullptr;
|
||||
|
||||
if (!cxx_heap().alloc(emutls_object->size, &address)) {
|
||||
Genode::error(__func__,
|
||||
": could not allocate thread-local variable instance");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (emutls_object->templ)
|
||||
memcpy(address, emutls_object->templ, emutls_object->size);
|
||||
else
|
||||
memset(address, 0, emutls_object->size);
|
||||
|
||||
tls_node = new (cxx_heap()) Tls_node(myself, address);
|
||||
|
||||
tls_tree->insert(tls_node);
|
||||
}
|
||||
|
||||
return tls_node->address();
|
||||
}
|
@ -30,7 +30,7 @@ using namespace Genode;
|
||||
static Heap *cxx_heap_ptr;
|
||||
|
||||
|
||||
static Heap &cxx_heap()
|
||||
Heap &cxx_heap()
|
||||
{
|
||||
class Cxx_heap_uninitialized : Exception { };
|
||||
if (!cxx_heap_ptr)
|
||||
|
62
repos/base/src/test/tls/main.cc
Normal file
62
repos/base/src/test/tls/main.cc
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* \brief Test TLS support
|
||||
* \author Christian Prochaska
|
||||
* \date 2019-06-13
|
||||
*/
|
||||
|
||||
#include <base/component.h>
|
||||
#include <base/log.h>
|
||||
#include <base/thread.h>
|
||||
|
||||
|
||||
static thread_local int thread_local_x = -1;
|
||||
static thread_local int thread_local_y;
|
||||
|
||||
|
||||
struct Test_thread : Genode::Thread
|
||||
{
|
||||
int _thread_id;
|
||||
int _x;
|
||||
int _y;
|
||||
|
||||
Test_thread(Genode::Env &env, int thread_id, int x, int y)
|
||||
: Genode::Thread(env, "test_thread", 16*1024),
|
||||
_thread_id(thread_id), _x(x), _y(y)
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
void entry() override
|
||||
{
|
||||
Genode::log("thread ", _thread_id,
|
||||
" initial: x: ", thread_local_x,
|
||||
", y: ", thread_local_y);
|
||||
|
||||
thread_local_x = _x;
|
||||
thread_local_y = _y;
|
||||
|
||||
Genode::log("thread ", _thread_id,
|
||||
" : x: ", thread_local_x,
|
||||
", y: ", thread_local_y);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void Component::construct(Genode::Env &env)
|
||||
{
|
||||
using namespace Genode;
|
||||
|
||||
Genode::log("main initial: x: ", thread_local_x,
|
||||
", y: ", thread_local_y);
|
||||
|
||||
thread_local_x = 5;
|
||||
thread_local_y = 6;
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
Test_thread test_thread(env, i, (i * 2) + 1, (i * 2) + 2);
|
||||
test_thread.join();
|
||||
}
|
||||
|
||||
Genode::log("main : x: ", thread_local_x,
|
||||
", y: ", thread_local_y);
|
||||
}
|
3
repos/base/src/test/tls/target.mk
Normal file
3
repos/base/src/test/tls/target.mk
Normal file
@ -0,0 +1,3 @@
|
||||
TARGET = test-tls
|
||||
SRC_CC = main.cc
|
||||
LIBS = base
|
@ -722,6 +722,7 @@ set default_test_pkgs {
|
||||
test-terminal_crosslink
|
||||
test-timed_semaphore
|
||||
test-timer
|
||||
test-tls
|
||||
test-trace
|
||||
test-trace_logger
|
||||
test-utf8
|
||||
|
@ -1 +1 @@
|
||||
893d85767720fc2b3c695c56d737d2307b1f2229
|
||||
3283673a91ae961dfb4e439854ef4f2a23bdc793
|
||||
|
44
repos/ports/src/noux-pkg/gcc/patches/emutls.patch
Normal file
44
repos/ports/src/noux-pkg/gcc/patches/emutls.patch
Normal file
@ -0,0 +1,44 @@
|
||||
emutls.patch
|
||||
|
||||
From: Christian Prochaska <christian.prochaska@genode-labs.com>
|
||||
|
||||
|
||||
---
|
||||
libgcc/Makefile.in | 9 ++++++---
|
||||
libstdc++-v3/configure.ac | 3 +++
|
||||
2 files changed, 9 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libgcc/Makefile.in b/libgcc/Makefile.in
|
||||
index 8cae772c8..7e4cbd0ea 100644
|
||||
--- a/libgcc/Makefile.in
|
||||
+++ b/libgcc/Makefile.in
|
||||
@@ -428,9 +428,12 @@ LIB2ADD += enable-execute-stack.c
|
||||
# While emutls.c has nothing to do with EH, it is in LIB2ADDEH*
|
||||
# instead of LIB2ADD because that's the way to be sure on some targets
|
||||
# (e.g. *-*-darwin*) only one copy of it is linked.
|
||||
-LIB2ADDEH += $(srcdir)/emutls.c
|
||||
-LIB2ADDEHSTATIC += $(srcdir)/emutls.c
|
||||
-LIB2ADDEHSHARED += $(srcdir)/emutls.c
|
||||
+#
|
||||
+# Genode implements '__emutls_get_address()' in the 'cxx' library
|
||||
+#
|
||||
+#LIB2ADDEH += $(srcdir)/emutls.c
|
||||
+#LIB2ADDEHSTATIC += $(srcdir)/emutls.c
|
||||
+#LIB2ADDEHSHARED += $(srcdir)/emutls.c
|
||||
|
||||
# Library members defined in libgcc2.c.
|
||||
lib2funcs = _muldi3 _negdi2 _lshrdi3 _ashldi3 _ashrdi3 _cmpdi2 _ucmpdi2 \
|
||||
diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
|
||||
index 7d7279b06..84d8c6650 100644
|
||||
--- a/libstdc++-v3/configure.ac
|
||||
+++ b/libstdc++-v3/configure.ac
|
||||
@@ -367,6 +367,9 @@ else
|
||||
AC_DEFINE(HAVE_TANL)
|
||||
AC_DEFINE(HAVE_TANHL)
|
||||
fi
|
||||
+
|
||||
+ # Genode supports TLS
|
||||
+ AC_DEFINE(HAVE_TLS)
|
||||
fi
|
||||
|
||||
# Check for _Unwind_GetIPInfo.
|
@ -12,3 +12,4 @@ noux_build.patch
|
||||
arm.patch
|
||||
new_opa.patch
|
||||
aarch64.patch
|
||||
emutls.patch
|
||||
|
Loading…
x
Reference in New Issue
Block a user