thread: rearrange thread context management
Use a bit allocator for the allocation management of thread contexts, instead of holding allocation information within the Thread_base objects, which lead to race conditions in the past. Moreover, extend the Thread_base class interface with the ability to to add additional stacks to a thread, and associate the context they're located in with the corresponding Thread_base object. Additional stacks can be used to do user-level scheduling with stack switching, without breaking Genode's API. Fixes #1024 Fixes #1036
This commit is contained in:
parent
66c5887bd3
commit
5447c406e5
|
@ -95,13 +95,15 @@ namespace Genode {
|
||||||
/**
|
/**
|
||||||
* Thread-context area configuration.
|
* Thread-context area configuration.
|
||||||
*/
|
*/
|
||||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
static constexpr addr_t context_area_virtual_base() {
|
||||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
return 0x40000000UL; }
|
||||||
|
static constexpr addr_t context_area_virtual_size() {
|
||||||
|
return 0x10000000UL; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of virtual address region holding the context of one thread
|
* Size of virtual address region holding the context of one thread
|
||||||
*/
|
*/
|
||||||
static addr_t context_virtual_size() { return 0x00100000UL; }
|
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Native_pd_args { };
|
struct Native_pd_args { };
|
||||||
|
|
|
@ -78,13 +78,15 @@ namespace Genode {
|
||||||
/**
|
/**
|
||||||
* Thread-context area configuration.
|
* Thread-context area configuration.
|
||||||
*/
|
*/
|
||||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
static constexpr addr_t context_area_virtual_base() {
|
||||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
return 0x40000000UL; }
|
||||||
|
static constexpr addr_t context_area_virtual_size() {
|
||||||
|
return 0x10000000UL; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of virtual address region holding the context of one thread
|
* Size of virtual address region holding the context of one thread
|
||||||
*/
|
*/
|
||||||
static addr_t context_virtual_size() { return 0x00100000UL; }
|
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Native_pd_args { };
|
struct Native_pd_args { };
|
||||||
|
|
38
base-foc/include/arm/base/native_config.h
Normal file
38
base-foc/include/arm/base/native_config.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* \brief Platform-specific context area definitions
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2014-01-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE__BASE__NATIVE_CONFIG_H_
|
||||||
|
#define _INCLUDE__BASE__NATIVE_CONFIG_H_
|
||||||
|
|
||||||
|
#include <base/stdint.h>
|
||||||
|
|
||||||
|
namespace Genode {
|
||||||
|
|
||||||
|
struct Native_config
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Thread-context area configuration
|
||||||
|
*/
|
||||||
|
static constexpr addr_t context_area_virtual_base() {
|
||||||
|
return 0x20000000UL; }
|
||||||
|
static constexpr addr_t context_area_virtual_size() {
|
||||||
|
return 0x10000000UL; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of virtual address region holding the context of one thread
|
||||||
|
*/
|
||||||
|
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _INCLUDE__BASE__NATIVE_CONFIG_H_ */
|
|
@ -1,8 +1,8 @@
|
||||||
#ifndef _INCLUDE__BASE__NATIVE_TYPES_H_
|
#ifndef _INCLUDE__BASE__NATIVE_TYPES_H_
|
||||||
#define _INCLUDE__BASE__NATIVE_TYPES_H_
|
#define _INCLUDE__BASE__NATIVE_TYPES_H_
|
||||||
|
|
||||||
|
#include <base/native_config.h>
|
||||||
#include <base/cap_map.h>
|
#include <base/cap_map.h>
|
||||||
#include <base/stdint.h>
|
|
||||||
|
|
||||||
namespace Fiasco {
|
namespace Fiasco {
|
||||||
#include <l4/sys/consts.h>
|
#include <l4/sys/consts.h>
|
||||||
|
@ -178,20 +178,6 @@ namespace Genode {
|
||||||
|
|
||||||
typedef int Native_connection_state;
|
typedef int Native_connection_state;
|
||||||
|
|
||||||
struct Native_config
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Thread-context area configuration
|
|
||||||
*/
|
|
||||||
static addr_t context_area_virtual_base();
|
|
||||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Size of virtual address region holding the context of one thread
|
|
||||||
*/
|
|
||||||
static addr_t context_virtual_size() { return 0x00100000UL; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Native_pd_args { };
|
struct Native_pd_args { };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
38
base-foc/include/x86/base/native_config.h
Normal file
38
base-foc/include/x86/base/native_config.h
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* \brief Platform-specific context area definitions
|
||||||
|
* \author Stefan Kalkowski
|
||||||
|
* \date 2014-01-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Genode Labs GmbH
|
||||||
|
*
|
||||||
|
* This file is part of the Genode OS framework, which is distributed
|
||||||
|
* under the terms of the GNU General Public License version 2.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _INCLUDE__BASE__NATIVE_CONFIG_H_
|
||||||
|
#define _INCLUDE__BASE__NATIVE_CONFIG_H_
|
||||||
|
|
||||||
|
#include <base/stdint.h>
|
||||||
|
|
||||||
|
namespace Genode {
|
||||||
|
|
||||||
|
struct Native_config
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Thread-context area configuration
|
||||||
|
*/
|
||||||
|
static constexpr addr_t context_area_virtual_base() {
|
||||||
|
return 0x40000000UL; }
|
||||||
|
static constexpr addr_t context_area_virtual_size() {
|
||||||
|
return 0x10000000UL; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Size of virtual address region holding the context of one thread
|
||||||
|
*/
|
||||||
|
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* _INCLUDE__BASE__NATIVE_CONFIG_H_ */
|
|
@ -1,3 +0,0 @@
|
||||||
include $(REP_DIR)/lib/mk/base.inc
|
|
||||||
|
|
||||||
SRC_CC += thread/thread_context_area.cc
|
|
|
@ -1,3 +0,0 @@
|
||||||
include $(REP_DIR)/lib/mk/base.inc
|
|
||||||
|
|
||||||
SRC_CC += thread/arndale/thread_context_area.cc
|
|
|
@ -1,3 +0,0 @@
|
||||||
include $(REP_DIR)/lib/mk/base.inc
|
|
||||||
|
|
||||||
SRC_CC += thread/thread_context_area.cc
|
|
|
@ -1,19 +0,0 @@
|
||||||
/*
|
|
||||||
* \brief Arndale specific definition of the context area location
|
|
||||||
* \author Sebastian Sumpf
|
|
||||||
* \date 2013-02-12
|
|
||||||
*
|
|
||||||
* We need to place the context area within core outside the physical memory.
|
|
||||||
* Sigma0 maps physical to core-local memory always 1:1 when using
|
|
||||||
* SIGMA0_REQ_FPAGE_ANY. Those mappings would interfere with the context area.
|
|
||||||
*
|
|
||||||
* Because the UTCB area of a task resides at the end of the context area and
|
|
||||||
* its address gets calculated by core, the context area in other tasks needs
|
|
||||||
* to be at the same address as in core.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <base/native_types.h>
|
|
||||||
|
|
||||||
using namespace Genode;
|
|
||||||
|
|
||||||
addr_t Native_config::context_area_virtual_base() { return 0x20000000UL; }
|
|
|
@ -17,10 +17,6 @@
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
#include <util/misc_math.h>
|
#include <util/misc_math.h>
|
||||||
|
|
||||||
namespace Fiasco {
|
|
||||||
#include <l4/sys/utcb.h>
|
|
||||||
}
|
|
||||||
|
|
||||||
using namespace Genode;
|
using namespace Genode;
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,7 +37,8 @@ namespace Genode {
|
||||||
|
|
||||||
Thread_base::Context *Thread_base::Context_allocator::base_to_context(addr_t base)
|
Thread_base::Context *Thread_base::Context_allocator::base_to_context(addr_t base)
|
||||||
{
|
{
|
||||||
addr_t result = base + Native_config::context_virtual_size() - sizeof(Context);
|
addr_t result = base + Native_config::context_virtual_size()
|
||||||
|
- sizeof(Context);
|
||||||
return reinterpret_cast<Context *>(result);
|
return reinterpret_cast<Context *>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,14 +49,17 @@ addr_t Thread_base::Context_allocator::addr_to_base(void *addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Thread_base::Context_allocator::_is_in_use(addr_t base)
|
size_t Thread_base::Context_allocator::base_to_idx(addr_t base)
|
||||||
{
|
{
|
||||||
List_element<Thread_base> *le = _threads.first();
|
return (base - Native_config::context_area_virtual_base()) /
|
||||||
for (; le; le = le->next())
|
Native_config::context_virtual_size();
|
||||||
if (base_to_context(base) == le->object()->_context)
|
}
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
addr_t Thread_base::Context_allocator::idx_to_base(size_t idx)
|
||||||
|
{
|
||||||
|
return Native_config::context_area_virtual_base() +
|
||||||
|
idx * Native_config::context_virtual_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -67,30 +67,19 @@ Thread_base::Context *Thread_base::Context_allocator::alloc(Thread_base *thread_
|
||||||
{
|
{
|
||||||
Lock::Guard _lock_guard(_threads_lock);
|
Lock::Guard _lock_guard(_threads_lock);
|
||||||
|
|
||||||
/*
|
try {
|
||||||
* Find slot in context area for the new context
|
return base_to_context(idx_to_base(_alloc.alloc()));
|
||||||
*/
|
} catch(Bit_allocator<MAX_THREADS>::Out_of_indices) {
|
||||||
addr_t base = Native_config::context_area_virtual_base();
|
|
||||||
for (; _is_in_use(base); base += Native_config::context_virtual_size()) {
|
|
||||||
|
|
||||||
/* check upper bound of context area */
|
|
||||||
if (base >= Native_config::context_area_virtual_base() + Native_config::context_area_virtual_size())
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_threads.insert(&thread_base->_list_element);
|
|
||||||
|
|
||||||
return base_to_context(base);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread_base::Context_allocator::free(Thread_base *thread_base)
|
void Thread_base::Context_allocator::free(Context *context)
|
||||||
{
|
{
|
||||||
Lock::Guard _lock_guard(_threads_lock);
|
Lock::Guard _lock_guard(_threads_lock);
|
||||||
|
|
||||||
_threads.remove(&thread_base->_list_element);
|
_alloc.free(base_to_idx(addr_to_base(context)));
|
||||||
|
|
||||||
thread_base->_context->~Context();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -124,7 +113,8 @@ Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
|
||||||
enum { PAGE_SIZE_LOG2 = 12 };
|
enum { PAGE_SIZE_LOG2 = 12 };
|
||||||
size_t ds_size = align_addr(stack_size, PAGE_SIZE_LOG2);
|
size_t ds_size = align_addr(stack_size, PAGE_SIZE_LOG2);
|
||||||
|
|
||||||
if (stack_size >= Native_config::context_virtual_size() - sizeof(Native_utcb) - (1 << PAGE_SIZE_LOG2))
|
if (stack_size >= Native_config::context_virtual_size() -
|
||||||
|
sizeof(Native_utcb) - (1UL << PAGE_SIZE_LOG2))
|
||||||
throw Stack_too_large();
|
throw Stack_too_large();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -132,8 +122,9 @@ Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
|
||||||
*
|
*
|
||||||
* The stack is always located at the top of the context.
|
* The stack is always located at the top of the context.
|
||||||
*/
|
*/
|
||||||
addr_t ds_addr = Context_allocator::addr_to_base(context) + Native_config::context_virtual_size()
|
addr_t ds_addr = Context_allocator::addr_to_base(context) +
|
||||||
- ds_size;
|
Native_config::context_virtual_size() -
|
||||||
|
ds_size;
|
||||||
|
|
||||||
/* add padding for UTCB if defined for the platform */
|
/* add padding for UTCB if defined for the platform */
|
||||||
if (sizeof(Native_utcb) >= (1 << PAGE_SIZE_LOG2))
|
if (sizeof(Native_utcb) >= (1 << PAGE_SIZE_LOG2))
|
||||||
|
@ -144,41 +135,47 @@ Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
|
||||||
try {
|
try {
|
||||||
ds_cap = env_context_area_ram_session()->alloc(ds_size);
|
ds_cap = env_context_area_ram_session()->alloc(ds_size);
|
||||||
addr_t attach_addr = ds_addr - Native_config::context_area_virtual_base();
|
addr_t attach_addr = ds_addr - Native_config::context_area_virtual_base();
|
||||||
env_context_area_rm_session()->attach_at(ds_cap, attach_addr, ds_size);
|
if (attach_addr != (addr_t)env_context_area_rm_session()->attach_at(ds_cap, attach_addr, ds_size))
|
||||||
|
|
||||||
} catch (Ram_session::Alloc_failed) {
|
|
||||||
throw Stack_alloc_failed();
|
throw Stack_alloc_failed();
|
||||||
}
|
}
|
||||||
|
catch (Ram_session::Alloc_failed) { throw Stack_alloc_failed(); }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now the thread context is backed by memory, so it is safe to access its
|
* Now the thread context is backed by memory, so it is safe to access its
|
||||||
* members.
|
* members.
|
||||||
*
|
*
|
||||||
* We need to initalize the context object's memory with zeroes,
|
* We need to initialize the context object's memory with zeroes,
|
||||||
* otherwise the ds_cap isn't invalid. That would cause trouble
|
* otherwise the ds_cap isn't invalid. That would cause trouble
|
||||||
* when the assignment operator of Native_capability is used.
|
* when the assignment operator of Native_capability is used.
|
||||||
*/
|
*/
|
||||||
memset(context, 0, sizeof(Context));
|
memset(context, 0, sizeof(Context) - sizeof(Context::utcb));
|
||||||
context->thread_base = this;
|
context->thread_base = this;
|
||||||
context->stack_base = ds_addr;
|
context->stack_base = ds_addr;
|
||||||
context->ds_cap = ds_cap;
|
context->ds_cap = ds_cap;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread_base::_free_context()
|
void Thread_base::_free_context(Context* context)
|
||||||
{
|
{
|
||||||
addr_t ds_addr = _context->stack_base - Native_config::context_area_virtual_base();
|
addr_t ds_addr = context->stack_base - Native_config::context_area_virtual_base();
|
||||||
Ram_dataspace_capability ds_cap = _context->ds_cap;
|
Ram_dataspace_capability ds_cap = context->ds_cap;
|
||||||
_context_allocator()->free(this);
|
|
||||||
|
/* call de-constructor explicitly before memory gets detached */
|
||||||
|
context->~Context();
|
||||||
|
|
||||||
Genode::env_context_area_rm_session()->detach((void *)ds_addr);
|
Genode::env_context_area_rm_session()->detach((void *)ds_addr);
|
||||||
Genode::env_context_area_ram_session()->free(ds_cap);
|
Genode::env_context_area_ram_session()->free(ds_cap);
|
||||||
|
|
||||||
|
/* context area ready for reuse */
|
||||||
|
_context_allocator()->free(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread_base::name(char *dst, size_t dst_len)
|
void Thread_base::name(char *dst, size_t dst_len)
|
||||||
{
|
{
|
||||||
snprintf(dst, min(dst_len, (size_t)Context::NAME_LEN), _context->name);
|
snprintf(dst, min(dst_len, (size_t)Context::NAME_LEN), "%s", _context->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -196,9 +193,23 @@ void Thread_base::join()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void* Thread_base::alloc_secondary_stack(char const *name, size_t stack_size)
|
||||||
|
{
|
||||||
|
Context *context = _alloc_context(stack_size);
|
||||||
|
strncpy(context->name, name, sizeof(context->name));
|
||||||
|
return (void *)context->stack_top();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread_base::free_secondary_stack(void* stack_addr)
|
||||||
|
{
|
||||||
|
addr_t base = Context_allocator::addr_to_base(stack_addr);
|
||||||
|
_free_context(Context_allocator::base_to_context(base));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Thread_base::Thread_base(const char *name, size_t stack_size)
|
Thread_base::Thread_base(const char *name, size_t stack_size)
|
||||||
:
|
:
|
||||||
_list_element(this),
|
|
||||||
_context(_alloc_context(stack_size)),
|
_context(_alloc_context(stack_size)),
|
||||||
_join_lock(Lock::LOCKED)
|
_join_lock(Lock::LOCKED)
|
||||||
{
|
{
|
||||||
|
@ -210,5 +221,5 @@ Thread_base::Thread_base(const char *name, size_t stack_size)
|
||||||
Thread_base::~Thread_base()
|
Thread_base::~Thread_base()
|
||||||
{
|
{
|
||||||
_deinit_platform_thread();
|
_deinit_platform_thread();
|
||||||
_free_context();
|
_free_context(_context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
/*
|
|
||||||
* \brief Generic definitions for the location of the thread-context area
|
|
||||||
* \author Sebastian Sumpf
|
|
||||||
* \date 2013-02-12
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <base/native_types.h>
|
|
||||||
|
|
||||||
using namespace Genode;
|
|
||||||
|
|
||||||
addr_t Native_config::context_area_virtual_base() { return 0x40000000UL; }
|
|
|
@ -1,6 +1,3 @@
|
||||||
# override default location of thread context area within core
|
|
||||||
vpath thread_context_area.cc $(REP_DIR)/src/base/thread/arndale
|
|
||||||
|
|
||||||
include $(PRG_DIR)/../target.inc
|
include $(PRG_DIR)/../target.inc
|
||||||
|
|
||||||
LD_TEXT_ADDR = 0x80100000
|
LD_TEXT_ADDR = 0x80100000
|
||||||
|
|
|
@ -33,7 +33,6 @@ SRC_CC = cap_session_component.cc \
|
||||||
signal_source_component.cc \
|
signal_source_component.cc \
|
||||||
trace_session_component.cc \
|
trace_session_component.cc \
|
||||||
thread_start.cc \
|
thread_start.cc \
|
||||||
thread_context_area.cc \
|
|
||||||
core_printf.cc
|
core_printf.cc
|
||||||
|
|
||||||
INC_DIR += $(REP_DIR)/src/core/include \
|
INC_DIR += $(REP_DIR)/src/core/include \
|
||||||
|
|
|
@ -37,13 +37,15 @@ namespace Genode {
|
||||||
/**
|
/**
|
||||||
* Thread-context area configuration.
|
* Thread-context area configuration.
|
||||||
*/
|
*/
|
||||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
static constexpr addr_t context_area_virtual_base() {
|
||||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
return 0x40000000UL; }
|
||||||
|
static constexpr addr_t context_area_virtual_size() {
|
||||||
|
return 0x10000000UL; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of virtual address region holding the context of one thread
|
* Size of virtual address region holding the context of one thread
|
||||||
*/
|
*/
|
||||||
static addr_t context_virtual_size() { return 0x00100000UL; }
|
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Native_pd_args { };
|
struct Native_pd_args { };
|
||||||
|
|
|
@ -106,13 +106,15 @@ namespace Genode
|
||||||
/**
|
/**
|
||||||
* Thread-context area configuration.
|
* Thread-context area configuration.
|
||||||
*/
|
*/
|
||||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
static constexpr addr_t context_area_virtual_base() {
|
||||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
return 0x40000000UL; }
|
||||||
|
static constexpr addr_t context_area_virtual_size() {
|
||||||
|
return 0x10000000UL; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of virtual address region holding the context of one thread
|
* Size of virtual address region holding the context of one thread
|
||||||
*/
|
*/
|
||||||
static addr_t context_virtual_size() { return 0x00100000UL; }
|
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Native_pd_args { };
|
struct Native_pd_args { };
|
||||||
|
|
|
@ -31,7 +31,6 @@ Native_utcb * Thread_base::utcb()
|
||||||
{
|
{
|
||||||
if (this) { return _tid.platform_thread->utcb_virt(); }
|
if (this) { return _tid.platform_thread->utcb_virt(); }
|
||||||
return _main_thread_utcb;
|
return _main_thread_utcb;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -55,8 +54,6 @@ void Thread_base::_thread_start()
|
||||||
|
|
||||||
|
|
||||||
Thread_base::Thread_base(const char * const label, size_t const stack_size)
|
Thread_base::Thread_base(const char * const label, size_t const stack_size)
|
||||||
:
|
|
||||||
_list_element(this)
|
|
||||||
{
|
{
|
||||||
_tid.platform_thread = new (platform()->core_mem_alloc())
|
_tid.platform_thread = new (platform()->core_mem_alloc())
|
||||||
Platform_thread(stack_size, Kernel::core_id(), label);
|
Platform_thread(stack_size, Kernel::core_id(), label);
|
||||||
|
|
|
@ -131,13 +131,15 @@ namespace Genode {
|
||||||
* Please update platform-specific files after changing these
|
* Please update platform-specific files after changing these
|
||||||
* values, e.g., 'base-linux/src/platform/context_area.*.ld'.
|
* values, e.g., 'base-linux/src/platform/context_area.*.ld'.
|
||||||
*/
|
*/
|
||||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
static constexpr addr_t context_area_virtual_base() {
|
||||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
return 0x40000000UL; }
|
||||||
|
static constexpr addr_t context_area_virtual_size() {
|
||||||
|
return 0x10000000UL; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of virtual address region holding the context of one thread
|
* Size of virtual address region holding the context of one thread
|
||||||
*/
|
*/
|
||||||
static addr_t context_virtual_size() { return 0x00100000UL; }
|
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class Native_pd_args
|
class Native_pd_args
|
||||||
|
|
|
@ -402,8 +402,6 @@ void Thread_base::join()
|
||||||
|
|
||||||
|
|
||||||
Thread_base::Thread_base(const char *name, size_t stack_size)
|
Thread_base::Thread_base(const char *name, size_t stack_size)
|
||||||
:
|
|
||||||
_list_element(this)
|
|
||||||
{
|
{
|
||||||
_tid.meta_data = new (env()->heap()) Thread_meta_data_created(this);
|
_tid.meta_data = new (env()->heap()) Thread_meta_data_created(this);
|
||||||
|
|
||||||
|
|
|
@ -257,13 +257,15 @@ namespace Genode {
|
||||||
/**
|
/**
|
||||||
* Thread-context area configuration.
|
* Thread-context area configuration.
|
||||||
*/
|
*/
|
||||||
static addr_t context_area_virtual_base() { return 0xa0000000UL; }
|
static constexpr addr_t context_area_virtual_base() {
|
||||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
return 0xa0000000UL; }
|
||||||
|
static constexpr addr_t context_area_virtual_size() {
|
||||||
|
return 0x10000000UL; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of virtual address region holding the context of one thread
|
* Size of virtual address region holding the context of one thread
|
||||||
*/
|
*/
|
||||||
static addr_t context_virtual_size() { return 0x00100000UL; }
|
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Native_pd_args { };
|
struct Native_pd_args { };
|
||||||
|
|
|
@ -95,13 +95,15 @@ namespace Genode {
|
||||||
/**
|
/**
|
||||||
* Thread-context area configuration.
|
* Thread-context area configuration.
|
||||||
*/
|
*/
|
||||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
static constexpr addr_t context_area_virtual_base() {
|
||||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
return 0x40000000UL; }
|
||||||
|
static constexpr addr_t context_area_virtual_size() {
|
||||||
|
return 0x10000000UL; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of virtual address region holding the context of one thread
|
* Size of virtual address region holding the context of one thread
|
||||||
*/
|
*/
|
||||||
static addr_t context_virtual_size() { return 0x00100000UL; }
|
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Native_pd_args { };
|
struct Native_pd_args { };
|
||||||
|
|
|
@ -79,13 +79,15 @@ namespace Genode {
|
||||||
/**
|
/**
|
||||||
* Thread-context area configuration.
|
* Thread-context area configuration.
|
||||||
*/
|
*/
|
||||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
static constexpr addr_t context_area_virtual_base() {
|
||||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
return 0x40000000UL; }
|
||||||
|
static constexpr addr_t context_area_virtual_size() {
|
||||||
|
return 0x10000000UL; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Size of virtual address region holding the context of one thread
|
* Size of virtual address region holding the context of one thread
|
||||||
*/
|
*/
|
||||||
static addr_t context_virtual_size() { return 0x00100000UL; }
|
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Native_pd_args { };
|
struct Native_pd_args { };
|
||||||
|
|
|
@ -39,6 +39,9 @@
|
||||||
* additional context members. Note that this memory is allocated from the RAM
|
* additional context members. Note that this memory is allocated from the RAM
|
||||||
* session of the process environment and not accounted for when using the
|
* session of the process environment and not accounted for when using the
|
||||||
* 'sizeof()' operand on a 'Thread_base' object.
|
* 'sizeof()' operand on a 'Thread_base' object.
|
||||||
|
*
|
||||||
|
* A thread may be associated with more than one stack. Additional secondary
|
||||||
|
* stacks can be associated with a thread, and used for user level scheduling.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -57,7 +60,7 @@
|
||||||
#include <base/native_types.h>
|
#include <base/native_types.h>
|
||||||
#include <base/trace/logger.h>
|
#include <base/trace/logger.h>
|
||||||
#include <util/string.h>
|
#include <util/string.h>
|
||||||
#include <util/list.h>
|
#include <util/bit_allocator.h>
|
||||||
#include <ram_session/ram_session.h> /* for 'Ram_dataspace_capability' type */
|
#include <ram_session/ram_session.h> /* for 'Ram_dataspace_capability' type */
|
||||||
#include <cpu_session/cpu_session.h> /* for 'Thread_capability' type */
|
#include <cpu_session/cpu_session.h> /* for 'Thread_capability' type */
|
||||||
|
|
||||||
|
@ -80,15 +83,6 @@ namespace Genode {
|
||||||
class Stack_too_large : public Exception { };
|
class Stack_too_large : public Exception { };
|
||||||
class Stack_alloc_failed : public Exception { };
|
class Stack_alloc_failed : public Exception { };
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
/**
|
|
||||||
* List-element helper to enable inserting threads in a list
|
|
||||||
*/
|
|
||||||
List_element<Thread_base> _list_element;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread context located within the thread-context area
|
* Thread context located within the thread-context area
|
||||||
*
|
*
|
||||||
|
@ -169,7 +163,11 @@ namespace Genode {
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
||||||
List<List_element<Thread_base> > _threads;
|
static constexpr size_t MAX_THREADS =
|
||||||
|
Native_config::context_area_virtual_size() /
|
||||||
|
Native_config::context_virtual_size();
|
||||||
|
|
||||||
|
Bit_allocator<MAX_THREADS> _alloc;
|
||||||
Lock _threads_lock;
|
Lock _threads_lock;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -191,7 +189,7 @@ namespace Genode {
|
||||||
/**
|
/**
|
||||||
* Release thread context
|
* Release thread context
|
||||||
*/
|
*/
|
||||||
void free(Thread_base *thread);
|
void free(Context *thread);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return 'Context' object for a given base address
|
* Return 'Context' object for a given base address
|
||||||
|
@ -202,6 +200,16 @@ namespace Genode {
|
||||||
* Return base address of context containing the specified address
|
* Return base address of context containing the specified address
|
||||||
*/
|
*/
|
||||||
static addr_t addr_to_base(void *addr);
|
static addr_t addr_to_base(void *addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return index in context area for a given base address
|
||||||
|
*/
|
||||||
|
static size_t base_to_idx(addr_t base);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return base address of context given index in context area
|
||||||
|
*/
|
||||||
|
static addr_t idx_to_base(size_t idx);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -217,7 +225,7 @@ namespace Genode {
|
||||||
/**
|
/**
|
||||||
* Detach and release thread context of the thread
|
* Detach and release thread context of the thread
|
||||||
*/
|
*/
|
||||||
void _free_context();
|
void _free_context(Context *context);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Platform-specific thread-startup code
|
* Platform-specific thread-startup code
|
||||||
|
@ -258,7 +266,7 @@ namespace Genode {
|
||||||
Genode::Pager_capability _pager_cap;
|
Genode::Pager_capability _pager_cap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Pointer to corresponding thread context
|
* Pointer to primary thread context
|
||||||
*/
|
*/
|
||||||
Context *_context;
|
Context *_context;
|
||||||
|
|
||||||
|
@ -326,6 +334,28 @@ namespace Genode {
|
||||||
*/
|
*/
|
||||||
void name(char *dst, size_t dst_len);
|
void name(char *dst, size_t dst_len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add an additional stack to the thread
|
||||||
|
*
|
||||||
|
* \throw Stack_too_large
|
||||||
|
* \throw Stack_alloc_failed
|
||||||
|
* \throw Context_alloc_failed
|
||||||
|
*
|
||||||
|
* The stack for the new thread will be allocated from the RAM
|
||||||
|
* session of the process environment. A small portion of the
|
||||||
|
* stack size is internally used by the framework for storing
|
||||||
|
* thread-context information such as the thread's name (see
|
||||||
|
* 'struct Context').
|
||||||
|
*
|
||||||
|
* \return pointer to the new stack's top
|
||||||
|
*/
|
||||||
|
void* alloc_secondary_stack(char const *name, size_t stack_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a secondary stack from the thread
|
||||||
|
*/
|
||||||
|
void free_secondary_stack(void* stack_addr);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Request capability of thread
|
* Request capability of thread
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -49,14 +49,17 @@ addr_t Thread_base::Context_allocator::addr_to_base(void *addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Thread_base::Context_allocator::_is_in_use(addr_t base)
|
size_t Thread_base::Context_allocator::base_to_idx(addr_t base)
|
||||||
{
|
{
|
||||||
List_element<Thread_base> *le = _threads.first();
|
return (base - Native_config::context_area_virtual_base()) /
|
||||||
for (; le; le = le->next())
|
Native_config::context_virtual_size();
|
||||||
if (base_to_context(base) == le->object()->_context)
|
}
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
addr_t Thread_base::Context_allocator::idx_to_base(size_t idx)
|
||||||
|
{
|
||||||
|
return Native_config::context_area_virtual_base() +
|
||||||
|
idx * Native_config::context_virtual_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -64,29 +67,19 @@ Thread_base::Context *Thread_base::Context_allocator::alloc(Thread_base *thread_
|
||||||
{
|
{
|
||||||
Lock::Guard _lock_guard(_threads_lock);
|
Lock::Guard _lock_guard(_threads_lock);
|
||||||
|
|
||||||
/*
|
try {
|
||||||
* Find slot in context area for the new context
|
return base_to_context(idx_to_base(_alloc.alloc()));
|
||||||
*/
|
} catch(Bit_allocator<MAX_THREADS>::Out_of_indices) {
|
||||||
addr_t base = Native_config::context_area_virtual_base();
|
|
||||||
for (; _is_in_use(base); base += Native_config::context_virtual_size()) {
|
|
||||||
|
|
||||||
/* check upper bound of context area */
|
|
||||||
if (base >= Native_config::context_area_virtual_base() +
|
|
||||||
Native_config::context_area_virtual_size())
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
_threads.insert(&thread_base->_list_element);
|
|
||||||
|
|
||||||
return base_to_context(base);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread_base::Context_allocator::free(Thread_base *thread_base)
|
void Thread_base::Context_allocator::free(Context *context)
|
||||||
{
|
{
|
||||||
Lock::Guard _lock_guard(_threads_lock);
|
Lock::Guard _lock_guard(_threads_lock);
|
||||||
|
|
||||||
_threads.remove(&thread_base->_list_element);
|
_alloc.free(base_to_idx(addr_to_base(context)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -159,23 +152,24 @@ Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
|
||||||
context->thread_base = this;
|
context->thread_base = this;
|
||||||
context->stack_base = ds_addr;
|
context->stack_base = ds_addr;
|
||||||
context->ds_cap = ds_cap;
|
context->ds_cap = ds_cap;
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Thread_base::_free_context()
|
void Thread_base::_free_context(Context* context)
|
||||||
{
|
{
|
||||||
addr_t ds_addr = _context->stack_base - Native_config::context_area_virtual_base();
|
addr_t ds_addr = context->stack_base - Native_config::context_area_virtual_base();
|
||||||
Ram_dataspace_capability ds_cap = _context->ds_cap;
|
Ram_dataspace_capability ds_cap = context->ds_cap;
|
||||||
|
|
||||||
/* call de-constructor explicitly before memory gets detached */
|
/* call de-constructor explicitly before memory gets detached */
|
||||||
_context->~Context();
|
context->~Context();
|
||||||
|
|
||||||
Genode::env_context_area_rm_session()->detach((void *)ds_addr);
|
Genode::env_context_area_rm_session()->detach((void *)ds_addr);
|
||||||
Genode::env_context_area_ram_session()->free(ds_cap);
|
Genode::env_context_area_ram_session()->free(ds_cap);
|
||||||
|
|
||||||
/* context area ready for reuse */
|
/* context area ready for reuse */
|
||||||
_context_allocator()->free(this);
|
_context_allocator()->free(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -211,9 +205,23 @@ void Thread_base::join()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void* Thread_base::alloc_secondary_stack(char const *name, size_t stack_size)
|
||||||
|
{
|
||||||
|
Context *context = _alloc_context(stack_size);
|
||||||
|
strncpy(context->name, name, sizeof(context->name));
|
||||||
|
return (void *)context->stack_top();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Thread_base::free_secondary_stack(void* stack_addr)
|
||||||
|
{
|
||||||
|
addr_t base = Context_allocator::addr_to_base(stack_addr);
|
||||||
|
_free_context(Context_allocator::base_to_context(base));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Thread_base::Thread_base(const char *name, size_t stack_size)
|
Thread_base::Thread_base(const char *name, size_t stack_size)
|
||||||
:
|
:
|
||||||
_list_element(this),
|
|
||||||
_context(_alloc_context(stack_size)),
|
_context(_alloc_context(stack_size)),
|
||||||
_join_lock(Lock::LOCKED)
|
_join_lock(Lock::LOCKED)
|
||||||
{
|
{
|
||||||
|
@ -225,5 +233,5 @@ Thread_base::Thread_base(const char *name, size_t stack_size)
|
||||||
Thread_base::~Thread_base()
|
Thread_base::~Thread_base()
|
||||||
{
|
{
|
||||||
_deinit_platform_thread();
|
_deinit_platform_thread();
|
||||||
_free_context();
|
_free_context(_context);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,15 +64,16 @@ class Routine : public Genode::List<Routine>::Element
|
||||||
/* will never return */
|
/* will never return */
|
||||||
if (!_started) {
|
if (!_started) {
|
||||||
_started = true;
|
_started = true;
|
||||||
_stack = (char *)dde_kit_simple_malloc(STACK_SIZE);
|
Genode::Thread_base *th = Genode::Thread_base::myself();
|
||||||
|
_stack = (char *) th->alloc_secondary_stack(_name, STACK_SIZE);
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
PDBG("Start func %s (%p) sp: %p", _name, _func, (_stack + STACK_SIZE));
|
PDBG("Start func %s (%p) sp: %p", _name, _func, _stack);
|
||||||
|
|
||||||
/* XXX move to platform code */
|
/* XXX move to platform code */
|
||||||
|
|
||||||
/* switch stack and call '_func(_arg)' */
|
/* switch stack and call '_func(_arg)' */
|
||||||
platform_execute((void *)(_stack + STACK_SIZE), (void *)_func, _arg);
|
platform_execute((void *)(_stack), (void *)_func, _arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* restore old state */
|
/* restore old state */
|
||||||
|
@ -122,7 +123,7 @@ class Routine : public Genode::List<Routine>::Element
|
||||||
~Routine()
|
~Routine()
|
||||||
{
|
{
|
||||||
if (_stack)
|
if (_stack)
|
||||||
dde_kit_simple_free(_stack);
|
Genode::Thread_base::myself()->free_secondary_stack(_stack);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue
Block a user