Thread API cleanup

This patch cleans up the thread API and comes with the following
noteworthy changes:

- Introduced Cpu_session::Weight type that replaces a formerly used
  plain integer value to prevent the accidental mix-up of
  arguments.
- The enum definition of Cpu_session::DEFAULT_WEIGHT moved to
  Cpu_session::Weight::DEFAULT_WEIGHT
- New Thread constructor that takes a 'Env &' as first argument.
  The original constructors are now marked as deprecated. For the
  common use case where the default 'Weight' and 'Affinity' are
  used, a shortcut is provided. In the long term, those two
  constructors should be the only ones to remain.
- The former 'Thread<>' class template has been renamed to
  'Thread_deprecated'.
- The former 'Thread_base' class is now called 'Thread'.
- The new 'name()' accessor returns the thread's name as 'Name'
  object as centrally defined via 'Cpu_session::Name'. It is meant to
  replace the old-fashioned 'name' method that takes a buffer and size
  as arguments.
- Adaptation of the thread test to the new API

Issue #1954
This commit is contained in:
Norman Feske
2016-05-04 12:27:17 +02:00
committed by Christian Helmuth
parent 7b73d1d823
commit fd401bdf53
211 changed files with 980 additions and 843 deletions

View File

@ -35,27 +35,27 @@ void Cpu_thread_component::update_exception_sigh()
Thread_capability Cpu_session_component::create_thread(Capability<Pd_session> pd_cap,
size_t weight,
Name const &name,
Affinity::Location affinity,
Weight weight,
addr_t utcb)
{
Trace::Thread_name thread_name(name.string());
Cpu_thread_component *thread = 0;
if (weight == 0) {
if (weight.value == 0) {
PWRN("Thread %s: Bad weight 0, using %i instead.",
name.string(), DEFAULT_WEIGHT);
weight = DEFAULT_WEIGHT;
name.string(), Weight::DEFAULT_WEIGHT);
weight = Weight();
}
if (weight > QUOTA_LIMIT) {
if (weight.value > QUOTA_LIMIT) {
PWRN("Thread %s: Oversized weight %zu, using %i instead.",
name.string(), weight, QUOTA_LIMIT);
weight = QUOTA_LIMIT;
name.string(), weight.value, QUOTA_LIMIT);
weight = Weight(QUOTA_LIMIT);
}
Lock::Guard thread_list_lock_guard(_thread_list_lock);
_incr_weight(weight);
_incr_weight(weight.value);
/*
* Create thread associated with its protection domain
@ -69,7 +69,7 @@ Thread_capability Cpu_session_component::create_thread(Capability<Pd_session> pd
thread = new (&_thread_alloc)
Cpu_thread_component(
cap(), *_thread_ep, *_pager_ep, *pd, _trace_control_area,
weight, _weight_to_quota(weight),
weight, _weight_to_quota(weight.value),
_thread_affinity(affinity), _label, thread_name,
_priority, utcb, _default_exception_handler);
};

View File

@ -60,7 +60,7 @@ namespace Genode {
Pager_entrypoint &_pager_ep;
Capability<Pd_session> _pd;
Region_map_component &_address_space_region_map;
size_t const _weight;
Cpu_session::Weight const _weight;
Session_label const _session_label;
Thread_name const _name;
Platform_thread _platform_thread;
@ -116,7 +116,8 @@ namespace Genode {
* \param pager_ep pager entrypoint used for handling the page
* faults of the thread
* \param pd PD session where the thread is executed
* \param weight weighting regarding the CPU session quota
* \param weight scheduling weight relative to the other
* threads of the same CPU session
* \param quota initial quota counter-value of the weight
* \param labal label of the threads session
* \param name name for the thread
@ -124,24 +125,25 @@ namespace Genode {
* \param utcb user-local UTCB base
* \param sigh initial exception handler
*/
Cpu_thread_component(Cpu_session_capability cpu_session_cap,
Rpc_entrypoint &ep,
Pager_entrypoint &pager_ep,
Pd_session_component &pd,
Trace::Control_area &trace_control_area,
size_t const weight,
size_t const quota,
Affinity::Location affinity,
Session_label const &label,
Thread_name const &name,
unsigned priority, addr_t utcb,
Cpu_thread_component(Cpu_session_capability cpu_session_cap,
Rpc_entrypoint &ep,
Pager_entrypoint &pager_ep,
Pd_session_component &pd,
Trace::Control_area &trace_control_area,
Cpu_session::Weight weight,
size_t quota,
Affinity::Location location,
Session_label const &label,
Thread_name const &name,
unsigned priority,
addr_t utcb,
Signal_context_capability sigh)
:
_ep(ep), _pager_ep(pager_ep), _pd(pd.cap()),
_address_space_region_map(pd.address_space_region_map()),
_weight(weight),
_session_label(label), _name(name),
_platform_thread(quota, name.string(), priority, affinity, utcb),
_platform_thread(quota, name.string(), priority, location, utcb),
_bound_to_pd(_bind_to_pd(pd)),
_sigh(sigh),
_trace_control_slot(trace_control_area),
@ -195,7 +197,7 @@ namespace Genode {
Trace::Source *trace_source() { return &_trace_source; }
size_t weight() const { return _weight; }
size_t weight() const { return _weight.value; }
void sigh(Signal_context_capability sigh)
{
@ -340,8 +342,8 @@ namespace Genode {
** CPU session interface **
***************************/
Thread_capability create_thread(Capability<Pd_session>, size_t, Name const &,
Affinity::Location, addr_t) override;
Thread_capability create_thread(Capability<Pd_session>, Name const &,
Affinity::Location, Weight, addr_t) override;
Ram_dataspace_capability utcb(Thread_capability thread) override;
void kill_thread(Thread_capability) override;
int start(Thread_capability, addr_t, addr_t) override;

View File

@ -18,7 +18,7 @@
namespace Genode { class Irq_object; }
class Genode::Irq_object : public Thread<4096> {
class Genode::Irq_object : public Thread_deprecated<4096> {
private:

View File

@ -141,7 +141,7 @@ class Genode::Pager_object : public Object_pool<Pager_object>::Entry
class Genode::Pager_entrypoint : public Object_pool<Pager_object>,
public Thread<PAGER_EP_STACK_SIZE>
public Thread_deprecated<PAGER_EP_STACK_SIZE>
{
private:
@ -161,7 +161,7 @@ class Genode::Pager_entrypoint : public Object_pool<Pager_object>,
*/
Pager_entrypoint(Rpc_cap_factory &cap_factory)
:
Thread<PAGER_EP_STACK_SIZE>("pager_ep"),
Thread_deprecated<PAGER_EP_STACK_SIZE>("pager_ep"),
_cap_factory(cap_factory)
{ start(); }

View File

@ -22,6 +22,9 @@
#include <rom_session/connection.h>
#include <cpu_session/connection.h>
/* base-internal includes */
#include <base/internal/globals.h>
/* core includes */
#include <platform.h>
#include <core_env.h>
@ -195,7 +198,7 @@ class Core_child : public Child_policy
* the creation of regular threads within core is unsupported.
*/
namespace Genode { void init_signal_thread() { } }
namespace Genode { void init_signal_thread(Env &) { } }
/*******************

View File

@ -40,13 +40,13 @@ struct Genode::Expanding_cpu_session_client : Upgradeable_client<Genode::Cpu_ses
{ }
Thread_capability
create_thread(Pd_session_capability pd, size_t quota, Name const &name,
Affinity::Location location, addr_t utcb)
create_thread(Pd_session_capability pd, Name const &name,
Affinity::Location location, Weight weight, addr_t utcb) override
{
return retry<Cpu_session::Out_of_metadata>(
[&] () {
return Cpu_session_client::create_thread(pd, quota, name,
location, utcb); },
return Cpu_session_client::create_thread(pd, name, location,
weight, utcb); },
[&] () { upgrade_ram(8*1024); });
}
};

View File

@ -21,11 +21,12 @@ namespace Genode {
class Region_map;
class Ram_session;
class Env;
extern Region_map *env_stack_area_region_map;
extern Ram_session *env_stack_area_ram_session;
void init_signal_thread();
void init_signal_thread(Env &);
void init_log();
}

View File

@ -30,14 +30,14 @@
* data shared between the user-level thread and the kernel. It is typically
* used for transferring IPC message payload or for system-call arguments.
* The additional stack members are a reference to the corresponding
* 'Thread_base' object and the name of the thread.
* 'Thread' object and the name of the thread.
*
* The stack area is a virtual memory area, initially not backed by real
* memory. When a new thread is created, an empty slot gets assigned to the new
* thread and populated with memory pages for the stack and thread-specific
* data. Note that this memory is allocated from the RAM session of the
* component environment and not accounted for when using the 'sizeof()'
* operand on a 'Thread_base' object.
* operand on a 'Thread' 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.
@ -58,6 +58,7 @@
#include <base/native_types.h> /* for 'Native_utcb' */
#include <cpu/consts.h>
#include <ram_session/ram_session.h> /* for 'Ram_dataspace_capability' type */
#include <cpu_session/cpu_session.h> /* for 'Cpu_session::Name' type */
/* base-internal includes */
#include <base/internal/native_utcb.h>
@ -75,7 +76,7 @@ class Genode::Stack
{
public:
typedef String<64> Name;
typedef Cpu_session::Name Name;
private:
@ -93,9 +94,9 @@ class Genode::Stack
Name const _name;
/**
* Pointer to corresponding 'Thread_base' object
* Pointer to corresponding 'Thread' object
*/
Thread_base &_thread;
Thread &_thread;
/**
* Virtual address of the start of the stack
@ -135,7 +136,7 @@ class Genode::Stack
/**
* Constructor
*/
Stack(Name const &name, Thread_base &thread, addr_t base,
Stack(Name const &name, Thread &thread, addr_t base,
Ram_dataspace_capability ds_cap)
:
_name(name), _thread(thread), _base(base), _ds_cap(ds_cap)
@ -179,9 +180,9 @@ class Genode::Stack
Name name() const { return _name; }
/**
* Return 'Thread_base' object of the stack's thread
* Return 'Thread' object of the stack's thread
*/
Thread_base &thread() { return _thread; }
Thread &thread() { return _thread; }
/**
* Return dataspace used as the stack's backing storage

View File

@ -59,7 +59,7 @@ class Genode::Stack_allocator
* \return virtual address of new stack, or
* 0 if the allocation failed
*/
Stack *alloc(Thread_base *thread, bool main_thread);
Stack *alloc(Thread *thread, bool main_thread);
/**
* Release stack

View File

@ -167,7 +167,7 @@ Child::Process::Initial_thread::Initial_thread(Cpu_session &cpu,
char const *name)
:
cpu(cpu),
cap(cpu.create_thread(pd, Cpu_session::DEFAULT_WEIGHT, name))
cap(cpu.create_thread(pd, name, Affinity::Location(), Cpu_session::Weight()))
{ }

View File

@ -12,11 +12,14 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <base/entrypoint.h>
#include <base/component.h>
#include <cap_session/connection.h>
#include <util/retry.h>
/* base-internal includes */
#include <base/internal/globals.h>
using namespace Genode;
@ -27,7 +30,6 @@ namespace Genode {
extern bool inhibit_tracing;
void call_global_static_constructors();
void init_signal_thread();
void destroy_signal_thread();
extern void (*call_component_construct)(Genode::Env &);
@ -76,7 +78,7 @@ void Entrypoint::_process_incoming_signals()
/* execute fork magic in noux plugin */
_suspended_callback();
init_signal_thread();
init_signal_thread(_env);
_rpc_ep.construct(&_env.pd(), Component::stack_size(), Component::name());
_signal_proxy_cap = manage(_signal_proxy);
_sig_rec.construct();
@ -155,7 +157,7 @@ Entrypoint::Entrypoint(Env &env)
_rpc_ep(&env.pd(), Component::stack_size(), Component::name())
{
/* initialize signalling after initializing but before calling the entrypoint */
init_signal_thread();
init_signal_thread(_env);
/*
* Invoke Component::construct function in the context of the entrypoint.
@ -186,6 +188,6 @@ Entrypoint::Entrypoint(Env &env, size_t stack_size, char const *name)
_env(env),
_rpc_ep(&env.pd(), stack_size, name)
{
_signal_proxy_thread.construct(*this);
_signal_proxy_thread.construct(env, *this);
}

View File

@ -21,13 +21,13 @@
using namespace Genode;
static inline Genode::Thread_base *invalid_thread_base()
static inline Genode::Thread *invalid_thread_base()
{
return (Genode::Thread_base*)~0;
return (Genode::Thread*)~0;
}
static inline bool thread_base_valid(Genode::Thread_base *thread_base)
static inline bool thread_base_valid(Genode::Thread *thread_base)
{
return (thread_base != invalid_thread_base());
}
@ -62,7 +62,7 @@ void Cancelable_lock::Applicant::wake_up()
void Cancelable_lock::lock()
{
Applicant myself(Thread_base::myself());
Applicant myself(Thread::myself());
spinlock_lock(&_spinlock_state);

View File

@ -60,7 +60,7 @@ void Rpc_entrypoint::activate()
bool Rpc_entrypoint::is_myself() const
{
return (Thread_base::myself() == this);
return (Thread::myself() == this);
}
@ -68,13 +68,13 @@ Rpc_entrypoint::Rpc_entrypoint(Pd_session *pd_session, size_t stack_size,
char const *name, bool start_on_construction,
Affinity::Location location)
:
Thread_base(Cpu_session::DEFAULT_WEIGHT, name, stack_size, location),
Thread(Cpu_session::Weight::DEFAULT_WEIGHT, name, stack_size, location),
_cap(Untyped_capability()),
_cap_valid(Lock::LOCKED), _delay_start(Lock::LOCKED),
_delay_exit(Lock::LOCKED),
_pd_session(*pd_session)
{
Thread_base::start();
Thread::start();
_block_until_cap_valid();
if (start_on_construction)

View File

@ -11,6 +11,7 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <util/retry.h>
#include <base/env.h>
#include <base/signal.h>
@ -20,11 +21,12 @@
#include <signal_source/client.h>
#include <util/volatile_object.h>
/* base-internal includes */
#include <base/internal/globals.h>
using namespace Genode;
enum { STACK_SIZE = 4*1024*sizeof(addr_t) };
class Signal_handler_thread : Thread<STACK_SIZE>, Lock
class Signal_handler_thread : Thread, Lock
{
private:
@ -44,13 +46,15 @@ class Signal_handler_thread : Thread<STACK_SIZE>, Lock
Signal_receiver::dispatch_signals(&(*_signal_source));
}
enum { STACK_SIZE = 4*1024*sizeof(addr_t) };
public:
/**
* Constructor
*/
Signal_handler_thread()
: Thread<STACK_SIZE>("signal handler"), Lock(Lock::LOCKED)
Signal_handler_thread(Env &env)
: Thread(env, "signal handler", STACK_SIZE), Lock(Lock::LOCKED)
{
start();
@ -92,10 +96,10 @@ namespace Genode {
* We allow this function to be overridden in to enable core to omit the
* creation of the signal thread.
*/
void init_signal_thread() __attribute__((weak));
void init_signal_thread()
void init_signal_thread(Env &env) __attribute__((weak));
void init_signal_thread(Env &env)
{
signal_handler_thread().construct();
signal_handler_thread().construct(env);
}
void destroy_signal_thread()

View File

@ -45,7 +45,7 @@ addr_t Stack_allocator::idx_to_base(size_t idx)
Stack *
Stack_allocator::alloc(Thread_base *thread_base, bool main_thread)
Stack_allocator::alloc(Thread *thread_base, bool main_thread)
{
if (main_thread)
/* the main-thread stack is the first one */

View File

@ -52,7 +52,7 @@ void Stack::size(size_t const size)
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_base::Stack_too_large();
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();
@ -63,10 +63,10 @@ void Stack::size(size_t const size)
void * const attach_addr = rm->attach_at(ds_cap, ds_addr, ds_size);
if (ds_addr != (addr_t)attach_addr)
throw Thread_base::Out_of_stack_space();
throw Thread::Out_of_stack_space();
}
catch (Ram_session::Alloc_failed) {
throw Thread_base::Stack_alloc_failed();
throw Thread::Stack_alloc_failed();
}
/* update stack information */
@ -75,7 +75,7 @@ void Stack::size(size_t const size)
Stack *
Thread_base::_alloc_stack(size_t stack_size, char const *name, bool main_thread)
Thread::_alloc_stack(size_t stack_size, char const *name, bool main_thread)
{
/*
* Synchronize stack list when creating new threads from multiple threads
@ -134,7 +134,7 @@ Thread_base::_alloc_stack(size_t stack_size, char const *name, bool main_thread)
}
void Thread_base::_free_stack(Stack *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();
@ -150,63 +150,66 @@ void Thread_base::_free_stack(Stack *stack)
}
void Thread_base::name(char *dst, size_t dst_len)
void Thread::name(char *dst, size_t dst_len)
{
snprintf(dst, dst_len, "%s", _stack->name().string());
}
void Thread_base::join() { _join_lock.lock(); }
Thread::Name Thread::name() const { return _stack->name(); }
void *Thread_base::alloc_secondary_stack(char const *name, size_t stack_size)
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_base::free_secondary_stack(void* stack_addr)
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_base::native_thread() {
Native_thread &Thread::native_thread() {
return _stack->native_thread(); }
void *Thread_base::stack_top() const { return (void *)_stack->top(); }
void *Thread::stack_top() const { return (void *)_stack->top(); }
void *Thread_base::stack_base() const { return (void*)_stack->base(); }
void *Thread::stack_base() const { return (void*)_stack->base(); }
void Thread_base::stack_size(size_t const size) { _stack->size(size); }
void Thread::stack_size(size_t const size) { _stack->size(size); }
size_t Thread_base::stack_virtual_size()
size_t Thread::stack_virtual_size()
{
return Genode::stack_virtual_size();
}
addr_t Thread_base::stack_area_virtual_base()
addr_t Thread::stack_area_virtual_base()
{
return Genode::stack_area_virtual_base();
}
size_t Thread_base::stack_area_virtual_size()
size_t Thread::stack_area_virtual_size()
{
return Genode::stack_area_virtual_size();
}
Thread_base::Thread_base(size_t weight, const char *name, size_t stack_size,
Type type, Cpu_session *cpu_session, Affinity::Location affinity)
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),
@ -225,14 +228,25 @@ Thread_base::Thread_base(size_t weight, const char *name, size_t stack_size,
}
Thread_base::Thread_base(size_t weight, const char *name, size_t stack_size,
Type type, Affinity::Location affinity)
: Thread_base(weight, name, stack_size, type, nullptr, affinity) { }
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_base::~Thread_base()
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_base::myself() == this) {
if (Thread::myself() == this) {
PERR("thread '%s' tried to self de-struct - sleeping forever.",
_stack->name().string());
sleep_forever();

View File

@ -15,4 +15,4 @@
using namespace Genode;
void Thread_base::_thread_bootstrap() { }
void Thread::_thread_bootstrap() { }

View File

@ -19,7 +19,7 @@
#include <base/internal/stack_area.h>
Genode::Thread_base *Genode::Thread_base::myself()
Genode::Thread *Genode::Thread::myself()
{
int dummy = 0; /* used for determining the stack pointer */

View File

@ -26,20 +26,20 @@ using namespace Genode;
/**
* Entry point entered by new threads
*/
void Thread_base::_thread_start()
void Thread::_thread_start()
{
Thread_base::myself()->_thread_bootstrap();
Thread_base::myself()->entry();
Thread_base::myself()->_join_lock.unlock();
Thread::myself()->_thread_bootstrap();
Thread::myself()->entry();
Thread::myself()->_join_lock.unlock();
Genode::sleep_forever();
}
/*****************
** Thread base **
*****************/
/************
** Thread **
************/
void Thread_base::_deinit_platform_thread()
void Thread::_deinit_platform_thread()
{
if (!_cpu_session)
_cpu_session = env()->cpu_session();
@ -48,19 +48,16 @@ void Thread_base::_deinit_platform_thread()
}
void Thread_base::start()
void Thread::start()
{
/* if no cpu session is given, use it from the environment */
/* if no CPU session is given, use it from the environment */
if (!_cpu_session)
_cpu_session = env()->cpu_session();
/* create thread at core */
char buf[48];
name(buf, sizeof(buf));
enum { WEIGHT = Cpu_session::DEFAULT_WEIGHT };
addr_t const utcb = (addr_t)&_stack->utcb();
_thread_cap = _cpu_session->create_thread(env()->pd_session_cap(),
WEIGHT, buf, _affinity, utcb);
_thread_cap = _cpu_session->create_thread(env()->pd_session_cap(), name(),
_affinity, Weight(), utcb);
if (!_thread_cap.valid())
throw Cpu_session::Thread_creation_failed();
@ -69,7 +66,7 @@ void Thread_base::start()
}
void Thread_base::cancel_blocking()
void Thread::cancel_blocking()
{
_cpu_session->cancel_blocking(_thread_cap);
}

View File

@ -163,9 +163,9 @@ Trace::Logger::Logger()
{ }
/*****************
** Thread_base **
*****************/
/************
** Thread **
************/
/**
* return logger instance for the main thread **
@ -180,12 +180,12 @@ static Trace::Logger *main_trace_logger()
static Trace::Control *main_trace_control;
Trace::Logger *Thread_base::_logger()
Trace::Logger *Thread::_logger()
{
if (inhibit_tracing)
return 0;
Thread_base * const myself = Thread_base::myself();
Thread * const myself = Thread::myself();
Trace::Logger * const logger = myself ? &myself->_trace_logger
: main_trace_logger();

View File

@ -19,4 +19,4 @@
#include <base/internal/native_utcb.h>
Genode::Native_utcb *Genode::Thread_base::utcb() { return &_stack->utcb(); }
Genode::Native_utcb *Genode::Thread::utcb() { return &_stack->utcb(); }

View File

@ -12,7 +12,7 @@
*/
#include <base/env.h>
#include <base/printf.h>
#include <base/log.h>
#include <base/stdint.h>
#include <base/sleep.h>
#include <base/thread.h>
@ -23,14 +23,14 @@ using namespace Genode;
extern "C" void __cxa_pure_virtual()
{
PWRN("cxa pure virtual function called, return addr is %p",
__builtin_return_address(0));
Genode::warning("cxa pure virtual function called, return addr is ",
__builtin_return_address(0));
}
extern "C" void __pure_virtual()
{
PWRN("pure virtual function called");
Genode::warning("pure virtual function called");
}
@ -103,15 +103,16 @@ extern "C" __attribute__((weak)) void raise()
extern "C" void *abort(void)
{
Genode::Thread_base * myself = Genode::Thread_base::myself();
char thread_name[64] = { "unknown" };
Genode::Thread const * const myself = Genode::Thread::myself();
Thread::Name name = "unknown";
if (myself)
myself->name(thread_name, sizeof(thread_name));
PWRN("abort called - thread: '%s'", thread_name);
name = myself->name();
Genode::warning("abort called - thread: ", name.string());
/* Notify the parent of failure */
if (!strcmp("main", thread_name, sizeof(thread_name)))
if (name != "main")
env()->parent()->exit(1);
sleep_forever();
@ -125,7 +126,7 @@ extern "C" void *fputc(void) {
extern "C" void *fputs(const char *s, void *) {
PWRN("C++ runtime: %s", s);
Genode::warning("C++ runtime: ", s);
return 0;
}
@ -166,7 +167,7 @@ void *memset(void *s, int c, size_t n)
extern "C" void *stderr(void) {
PWRN("stderr - not yet implemented");
Genode::warning("stderr - not yet implemented");
return 0;
}
@ -180,7 +181,7 @@ FILE *__stderrp;
extern "C" void *strcat(void)
{
PWRN("strcat - not yet implemented");
Genode::warning("strcat - not yet implemented");
return 0;
}
@ -214,7 +215,7 @@ extern "C" int strcmp(const char *s1, const char *s2)
*/
extern "C" int sprintf(char *str, const char *format, ...)
{
PWRN("sprintf - not implemented");
Genode::warning("sprintf - not implemented");
return 0;
}
@ -225,5 +226,5 @@ extern "C" int sprintf(char *str, const char *format, ...)
extern "C" __attribute__((weak)) void __stack_chk_fail_local(void)
{
PERR("Violated stack boundary");
Genode::error("Violated stack boundary");
}

View File

@ -567,9 +567,9 @@ void Component::construct(Genode::Env &env)
try {
if (Genode::config()->xml_node().attribute("ld_verbose").has_value("yes")) {
PINF(" %lx .. %lx: stack area",
Genode::Thread_base::stack_area_virtual_base(),
Genode::Thread_base::stack_area_virtual_base() +
Genode::Thread_base::stack_area_virtual_size() - 1);
Genode::Thread::stack_area_virtual_base(),
Genode::Thread::stack_area_virtual_base() +
Genode::Thread::stack_area_virtual_size() - 1);
dump_link_map(Elf_object::obj_list()->head());
}
} catch (...) { }

View File

@ -44,7 +44,7 @@ void init_rtld() { }
/**
* The first thread in a program
*/
class Main_thread : public Thread<MAIN_THREAD_STACK_SIZE>
class Main_thread : public Thread_deprecated<MAIN_THREAD_STACK_SIZE>
{
public:
@ -55,7 +55,7 @@ class Main_thread : public Thread<MAIN_THREAD_STACK_SIZE>
*/
Main_thread(bool reinit)
:
Thread("main", reinit ? REINITIALIZED_MAIN : MAIN)
Thread_deprecated("main", reinit ? REINITIALIZED_MAIN : MAIN)
{ }
/**********************

View File

@ -20,7 +20,7 @@
enum { STACK_SIZE = sizeof(long)*1024, COUNT_VALUE = 10 * 1024 * 1024 };
struct Spinning_thread : Genode::Thread<STACK_SIZE>
struct Spinning_thread : Genode::Thread_deprecated<STACK_SIZE>
{
Genode::Affinity::Location const _location;
@ -50,10 +50,10 @@ struct Spinning_thread : Genode::Thread<STACK_SIZE>
Spinning_thread(Genode::Affinity::Location location, char const *name)
:
Genode::Thread<STACK_SIZE>(name), _location(location), cnt(0ULL),
Genode::Thread_deprecated<STACK_SIZE>(name), _location(location), cnt(0ULL),
barrier(Genode::Lock::LOCKED)
{
Genode::env()->cpu_session()->affinity(Thread_base::cap(), location);
Genode::env()->cpu_session()->affinity(Thread::cap(), location);
start();
}
};

View File

@ -39,7 +39,7 @@ class Sync_signal_transmitter : public Signal_transmitter
}
};
class Fpu_user : public Thread<4 * 1024>
class Fpu_user : public Thread_deprecated<4 * 1024>
{
private:
@ -56,7 +56,7 @@ class Fpu_user : public Thread<4 * 1024>
public:
Fpu_user() : Thread("fpu_user"), _x(0), _st(0) { }
Fpu_user() : Thread_deprecated("fpu_user"), _x(0), _st(0) { }
void start(float const x, Sync_signal_transmitter * const st)
{

View File

@ -39,7 +39,7 @@ enum {
/**
* Region-manager fault handler resolves faults by attaching new dataspaces
*/
class Local_fault_handler : public Thread<4096>
class Local_fault_handler : public Thread_deprecated<4096>
{
private:
@ -50,7 +50,7 @@ class Local_fault_handler : public Thread<4096>
Local_fault_handler(Region_map &region_map, Signal_receiver &receiver)
:
Thread("local_fault_handler"),
Thread_deprecated("local_fault_handler"),
_region_map(region_map), _receiver(receiver)
{ }

View File

@ -14,8 +14,12 @@
/* Genode includes */
#include <base/printf.h>
#include <base/log.h>
#include <base/thread.h>
#include <base/env.h>
#include <base/component.h>
#include <base/heap.h>
#include <os/config.h>
#include <util/volatile_object.h>
#include <cpu_session/connection.h>
@ -27,27 +31,34 @@ using namespace Genode;
*********************************/
template <int CHILDREN>
struct Helper : Thread<0x2000>
struct Helper : Thread
{
void *child[CHILDREN];
Helper() : Thread<0x2000>("helper") { }
enum { STACK_SIZE = 0x2000 };
Env &_env;
Helper(Env &env) : Thread(env, "helper", STACK_SIZE), _env(env) { }
void *stack() const { return _stack; }
void entry()
{
Helper helper[CHILDREN];
Lazy_volatile_object<Helper> helper[CHILDREN];
for (unsigned i = 0; i < CHILDREN; ++i)
child[i] = helper[i].stack();
helper[i].construct(_env);
for (unsigned i = 0; i < CHILDREN; ++i)
child[i] = helper[i]->stack();
}
};
static void test_stack_alloc()
static void test_stack_alloc(Env &env)
{
printf("running '%s'\n", __func__);
log("running '", __func__, "'");
/*
* Create HELPER threads, which concurrently create CHILDREN threads each.
@ -55,15 +66,16 @@ static void test_stack_alloc()
*/
enum { HELPER = 10, CHILDREN = 9 };
Helper<CHILDREN> helper[HELPER];
Lazy_volatile_object<Helper<CHILDREN> > helper[HELPER];
for (unsigned i = 0; i < HELPER; ++i) helper[i].start();
for (unsigned i = 0; i < HELPER; ++i) helper[i].join();
for (unsigned i = 0; i < HELPER; ++i) helper[i].construct(env);
for (unsigned i = 0; i < HELPER; ++i) helper[i]->start();
for (unsigned i = 0; i < HELPER; ++i) helper[i]->join();
if (0)
for (unsigned i = 0; i < HELPER; ++i)
for (unsigned j = 0; j < CHILDREN; ++j)
printf("%p [%d.%d]\n", helper[i].child[j], i, j);
log(helper[i]->child[j], " [", i, ".", j, "]");
}
@ -92,13 +104,15 @@ static void test_stack_alignment_varargs(char const *format, ...)
static void log_stack_address(char const *who)
{
long dummy;
printf("%s stack @ %p\n", who, &dummy);
log(who, " stack @ ", &dummy);
}
struct Stack_helper : Thread<0x2000>
struct Stack_helper : Thread
{
Stack_helper() : Thread<0x2000>("stack_helper") { }
enum { STACK_SIZE = 0x2000 };
Stack_helper(Env &env) : Thread(env, "stack_helper", STACK_SIZE) { }
void entry()
{
@ -108,11 +122,11 @@ struct Stack_helper : Thread<0x2000>
};
static void test_stack_alignment()
static void test_stack_alignment(Env &env)
{
printf("running '%s'\n", __func__);
log("running '", __func__, "'");
Stack_helper helper;
Stack_helper helper(env);
helper.start();
helper.join();
@ -128,16 +142,16 @@ static void test_stack_alignment()
static void test_main_thread()
{
printf("running '%s'\n", __func__);
log("running '", __func__, "'");
/* check wether my thread object exists */
Thread_base * myself = Genode::Thread_base::myself();
Thread * myself = Thread::myself();
if (!myself) { throw -1; }
printf("thread base %p\n", myself);
log("thread base ", myself);
/* check whether my stack is inside the first stack region */
addr_t const stack_slot_base = Thread_base::stack_area_virtual_base();
addr_t const stack_slot_size = Thread_base::stack_area_virtual_size();
addr_t const stack_slot_base = Thread::stack_area_virtual_base();
addr_t const stack_slot_size = Thread::stack_area_virtual_size();
addr_t const stack_slot_top = stack_slot_base + stack_slot_size;
addr_t const stack_top = (addr_t)myself->stack_top();
@ -148,15 +162,15 @@ static void test_main_thread()
if (stack_base >= stack_slot_top) { throw -4; }
if (stack_base < stack_slot_base) { throw -5; }
printf("thread stack top %p\n", myself->stack_top());
printf("thread stack bottom %p\n", myself->stack_base());
log("thread stack top ", myself->stack_top());
log("thread stack bottom ", myself->stack_base());
/* check wether my stack pointer is inside my stack */
unsigned dummy = 0;
addr_t const sp = (addr_t)&dummy;
if (sp >= stack_top) { throw -6; }
if (sp < stack_base) { throw -7; }
printf("thread stack pointer %p\n", (void *)sp);
log("thread stack pointer ", (void *)sp);
}
@ -164,56 +178,63 @@ static void test_main_thread()
** Using cpu-session for thread creation *
******************************************/
struct Cpu_helper : Thread<0x2000>
struct Cpu_helper : Thread
{
Cpu_helper(const char * name, Cpu_session * cpu)
: Thread<0x2000>(name, cpu) { }
enum { STACK_SIZE = 0x2000 };
Env &_env;
Cpu_helper(Env &env, const char * name, Cpu_session &cpu)
:
Thread(env, name, STACK_SIZE, Thread::Location(), Thread::Weight(), cpu),
_env(env)
{ }
void entry()
{
char name[64];
Thread_base::name(name, sizeof(name));
printf("%s : _cpu_session=0x%p env()->cpu_session()=0x%p\n",
name, _cpu_session, env()->cpu_session());
log(Thread::name().string(), " : _cpu_session=", _cpu_session,
" env.cpu()=", &_env.cpu());
}
};
static void test_cpu_session()
static void test_cpu_session(Env &env)
{
printf("running '%s'\n", __func__);
log("running '", __func__, "'");
Cpu_helper thread0("prio high ", env()->cpu_session());
Cpu_helper thread0(env, "prio high ", env.cpu());
thread0.start();
thread0.join();
Cpu_connection con1("prio middle", Cpu_session::PRIORITY_LIMIT / 4);
Cpu_helper thread1("prio middle", &con1);
Cpu_helper thread1(env, "prio middle", con1);
thread1.start();
thread1.join();
Cpu_connection con2("prio low", Cpu_session::PRIORITY_LIMIT / 2);
Cpu_helper thread2("prio low ", &con2);
Cpu_helper thread2(env, "prio low ", con2);
thread2.start();
thread2.join();
}
struct Pause_helper : Thread<0x1000>
struct Pause_helper : Thread
{
volatile unsigned loop = 0;
volatile bool beep = false;
Pause_helper(const char * name, Cpu_session * cpu)
: Thread<0x1000>(name, cpu) { }
enum { STACK_SIZE = 0x1000 };
Pause_helper(Env &env, const char * name, Cpu_session &cpu)
: Thread(env, name, STACK_SIZE, Thread::Location(), Thread::Weight(), cpu) { }
void entry()
{
while (1) {
/**
* Don't use printf here, since this thread becomes "paused".
* If it is holding the lock of the printf backend being paused,
* all other threads of this task trying to do printf will
/*
* Don't log here, since this thread becomes "paused".
* If it is holding the lock of the log backend being paused, all
* other threads of this task trying to print log messages will
* block - looks like a deadlock.
*/
// printf("stop me if you can\n");
@ -228,25 +249,26 @@ struct Pause_helper : Thread<0x1000>
}
};
static void test_pause_resume()
{
printf("running '%s'\n", __func__);
Pause_helper thread("pause", env()->cpu_session());
static void test_pause_resume(Env &env)
{
log("running '", __func__, "'");
Pause_helper thread(env, "pause", env.cpu());
thread.start();
while (thread.loop < 1) { }
Thread_state state;
printf("--- pausing ---\n");
env()->cpu_session()->pause(thread.cap());
log("--- pausing ---");
env.cpu().pause(thread.cap());
unsigned loop_paused = thread.loop;
printf("--- paused ---\n");
log("--- paused ---");
printf("--- reading thread state ---\n");
log("--- reading thread state ---");
try {
state = env()->cpu_session()->state(thread.cap());
state = env.cpu().state(thread.cap());
} catch (Cpu_session::State_access_failed) {
throw -10;
}
@ -254,47 +276,50 @@ static void test_pause_resume()
throw -11;
thread.beep = true;
printf("--- resuming thread ---\n");
env()->cpu_session()->resume(thread.cap());
log("--- resuming thread ---");
env.cpu().resume(thread.cap());
while (thread.loop == loop_paused) { }
printf("--- thread resumed ---\n");
log("--- thread resumed ---");
thread.join();
}
/*
* Test to check that core as the used kernel behaves well if up to the
* supported Genode maximum threads are created.
*/
static void test_create_as_many_threads()
static void test_create_as_many_threads(Env &env)
{
printf("running '%s'\n", __func__);
log("running '", __func__, "'");
addr_t const max = Thread_base::stack_area_virtual_size() /
Thread_base::stack_virtual_size();
addr_t const max = Thread::stack_area_virtual_size() /
Thread::stack_virtual_size();
Cpu_helper * threads[max];
static char thread_name[8];
Heap heap(env.ram(), env.rm());
unsigned i = 0;
try {
for (; i < max; i++) {
try {
snprintf(thread_name, sizeof(thread_name), "%u", i + 1);
threads[i] = new (env()->heap()) Cpu_helper(thread_name, env()->cpu_session());
threads[i] = new (heap) Cpu_helper(env, thread_name, env.cpu());
threads[i]->start();
threads[i]->join();
} catch (Cpu_session::Thread_creation_failed) {
throw "Thread_creation_failed";
} catch (Thread_base::Out_of_stack_space) {
} catch (Thread::Out_of_stack_space) {
throw "Out_of_stack_space";
}
}
} catch (const char * ex) {
PINF("created %u threads before I got '%s'", i, ex);
for (unsigned j = i; j > 0; j--) {
destroy(env()->heap(), threads[j - 1]);
destroy(heap, threads[j - 1]);
threads[j - 1] = nullptr;
}
return;
@ -307,18 +332,33 @@ static void test_create_as_many_threads()
throw -21;
}
int main()
char const *Component::name() { return "test-thread"; }
size_t Component::stack_size() { return 16*1024*sizeof(long); }
void Component::construct(Env &env)
{
printf("--- thread test started ---\n");
log("--- thread test started ---");
Xml_node config = Genode::config()->xml_node();
try {
test_stack_alloc();
test_stack_alignment();
test_stack_alloc(env);
test_stack_alignment(env);
test_main_thread();
test_cpu_session();
test_pause_resume();
test_create_as_many_threads();
test_cpu_session(env);
if (config.has_sub_node("pause_resume"))
test_pause_resume(env);
test_create_as_many_threads(env);
} catch (int error) {
return error;
Genode::error("error ", error);
throw;
}
log("--- test completed successfully ---");
}

View File

@ -1,3 +1,3 @@
TARGET = test-thread
SRC_CC = main.cc
LIBS = base
LIBS = base config

View File

@ -143,7 +143,7 @@ static void test_weak_pointer_tracking()
*******************************************/
template <typename O>
struct Destruct_thread : Genode::Thread<4096>
struct Destruct_thread : Genode::Thread_deprecated<4096>
{
O *obj;
@ -155,7 +155,7 @@ struct Destruct_thread : Genode::Thread<4096>
PLOG("thread: destruction completed, job done");
}
Destruct_thread(O *obj) : Thread("object_destructor"), obj(obj) { }
Destruct_thread(O *obj) : Thread_deprecated("object_destructor"), obj(obj) { }
};