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:
Stefan Kalkowski 2014-01-24 12:06:21 +01:00 committed by Christian Helmuth
parent 66c5887bd3
commit 5447c406e5
25 changed files with 259 additions and 179 deletions

View File

@ -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 { };

View File

@ -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 { };

View 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_ */

View File

@ -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 { };
} }

View 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_ */

View File

@ -1,3 +0,0 @@
include $(REP_DIR)/lib/mk/base.inc
SRC_CC += thread/thread_context_area.cc

View File

@ -1,3 +0,0 @@
include $(REP_DIR)/lib/mk/base.inc
SRC_CC += thread/arndale/thread_context_area.cc

View File

@ -1,3 +0,0 @@
include $(REP_DIR)/lib/mk/base.inc
SRC_CC += thread/thread_context_area.cc

View File

@ -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; }

View File

@ -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);
} }

View File

@ -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; }

View File

@ -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

View File

@ -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 \

View File

@ -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 { };

View File

@ -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 { };

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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 { };

View File

@ -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 { };

View File

@ -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 { };

View File

@ -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
*/ */

View File

@ -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);
} }

View File

@ -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);
} }
/** /**