From 3f9b098b70e1d3f96ad64e602f7dcaf64bb3eef6 Mon Sep 17 00:00:00 2001 From: Martin Stein Date: Wed, 26 Feb 2014 16:47:54 +0100 Subject: [PATCH] base: provide Thread_base::stack_size(size_t) The new method enhances the stack of the targeted thread if it is smaller than a given size. ref #1075 --- base-foc/src/base/thread/thread.cc | 34 ++++++++++++++++++++++++++++++ base/include/base/thread.h | 20 ++++++++++++++++++ base/src/base/thread/thread.cc | 34 ++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+) diff --git a/base-foc/src/base/thread/thread.cc b/base-foc/src/base/thread/thread.cc index fd06c7155..a09c38d98 100644 --- a/base-foc/src/base/thread/thread.cc +++ b/base-foc/src/base/thread/thread.cc @@ -31,6 +31,40 @@ namespace Genode { } +void Thread_base::Context::stack_size(size_t const size) +{ + /* check if the stack needs to be enhanced */ + size_t const stack_size = (addr_t)_stack - stack_base; + if (stack_size >= size) { return; } + + /* check if the stack enhancement fits the context region */ + enum { + CONTEXT_SIZE = Native_config::context_virtual_size(), + CONTEXT_AREA_BASE = Native_config::context_area_virtual_base(), + UTCB_SIZE = sizeof(Native_utcb), + PAGE_SIZE_LOG2 = 12, + PAGE_SIZE = (1UL << PAGE_SIZE_LOG2), + }; + addr_t const context_base = Context_allocator::addr_to_base(this); + size_t const ds_size = align_addr(size - stack_size, PAGE_SIZE_LOG2); + if (stack_base - ds_size < context_base) { throw Stack_too_large(); } + + /* allocate and attach backing store for the stack enhancement */ + addr_t const ds_addr = stack_base - ds_size - CONTEXT_AREA_BASE; + try { + Ram_session * const ram = env_context_area_ram_session(); + Ram_dataspace_capability const ds_cap = ram->alloc(ds_size); + Rm_session * const rm = env_context_area_rm_session(); + void * const attach_addr = rm->attach_at(ds_cap, ds_addr, ds_size); + if (ds_addr != (addr_t)attach_addr) { throw Stack_alloc_failed(); } + } + catch (Ram_session::Alloc_failed) { throw Stack_alloc_failed(); } + + /* update context information */ + stack_base -= ds_size; +} + + Thread_base::Context * Thread_base::_alloc_context(size_t stack_size, bool main_thread) { diff --git a/base/include/base/thread.h b/base/include/base/thread.h index 7fbb96845..61e357a91 100644 --- a/base/include/base/thread.h +++ b/base/include/base/thread.h @@ -112,6 +112,16 @@ namespace Genode { return ((addr_t)_stack & ~0xf) - Abi::stack_adjustment(); } + /** + * Ensure that the stack has a given size at the minimum + * + * \param size minimum stack size + * + * \throw Stack_too_large + * \throw Stack_alloc_failed + */ + void stack_size(size_t const size); + /** * Virtual address of the start of the stack * @@ -421,6 +431,16 @@ namespace Genode { */ static Thread_base *myself(); + /** + * Ensure that the stack has a given size at the minimum + * + * \param size minimum stack size + * + * \throw Context::Stack_too_large + * \throw Context::Stack_alloc_failed + */ + void stack_size(size_t const size) { _context->stack_size(size); } + /** * Return user-level thread control block * diff --git a/base/src/base/thread/thread.cc b/base/src/base/thread/thread.cc index 71aa008cc..dae638ba3 100644 --- a/base/src/base/thread/thread.cc +++ b/base/src/base/thread/thread.cc @@ -31,6 +31,40 @@ namespace Genode { } +void Thread_base::Context::stack_size(size_t const size) +{ + /* check if the stack needs to be enhanced */ + size_t const stack_size = (addr_t)_stack - stack_base; + if (stack_size >= size) { return; } + + /* check if the stack enhancement fits the context region */ + enum { + CONTEXT_SIZE = Native_config::context_virtual_size(), + CONTEXT_AREA_BASE = Native_config::context_area_virtual_base(), + UTCB_SIZE = sizeof(Native_utcb), + PAGE_SIZE_LOG2 = 12, + PAGE_SIZE = (1UL << PAGE_SIZE_LOG2), + }; + addr_t const context_base = Context_allocator::addr_to_base(this); + size_t const ds_size = align_addr(size - stack_size, PAGE_SIZE_LOG2); + if (stack_base - ds_size < context_base) { throw Stack_too_large(); } + + /* allocate and attach backing store for the stack enhancement */ + addr_t const ds_addr = stack_base - ds_size - CONTEXT_AREA_BASE; + try { + Ram_session * const ram = env_context_area_ram_session(); + Ram_dataspace_capability const ds_cap = ram->alloc(ds_size); + Rm_session * const rm = env_context_area_rm_session(); + void * const attach_addr = rm->attach_at(ds_cap, ds_addr, ds_size); + if (ds_addr != (addr_t)attach_addr) { throw Stack_alloc_failed(); } + } + catch (Ram_session::Alloc_failed) { throw Stack_alloc_failed(); } + + /* update context information */ + stack_base -= ds_size; +} + + Thread_base::Context * Thread_base::_alloc_context(size_t stack_size, bool main_thread) {