genode/repos/base/src/lib/base/thread.cc
Norman Feske aa66b5d62f base: remove dependency from deprecated APIs
This patch adjusts the implementation of the base library and core such
that the code no longer relies on deprecated APIs except for very few
cases, mainly to keep those deprecated APIs in tact for now.

The most prominent changes are:

- Removing the use of base/printf.h

- Removing of the log backend for printf. The 'Console' with the
  format-string parser is still there along with 'snprintf.h' because
  the latter is still used at a few places, most prominently the
  'Connection' classes.

- Removing the notion of a RAM session, which does not exist in
  Genode anymore. Still the types were preserved (by typedefs to
  PD session) to keep up compatibility. But this transition should
  come to an end now.

- Slight rennovation of core's tracing service, e.g., the use of an
  Attached_dataspace as the Argument_buffer.

- Reducing the reliance on global accessors like deprecated_env() or
  core_env(). Still there is a longish way to go to eliminate all such
  calls. A useful pattern (or at least a stop-gap solution) is to
  pass the 'Env' to the individual compilation units via init functions.

- Avoiding the use of the old 'Child_policy::resolve_session_request'
  interface that returned a 'Service' instead of a 'Route'.

Issue #1987
2019-02-19 11:08:17 +01:00

263 lines
7.0 KiB
C++

/*
* \brief Implementation of the Thread API
* \author Norman Feske
* \date 2010-01-11
*/
/*
* Copyright (C) 2010-2017 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
/* Genode includes */
#include <util/construct_at.h>
#include <util/string.h>
#include <util/misc_math.h>
#include <base/thread.h>
#include <base/env.h>
#include <base/sleep.h>
#include <base/snprintf.h>
#include <deprecated/env.h>
/* base-internal includes */
#include <base/internal/stack_allocator.h>
#include <base/internal/globals.h>
using namespace Genode;
void Stack::size(size_t const size)
{
/* check if the stack needs to be enhanced */
size_t const stack_size = (addr_t)_stack - _base;
if (stack_size >= size) { return; }
/* check if the stack enhancement fits the stack region */
enum {
UTCB_SIZE = sizeof(Native_utcb),
PAGE_SIZE_LOG2 = 12,
PAGE_SIZE = (1UL << PAGE_SIZE_LOG2),
};
addr_t const stack_slot_base = Stack_allocator::addr_to_base(this);
size_t const ds_size = align_addr(size - stack_size, PAGE_SIZE_LOG2);
if (_base - ds_size < stack_slot_base)
throw Thread::Stack_too_large();
/* allocate and attach backing store for the stack enhancement */
addr_t const ds_addr = _base - ds_size - stack_area_virtual_base();
try {
Ram_allocator * const ram = env_stack_area_ram_allocator;
Ram_dataspace_capability const ds_cap = ram->alloc(ds_size);
Region_map * const rm = env_stack_area_region_map;
void * const attach_addr = rm->attach_at(ds_cap, ds_addr, ds_size);
if (ds_addr != (addr_t)attach_addr)
throw Thread::Out_of_stack_space();
}
catch (Out_of_ram) { throw Thread::Stack_alloc_failed(); }
/* update stack information */
_base -= ds_size;
}
Stack *
Thread::_alloc_stack(size_t stack_size, char const *name, bool main_thread)
{
/* allocate stack */
Stack *stack = Stack_allocator::stack_allocator().alloc(this, main_thread);
if (!stack)
throw Out_of_stack_space();
/* determine size of dataspace to allocate for the stack */
enum { PAGE_SIZE_LOG2 = 12 };
size_t ds_size = align_addr(stack_size, PAGE_SIZE_LOG2);
if (stack_size >= stack_virtual_size() -
sizeof(Native_utcb) - (1UL << PAGE_SIZE_LOG2))
throw Stack_too_large();
/*
* Calculate base address of the stack
*
* The stack pointer is always located at the top of the stack header.
*/
addr_t ds_addr = Stack_allocator::addr_to_base(stack) +
stack_virtual_size() - ds_size;
/* add padding for UTCB if defined for the platform */
if (sizeof(Native_utcb) >= (1 << PAGE_SIZE_LOG2))
ds_addr -= sizeof(Native_utcb);
/* allocate and attach backing store for the stack */
Ram_dataspace_capability ds_cap;
try {
ds_cap = env_stack_area_ram_allocator->alloc(ds_size);
addr_t attach_addr = ds_addr - stack_area_virtual_base();
if (attach_addr != (addr_t)env_stack_area_region_map->attach_at(ds_cap, attach_addr, ds_size))
throw Stack_alloc_failed();
}
catch (Out_of_ram) { throw Stack_alloc_failed(); }
/*
* Now the stack is backed by memory, so it is safe to access its members.
*
* We need to initialize the stack 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.
*/
construct_at<Stack>(stack, name, *this, ds_addr, ds_cap);
Abi::init_stack(stack->top());
return stack;
}
void Thread::_free_stack(Stack *stack)
{
addr_t ds_addr = stack->base() - stack_area_virtual_base();
Ram_dataspace_capability ds_cap = stack->ds_cap();
/* call de-constructor explicitly before memory gets detached */
stack->~Stack();
Genode::env_stack_area_region_map->detach((void *)ds_addr);
Genode::env_stack_area_ram_allocator->free(ds_cap);
/* stack ready for reuse */
Stack_allocator::stack_allocator().free(stack);
}
void Thread::name(char *dst, size_t dst_len)
{
snprintf(dst, dst_len, "%s", _stack->name().string());
}
Thread::Name Thread::name() const { return _stack->name(); }
void Thread::join() { _join_lock.lock(); }
void *Thread::alloc_secondary_stack(char const *name, size_t stack_size)
{
Stack *stack = _alloc_stack(stack_size, name, false);
return (void *)stack->top();
}
void Thread::free_secondary_stack(void* stack_addr)
{
addr_t base = Stack_allocator::addr_to_base(stack_addr);
_free_stack(Stack_allocator::base_to_stack(base));
}
Native_thread &Thread::native_thread() {
return _stack->native_thread(); }
void *Thread::stack_top() const { return (void *)_stack->top(); }
void *Thread::stack_base() const { return (void*)_stack->base(); }
void Thread::stack_size(size_t const size) { _stack->size(size); }
Thread::Stack_info Thread::mystack()
{
addr_t base = Stack_allocator::addr_to_base(&base);
Stack *stack = Stack_allocator::base_to_stack(base);
return { stack->base(), stack->top() };
}
size_t Thread::stack_virtual_size()
{
return Genode::stack_virtual_size();
}
addr_t Thread::stack_area_virtual_base()
{
return Genode::stack_area_virtual_base();
}
size_t Thread::stack_area_virtual_size()
{
return Genode::stack_area_virtual_size();
}
Thread::Thread(size_t weight, const char *name, size_t stack_size,
Type type, Cpu_session *cpu_session, Affinity::Location affinity)
:
_cpu_session(cpu_session),
_affinity(affinity),
_trace_control(nullptr),
_stack(type == REINITIALIZED_MAIN ?
_stack : _alloc_stack(stack_size, name, type == MAIN)),
_join_lock(Lock::LOCKED)
{
_init_platform_thread(weight, type);
}
void Thread::_init_cpu_session_and_trace_control()
{
/* if no CPU session is given, use it from the environment */
if (!_cpu_session) {
_cpu_session = env_deprecated()->cpu_session(); }
/* initialize trace control now that the CPU session must be valid */
Dataspace_capability ds = _cpu_session->trace_control();
if (ds.valid()) {
_trace_control = env_deprecated()->rm_session()->attach(ds); }
}
Thread::Thread(size_t weight, const char *name, size_t stack_size,
Type type, Affinity::Location affinity)
: Thread(weight, name, stack_size, type, nullptr, affinity) { }
Thread::Thread(Env &env, Name const &name, size_t stack_size, Location location,
Weight weight, Cpu_session &cpu)
: Thread(weight.value, name.string(), stack_size, NORMAL,
&cpu == &env.cpu() ? nullptr : &cpu, location)
{ }
Thread::Thread(Env &env, Name const &name, size_t stack_size)
: Thread(env, name, stack_size, Location(), Weight(), env.cpu()) { }
Thread::~Thread()
{
if (Thread::myself() == this) {
error("thread '", _stack->name().string(), "' "
"tried to self de-struct - sleeping forever.");
sleep_forever();
}
_deinit_platform_thread();
_free_stack(_stack);
/*
* We have to detach the trace control dataspace last because
* we cannot invalidate the pointer used by the Trace::Logger
* from here and any following RPC call will stumple upon the
* detached trace control dataspace.
*/
if (_trace_control)
env_deprecated()->rm_session()->detach(_trace_control);
}