mirror of
https://github.com/genodelabs/genode.git
synced 2024-12-19 05:37:54 +00:00
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.
|
||||
*/
|
||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
||||
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 addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
};
|
||||
|
||||
struct Native_pd_args { };
|
||||
|
@ -78,13 +78,15 @@ namespace Genode {
|
||||
/**
|
||||
* Thread-context area configuration.
|
||||
*/
|
||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
||||
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 addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
};
|
||||
|
||||
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_
|
||||
#define _INCLUDE__BASE__NATIVE_TYPES_H_
|
||||
|
||||
#include <base/native_config.h>
|
||||
#include <base/cap_map.h>
|
||||
#include <base/stdint.h>
|
||||
|
||||
namespace Fiasco {
|
||||
#include <l4/sys/consts.h>
|
||||
@ -178,20 +178,6 @@ namespace Genode {
|
||||
|
||||
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 { };
|
||||
}
|
||||
|
||||
|
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/misc_math.h>
|
||||
|
||||
namespace Fiasco {
|
||||
#include <l4/sys/utcb.h>
|
||||
}
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
@ -41,7 +37,8 @@ namespace Genode {
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
for (; le; le = le->next())
|
||||
if (base_to_context(base) == le->object()->_context)
|
||||
return true;
|
||||
return (base - Native_config::context_area_virtual_base()) /
|
||||
Native_config::context_virtual_size();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* Find slot in context area for the new context
|
||||
*/
|
||||
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;
|
||||
try {
|
||||
return base_to_context(idx_to_base(_alloc.alloc()));
|
||||
} catch(Bit_allocator<MAX_THREADS>::Out_of_indices) {
|
||||
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);
|
||||
|
||||
_threads.remove(&thread_base->_list_element);
|
||||
|
||||
thread_base->_context->~Context();
|
||||
_alloc.free(base_to_idx(addr_to_base(context)));
|
||||
}
|
||||
|
||||
|
||||
@ -124,7 +113,8 @@ Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
|
||||
enum { PAGE_SIZE_LOG2 = 12 };
|
||||
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();
|
||||
|
||||
/*
|
||||
@ -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.
|
||||
*/
|
||||
addr_t ds_addr = Context_allocator::addr_to_base(context) + Native_config::context_virtual_size()
|
||||
- ds_size;
|
||||
addr_t ds_addr = Context_allocator::addr_to_base(context) +
|
||||
Native_config::context_virtual_size() -
|
||||
ds_size;
|
||||
|
||||
/* add padding for UTCB if defined for the platform */
|
||||
if (sizeof(Native_utcb) >= (1 << PAGE_SIZE_LOG2))
|
||||
@ -144,41 +135,47 @@ Thread_base::Context *Thread_base::_alloc_context(size_t stack_size)
|
||||
try {
|
||||
ds_cap = env_context_area_ram_session()->alloc(ds_size);
|
||||
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);
|
||||
|
||||
} catch (Ram_session::Alloc_failed) {
|
||||
throw Stack_alloc_failed();
|
||||
if (attach_addr != (addr_t)env_context_area_rm_session()->attach_at(ds_cap, attach_addr, ds_size))
|
||||
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
|
||||
* 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
|
||||
* 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->stack_base = ds_addr;
|
||||
context->ds_cap = ds_cap;
|
||||
|
||||
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();
|
||||
Ram_dataspace_capability ds_cap = _context->ds_cap;
|
||||
_context_allocator()->free(this);
|
||||
addr_t ds_addr = context->stack_base - Native_config::context_area_virtual_base();
|
||||
Ram_dataspace_capability ds_cap = context->ds_cap;
|
||||
|
||||
/* call de-constructor explicitly before memory gets detached */
|
||||
context->~Context();
|
||||
|
||||
Genode::env_context_area_rm_session()->detach((void *)ds_addr);
|
||||
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)
|
||||
{
|
||||
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)
|
||||
:
|
||||
_list_element(this),
|
||||
_context(_alloc_context(stack_size)),
|
||||
_join_lock(Lock::LOCKED)
|
||||
{
|
||||
@ -210,5 +221,5 @@ Thread_base::Thread_base(const char *name, size_t stack_size)
|
||||
Thread_base::~Thread_base()
|
||||
{
|
||||
_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
|
||||
|
||||
LD_TEXT_ADDR = 0x80100000
|
||||
|
@ -33,7 +33,6 @@ SRC_CC = cap_session_component.cc \
|
||||
signal_source_component.cc \
|
||||
trace_session_component.cc \
|
||||
thread_start.cc \
|
||||
thread_context_area.cc \
|
||||
core_printf.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/core/include \
|
||||
|
@ -37,13 +37,15 @@ namespace Genode {
|
||||
/**
|
||||
* Thread-context area configuration.
|
||||
*/
|
||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
||||
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 addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
};
|
||||
|
||||
struct Native_pd_args { };
|
||||
|
@ -106,13 +106,15 @@ namespace Genode
|
||||
/**
|
||||
* Thread-context area configuration.
|
||||
*/
|
||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
||||
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 addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
};
|
||||
|
||||
struct Native_pd_args { };
|
||||
|
@ -31,7 +31,6 @@ Native_utcb * Thread_base::utcb()
|
||||
{
|
||||
if (this) { return _tid.platform_thread->utcb_virt(); }
|
||||
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)
|
||||
:
|
||||
_list_element(this)
|
||||
{
|
||||
_tid.platform_thread = new (platform()->core_mem_alloc())
|
||||
Platform_thread(stack_size, Kernel::core_id(), label);
|
||||
|
@ -131,13 +131,15 @@ namespace Genode {
|
||||
* Please update platform-specific files after changing these
|
||||
* values, e.g., 'base-linux/src/platform/context_area.*.ld'.
|
||||
*/
|
||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
||||
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 addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
};
|
||||
|
||||
class Native_pd_args
|
||||
|
@ -402,8 +402,6 @@ void Thread_base::join()
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
@ -257,13 +257,15 @@ namespace Genode {
|
||||
/**
|
||||
* Thread-context area configuration.
|
||||
*/
|
||||
static addr_t context_area_virtual_base() { return 0xa0000000UL; }
|
||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
||||
static constexpr addr_t context_area_virtual_base() {
|
||||
return 0xa0000000UL; }
|
||||
static constexpr 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; }
|
||||
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
};
|
||||
|
||||
struct Native_pd_args { };
|
||||
|
@ -95,13 +95,15 @@ namespace Genode {
|
||||
/**
|
||||
* Thread-context area configuration.
|
||||
*/
|
||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
||||
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 addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
};
|
||||
|
||||
struct Native_pd_args { };
|
||||
|
@ -79,13 +79,15 @@ namespace Genode {
|
||||
/**
|
||||
* Thread-context area configuration.
|
||||
*/
|
||||
static addr_t context_area_virtual_base() { return 0x40000000UL; }
|
||||
static addr_t context_area_virtual_size() { return 0x10000000UL; }
|
||||
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 addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
static constexpr addr_t context_virtual_size() { return 0x00100000UL; }
|
||||
};
|
||||
|
||||
struct Native_pd_args { };
|
||||
|
@ -39,6 +39,9 @@
|
||||
* additional context members. Note that this memory is allocated from the RAM
|
||||
* session of the process environment and not accounted for when using the
|
||||
* '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/trace/logger.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 <cpu_session/cpu_session.h> /* for 'Thread_capability' type */
|
||||
|
||||
@ -80,15 +83,6 @@ namespace Genode {
|
||||
class Stack_too_large : 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
|
||||
*
|
||||
@ -169,8 +163,12 @@ namespace Genode {
|
||||
{
|
||||
private:
|
||||
|
||||
List<List_element<Thread_base> > _threads;
|
||||
Lock _threads_lock;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Detect if a context already exists at the specified address
|
||||
@ -191,7 +189,7 @@ namespace Genode {
|
||||
/**
|
||||
* Release thread context
|
||||
*/
|
||||
void free(Thread_base *thread);
|
||||
void free(Context *thread);
|
||||
|
||||
/**
|
||||
* Return 'Context' object for a given base address
|
||||
@ -202,6 +200,16 @@ namespace Genode {
|
||||
* Return base address of context containing the specified address
|
||||
*/
|
||||
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
|
||||
*/
|
||||
void _free_context();
|
||||
void _free_context(Context *context);
|
||||
|
||||
/**
|
||||
* Platform-specific thread-startup code
|
||||
@ -258,7 +266,7 @@ namespace Genode {
|
||||
Genode::Pager_capability _pager_cap;
|
||||
|
||||
/**
|
||||
* Pointer to corresponding thread context
|
||||
* Pointer to primary thread context
|
||||
*/
|
||||
Context *_context;
|
||||
|
||||
@ -326,6 +334,28 @@ namespace Genode {
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
@ -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();
|
||||
for (; le; le = le->next())
|
||||
if (base_to_context(base) == le->object()->_context)
|
||||
return true;
|
||||
return (base - Native_config::context_area_virtual_base()) /
|
||||
Native_config::context_virtual_size();
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
/*
|
||||
* Find slot in context area for the new context
|
||||
*/
|
||||
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;
|
||||
try {
|
||||
return base_to_context(idx_to_base(_alloc.alloc()));
|
||||
} catch(Bit_allocator<MAX_THREADS>::Out_of_indices) {
|
||||
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);
|
||||
|
||||
_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->stack_base = ds_addr;
|
||||
context->ds_cap = ds_cap;
|
||||
|
||||
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();
|
||||
Ram_dataspace_capability ds_cap = _context->ds_cap;
|
||||
addr_t ds_addr = context->stack_base - Native_config::context_area_virtual_base();
|
||||
Ram_dataspace_capability ds_cap = context->ds_cap;
|
||||
|
||||
/* 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_ram_session()->free(ds_cap);
|
||||
|
||||
/* 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)
|
||||
:
|
||||
_list_element(this),
|
||||
_context(_alloc_context(stack_size)),
|
||||
_join_lock(Lock::LOCKED)
|
||||
{
|
||||
@ -225,5 +233,5 @@ Thread_base::Thread_base(const char *name, size_t stack_size)
|
||||
Thread_base::~Thread_base()
|
||||
{
|
||||
_deinit_platform_thread();
|
||||
_free_context();
|
||||
_free_context(_context);
|
||||
}
|
||||
|
@ -64,15 +64,16 @@ class Routine : public Genode::List<Routine>::Element
|
||||
/* will never return */
|
||||
if (!_started) {
|
||||
_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)
|
||||
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 */
|
||||
|
||||
/* 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 */
|
||||
@ -122,7 +123,7 @@ class Routine : public Genode::List<Routine>::Element
|
||||
~Routine()
|
||||
{
|
||||
if (_stack)
|
||||
dde_kit_simple_free(_stack);
|
||||
Genode::Thread_base::myself()->free_secondary_stack(_stack);
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user