Move server API concept to base framework

This commit introduces the new `Component` interface in the form of the
headers base/component.h and base/entrypoint.h. The os/server.h API
has become merely a compatibilty wrapper and will eventually be removed.
The same holds true for os/signal_rpc_dispatcher.h. The mechanism has
moved to base/signal.h and is now called 'Signal_handler'.

Since the patch shuffles headers around, please do a 'make clean' in the
build directory.

Issue #1832
This commit is contained in:
Norman Feske
2015-12-23 15:22:33 +01:00
committed by Christian Helmuth
parent 4ac7127f89
commit 051e84c4b4
74 changed files with 1730 additions and 638 deletions

View File

@ -0,0 +1,76 @@
/*
* \brief Component bootstrap
* \author Norman Feske
* \author Christian Helmuth
* \date 2016-01-13
*/
/*
* Copyright (C) 2016 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.
*/
/* Genode includes */
#include <base/component.h>
#include <base/env.h>
namespace {
struct Environment : Genode::Environment
{
Genode::Entrypoint &_ep;
Environment(Genode::Entrypoint &ep) : _ep(ep) { }
Genode::Parent &parent() override { return *Genode::env()->parent(); }
Genode::Ram_session &ram() override { return *Genode::env()->ram_session(); }
Genode::Cpu_session &cpu() override { return *Genode::env()->cpu_session(); }
Genode::Rm_session &rm() override { return *Genode::env()->rm_session(); }
Genode::Pd_session &pd() override { return *Genode::env()->pd_session(); }
Genode::Entrypoint &ep() override { return _ep; }
Genode::Ram_session_capability ram_session_cap() override
{
return Genode::env()->ram_session_cap();
}
Genode::Cpu_session_capability cpu_session_cap() override
{
return Genode::env()->cpu_session_cap();
}
};
}
namespace Genode {
struct Startup;
extern void bootstrap_component();
}
/*
* We need to execute the constructor of the main entrypoint from a
* class called 'Startup' as 'Startup' is a friend of 'Entrypoint'.
*/
struct Genode::Startup
{
::Environment env { ep };
/*
* The construction of the main entrypoint does never return.
*/
Entrypoint ep { env };
};
void Genode::bootstrap_component()
{
static Startup startup;
/* never reached */
}

View File

@ -0,0 +1,191 @@
/*
* \brief Entrypoint for serving RPC requests and dispatching signals
* \author Norman Feske
* \author Christian Helmuth
* \date 2015-12-17
*/
/*
* Copyright (C) 2015 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.
*/
#include <base/entrypoint.h>
#include <base/component.h>
#include <cap_session/connection.h>
#include <util/retry.h>
using namespace Genode;
/*
* XXX move declarations to base-internal headers
*/
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::Environment &);
}
void Entrypoint::_dispatch_signal(Signal &sig)
{
Signal_dispatcher_base *dispatcher = 0;
dispatcher = dynamic_cast<Signal_dispatcher_base *>(sig.context());
if (!dispatcher)
return;
dispatcher->dispatch(sig.num());
}
void Entrypoint::_process_incoming_signals()
{
for (;;) {
do {
_sig_rec->block_for_signal();
/*
* It might happen that we try to forward a signal to the
* entrypoint, while the context of that signal is already
* destroyed. In that case we will get an ipc error exception
* as result, which has to be caught.
*/
retry<Genode::Blocking_canceled>(
[&] () { _signal_proxy_cap.call<Signal_proxy::Rpc_signal>(); },
[] () { PWRN("Catched Blocking_canceled on signal processing"); }
);
} while (!_suspended_callback);
_suspend_dispatcher.destruct();
_sig_rec.destruct();
dissolve(_signal_proxy);
_signal_proxy_cap = Capability<Signal_proxy>();
_rpc_ep.destruct();
destroy_signal_thread();
/* execute fork magic in noux plugin */
_suspended_callback();
init_signal_thread();
_rpc_ep.construct(&_env.pd(), Component::stack_size(), Component::name());
_signal_proxy_cap = manage(_signal_proxy);
_sig_rec.construct();
/*
* Before calling the resumed callback, we reset the callback pointer
* as these may be set again in the resumed code to initiate the next
* suspend-resume cycle (e.g., exit()).
*/
void (*resumed_callback)() = _resumed_callback;
_suspended_callback = nullptr;
_resumed_callback = nullptr;
resumed_callback();
}
}
void Entrypoint::schedule_suspend(void (*suspended)(), void (*resumed)())
{
_suspended_callback = suspended;
_resumed_callback = resumed;
/*
* We always construct the dispatcher when the suspend is scheduled and
* destruct it when the suspend is executed.
*/
_suspend_dispatcher.construct(*this, *this, &Entrypoint::_handle_suspend);
/* trigger wakeup of the signal-dispatch loop for suspend */
Genode::Signal_transmitter(*_suspend_dispatcher).submit();
}
Signal_context_capability Entrypoint::manage(Signal_dispatcher_base &dispatcher)
{
return _sig_rec->manage(&dispatcher);
}
void Genode::Entrypoint::dissolve(Signal_dispatcher_base &dispatcher)
{
_sig_rec->dissolve(&dispatcher);
}
namespace {
struct Constructor
{
GENODE_RPC(Rpc_construct, void, construct);
GENODE_RPC_INTERFACE(Rpc_construct);
};
struct Constructor_component : Rpc_object<Constructor, Constructor_component>
{
Environment &env;
Constructor_component(Environment &env) : env(env) { }
void construct()
{
/* enable tracing support */
Genode::inhibit_tracing = false;
Genode::call_global_static_constructors();
Genode::call_component_construct(env);
}
};
}
Entrypoint::Entrypoint(Environment &env)
:
_env(env),
_rpc_ep(&env.pd(), Component::stack_size(), Component::name())
{
/* initialize signalling after initializing but before calling the entrypoint */
init_signal_thread();
/*
* Invoke Component::construct function in the context of the entrypoint.
*/
Constructor_component constructor(env);
Capability<Constructor> constructor_cap =
_rpc_ep->manage(&constructor);
try {
constructor_cap.call<Constructor::Rpc_construct>();
} catch (Genode::Blocking_canceled) {
PWRN("Catched Blocking_canceled in Entrypoint constructor");
}
_rpc_ep->dissolve(&constructor);
/*
* The calling initial thread becomes the signal proxy thread for this
* entrypoint
*/
_process_incoming_signals();
}
Entrypoint::Entrypoint(Environment &env, size_t stack_size, char const *name)
:
_env(env),
_rpc_ep(&env.pd(), stack_size, name)
{
_signal_proxy_thread.construct(*this);
}

View File

@ -24,12 +24,7 @@ void prepare_reinit_main_thread();
void reinit_main_thread();
namespace Genode
{
extern bool inhibit_tracing;
Rm_session * env_stack_area_rm_session();
}
namespace Genode { extern bool inhibit_tracing; }
void Genode::Platform_env::reinit(Native_capability::Dst dst,
@ -86,7 +81,7 @@ Genode::Platform_env::
reinit_main_thread(Rm_session_capability & stack_area_rm)
{
/* reinitialize stack area RM session */
Rm_session * const rms = env_stack_area_rm_session();
Rm_session * const rms = env_stack_area_rm_session;
Rm_session_client * const rmc = dynamic_cast<Rm_session_client *>(rms);
construct_at<Rm_session_client>(rmc, stack_area_rm);

View File

@ -11,56 +11,12 @@
* under the terms of the GNU General Public License version 2.
*/
/* Genode includes */
#include <rm_session/connection.h>
/* base-internal includes */
#include <base/internal/platform_env_common.h>
#include <base/internal/stack_area.h>
using namespace Genode;
struct Expanding_rm_connection : Connection<Rm_session>, Expanding_rm_session_client
{
/**
* Constructor
*
* \param start start of the managed VM-region
* \param size size of the VM-region to manage
*/
Expanding_rm_connection(addr_t start = ~0UL, size_t size = 0) :
Connection<Rm_session>(
session("ram_quota=64K, start=0x%p, size=0x%zx",
start, size)),
Expanding_rm_session_client(cap()) { }
};
struct Stack_area_rm_session : Expanding_rm_connection
{
Stack_area_rm_session()
: Expanding_rm_connection(0, stack_area_virtual_size())
{
addr_t const local_base = stack_area_virtual_base();
size_t const size = stack_area_virtual_size();
env()->rm_session()->attach_at(dataspace(), local_base, size);
}
};
namespace Genode {
Rm_session *env_stack_area_rm_session()
{
static Stack_area_rm_session inst;
return &inst;
}
Ram_session *env_stack_area_ram_session()
{
return env()->ram_session();
}
Rm_session *env_stack_area_rm_session;
Ram_session *env_stack_area_ram_session;
}

View File

@ -30,6 +30,9 @@ void Rpc_entrypoint::_dissolve(Rpc_object_base *obj)
_free_rpc_cap(_pd_session, obj->cap());
/* effectively invalidate the capability used before */
obj->cap(Untyped_capability());
/* now the object may be safely destructed */
}

View File

@ -17,6 +17,7 @@
#include <base/thread.h>
#include <base/trace/events.h>
#include <signal_source/client.h>
#include <util/volatile_object.h>
using namespace Genode;
@ -27,19 +28,19 @@ class Signal_handler_thread : Thread<STACK_SIZE>, Lock
private:
/**
* Return process-wide signal source used for signal reception
* Actual signal source
*
* This function must be called from the context of the signal handler
* Member must be constructed in the context of the signal handler
* thread because on some platforms (e.g., Fiasco.OC), the calling
* thread context is used for implementing the signal-source protocol.
*/
static Signal_source *signal_source();
Lazy_volatile_object<Signal_source_client> _signal_source;
void entry()
{
Signal_source *source = signal_source();
_signal_source.construct(env()->pd_session()->alloc_signal_source());
unlock();
Signal_receiver::dispatch_signals(source);
Signal_receiver::dispatch_signals(&(*_signal_source));
}
public:
@ -53,30 +54,53 @@ class Signal_handler_thread : Thread<STACK_SIZE>, Lock
start();
/*
* Make sure to have initialized the 'signal_source()' channel
* before proceeding with the use of signals. Otherwise, signals
* that occurred until the construction of 'signal_source' is
* completed may get lost.
* Make sure the signal source was constructed before proceeding
* with the use of signals. Otherwise, signals may get lost until
* the construction finished.
*/
lock();
}
~Signal_handler_thread()
{
env()->pd_session()->free_signal_source(*_signal_source);
}
};
Signal_source *Signal_handler_thread::signal_source()
/*
* The signal-handler thread will be constructed before global constructors are
* called and, consequently, must not be a global static object. Otherwise, the
* Lazy_volatile_object constructor will be executed twice.
*/
static Lazy_volatile_object<Signal_handler_thread> & signal_handler_thread()
{
static Signal_source_client sigsrc(env()->pd_session()->alloc_signal_source());
return &sigsrc;
static Lazy_volatile_object<Signal_handler_thread> inst;
return inst;
}
/**
* Return process-wide signal source used for signal reception
*/
static Signal_handler_thread *signal_handler_thread()
{
static Signal_handler_thread signal_handler_thread;
return &signal_handler_thread;
namespace Genode {
/*
* Initialize the component-local signal-handling thread
*
* This function is called once at the startup of the component. It must
* be called before creating the first signal receiver.
*
* 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()
{
signal_handler_thread().construct();
}
void destroy_signal_thread()
{
signal_handler_thread().destruct();
}
}
@ -182,12 +206,7 @@ void Signal_context::submit(unsigned num)
** Signal receiver **
*********************/
Signal_receiver::Signal_receiver()
{
/* make sure that the process-local signal handler thread is running */
signal_handler_thread();
}
Signal_receiver::Signal_receiver() { }
Signal_context_capability Signal_receiver::manage(Signal_context *context)

View File

@ -33,8 +33,8 @@ using namespace Genode;
*/
namespace Genode {
Rm_session *env_stack_area_rm_session();
Ram_session *env_stack_area_ram_session();
extern Rm_session * const env_stack_area_rm_session;
extern Ram_session * const env_stack_area_ram_session;
}
@ -58,9 +58,9 @@ void Stack::size(size_t const size)
/* allocate and attach backing store for the stack enhancement */
addr_t const ds_addr = _base - ds_size - stack_area_virtual_base();
try {
Ram_session * const ram = env_stack_area_ram_session();
Ram_session * const ram = env_stack_area_ram_session;
Ram_dataspace_capability const ds_cap = ram->alloc(ds_size);
Rm_session * const rm = env_stack_area_rm_session();
Rm_session * const rm = env_stack_area_rm_session;
void * const attach_addr = rm->attach_at(ds_cap, ds_addr, ds_size);
if (ds_addr != (addr_t)attach_addr)
@ -114,9 +114,9 @@ Thread_base::_alloc_stack(size_t stack_size, char const *name, bool main_thread)
/* allocate and attach backing store for the stack */
Ram_dataspace_capability ds_cap;
try {
ds_cap = env_stack_area_ram_session()->alloc(ds_size);
ds_cap = env_stack_area_ram_session->alloc(ds_size);
addr_t attach_addr = ds_addr - stack_area_virtual_base();
if (attach_addr != (addr_t)env_stack_area_rm_session()->attach_at(ds_cap, attach_addr, ds_size))
if (attach_addr != (addr_t)env_stack_area_rm_session->attach_at(ds_cap, attach_addr, ds_size))
throw Stack_alloc_failed();
}
catch (Ram_session::Alloc_failed) { throw Stack_alloc_failed(); }
@ -143,8 +143,8 @@ void Thread_base::_free_stack(Stack *stack)
/* call de-constructor explicitly before memory gets detached */
stack->~Stack();
Genode::env_stack_area_rm_session()->detach((void *)ds_addr);
Genode::env_stack_area_ram_session()->free(ds_cap);
Genode::env_stack_area_rm_session->detach((void *)ds_addr);
Genode::env_stack_area_ram_session->free(ds_cap);
/* stack ready for reuse */
Stack_allocator::stack_allocator().free(stack);

View File

@ -32,6 +32,8 @@
#include <core_pd_session.h>
#include <ram_session_component.h>
namespace Genode { void init_stack_area(); }
namespace Genode {
/**
@ -118,6 +120,13 @@ namespace Genode {
enum { ENTRYPOINT_STACK_SIZE = 2048 * sizeof(Genode::addr_t) };
/*
* Initialize the stack area before creating the first thread,
* which happens to be the '_entrypoint'.
*/
bool _init_stack_area() { init_stack_area(); return true; }
bool _stack_area_initialized = _init_stack_area();
Rpc_entrypoint _entrypoint;
Core_rm_session _rm_session;
Core_ram_session _ram_session;
@ -172,13 +181,14 @@ namespace Genode {
Pd_session *pd_session() override { return &_pd_session_client; }
Allocator *heap() override { return &_heap; }
Cpu_session *cpu_session()
Cpu_session *cpu_session() override
{
PWRN("%s:%u not implemented", __FILE__, __LINE__);
return 0;
}
Cpu_session_capability cpu_session_cap() {
Cpu_session_capability cpu_session_cap() override
{
PWRN("%s:%u not implemented", __FILE__, __LINE__);
return Cpu_session_capability();
}
@ -189,9 +199,9 @@ namespace Genode {
return Pd_session_capability();
}
void reinit(Capability<Parent>::Dst, long) { }
void reinit(Capability<Parent>::Dst, long) override { }
void reinit_main_thread(Rm_session_capability &) { }
void reinit_main_thread(Rm_session_capability &) override { }
};

View File

@ -167,6 +167,22 @@ class Core_child : public Child_policy
};
/****************
** Signal API **
****************/
/*
* In contrast to the 'Platform_env' used by non-core components, core disables
* the signal thread but overriding 'Genode::init_signal_thread' with a dummy.
* Within core, the signal thread is not needed as core is never supposed to
* receive any signals. Otherwise, the signal thread would be the only
* non-entrypoint thread within core, which would be a problem on NOVA where
* the creation of regular threads within core is unsupported.
*/
namespace Genode { void init_signal_thread() { } }
/*******************
** Trace support **
*******************/
@ -187,6 +203,7 @@ namespace Genode {
extern char const *version_string;
}
int main()
{
/**

View File

@ -27,6 +27,16 @@
#include <map_local.h>
#include <dataspace_component.h>
namespace Genode {
Rm_session *env_stack_area_rm_session;
Ram_session *env_stack_area_ram_session;
void init_stack_area();
}
using namespace Genode;
@ -149,20 +159,11 @@ class Stack_area_ram_session : public Ram_session
};
/**
* Return single instance of the context-area RM and RAM session
*/
namespace Genode {
void Genode::init_stack_area()
{
static Stack_area_rm_session rm;
env_stack_area_rm_session = &rm;
Rm_session *env_stack_area_rm_session()
{
static Stack_area_rm_session inst;
return &inst;
}
Ram_session *env_stack_area_ram_session()
{
static Stack_area_ram_session inst;
return &inst;
}
static Stack_area_ram_session ram;
env_stack_area_ram_session = &ram;
}

View File

@ -88,7 +88,15 @@ class Genode::Platform_env : public Genode::Env, public Emergency_ram_reserve
};
Resources _resources;
Heap _heap;
Heap _heap;
/*
* The '_heap' must be initialized before the '_stack_area'
* because the 'Local_parent' performs a dynamic memory allocation
* due to the creation of the stack area's sub-RM session.
*/
Attached_stack_area _stack_area { _parent_client, _resources.rm };
char _initial_heap_chunk[sizeof(addr_t) * 4096];
@ -112,13 +120,16 @@ class Genode::Platform_env : public Genode::Env, public Emergency_ram_reserve
_heap(&_resources.ram, &_resources.rm, Heap::UNLIMITED,
_initial_heap_chunk, sizeof(_initial_heap_chunk)),
_emergency_ram_ds(_resources.ram.alloc(_emergency_ram_size()))
{ }
{
env_stack_area_ram_session = &_resources.ram;
env_stack_area_rm_session = &_stack_area;
}
/*
* Support functions for implementing fork on Noux.
*/
void reinit(Native_capability::Dst, long);
void reinit_main_thread(Rm_session_capability &);
void reinit(Native_capability::Dst, long) override;
void reinit_main_thread(Rm_session_capability &) override;
/*************************************

View File

@ -25,6 +25,9 @@
#include <cpu_session/client.h>
#include <pd_session/client.h>
#include <base/internal/stack_area.h>
namespace Genode {
class Expanding_rm_session_client;
@ -32,7 +35,14 @@ namespace Genode {
class Expanding_cpu_session_client;
class Expanding_parent_client;
struct Attached_stack_area;
Parent_capability parent_cap();
extern Rm_session *env_stack_area_rm_session;
extern Ram_session *env_stack_area_ram_session;
void init_signal_thread();
}
@ -325,4 +335,31 @@ class Genode::Expanding_parent_client : public Parent_client
}
};
struct Genode::Attached_stack_area : Genode::Expanding_rm_session_client
{
/**
* Helper for requesting the sub RM session of the stack area
*/
Rm_session_capability _session(Parent &parent)
{
char buf[256];
snprintf(buf, sizeof(buf), "ram_quota=64K, start=0x0, size=0x%zx",
(size_t)stack_area_virtual_size());
return static_cap_cast<Rm_session>(parent.session(Rm_session::service_name(),
buf, Affinity()));
}
Attached_stack_area(Parent &parent, Rm_session &env_rm)
:
Expanding_rm_session_client(_session(parent))
{
env_rm.attach_at(Expanding_rm_session_client::dataspace(),
stack_area_virtual_base(),
stack_area_virtual_size());
}
};
#endif /* _INCLUDE__BASE__INTERNAL__PLATFORM_ENV_COMMON_H_ */

View File

@ -13,12 +13,14 @@
/*
* Program doesn't need to startup with CRT0 as LDSO has done this
* initialization during its own CRT0 already.
* Components don't need to startup with CRT0 as LDSO has done this
* initialization during its own CRT0 already. The component always starts at
* Genode::component_entry_point() as a trampoline to
* call_component_construct().
*/
ENTRY(main)
ENTRY(_ZN6Genode21component_entry_pointERNS_11EnvironmentE)
PHDRS
PHDRS
{
phdr PT_PHDR PHDRS;
interp PT_INTERP;
@ -34,11 +36,15 @@ SECTIONS
.text :
{
_prog_img_beg = .;
/* put entry code at the start of the text segment / raw binary */
*(.text._ZN6Genode21component_entry_pointERNS_11EnvironmentE)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
} : ro =0x0
.interp : { *(.interp) } : interp : ro
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
@ -137,7 +143,7 @@ SECTIONS
/* Thread Local Storage sections */
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
/* Take out for now because these sections cause warnings on ARM. If this
* should lead to an error then we'll take it back in.
.preinit_array :
@ -201,7 +207,7 @@ SECTIONS
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) } : rw : dynamic
/* merge .got.plt and .got into .got, since the ARM toolchain for OKL4
* set's * DT_PLTGOT to .got instead of .got.plt */
.got : { *(.got.plt) *(.got) }

View File

@ -12,7 +12,7 @@
*/
/* Genode includes */
#include <base/env.h>
#include <base/component.h>
#include <base/printf.h>
#include <os/config.h>
#include <util/list.h>
@ -35,13 +35,6 @@ namespace Linker {
};
/**
* Genode args to the 'main' function
*/
extern char **genode_argv;
extern int genode_argc;
extern char **genode_envp;
static Binary *binary = 0;
bool Linker::bind_now = false;
Link_map *Link_map::first;
@ -364,7 +357,7 @@ struct Linker::Binary : Root_object, Elf_object
return 0;
}
int call_entry_point()
void call_entry_point(Genode::Environment &env)
{
/* call static construtors and register destructors */
Func * const ctors_start = (Func *)lookup_symbol("_ctors_start");
@ -375,11 +368,13 @@ struct Linker::Binary : Root_object, Elf_object
Func * const dtors_end = (Func *)lookup_symbol("_dtors_end");
for (Func * dtor = dtors_start; dtor != dtors_end; genode_atexit(*dtor++));
/* call main function of the program */
typedef int (*Main)(int, char **, char **);
Main const main = reinterpret_cast<Main>(_file->entry);
/* call component entry point */
/* XXX the function type for call_component_construct() is a candidate
* for a base-internal header */
typedef void (*Entry)(Genode::Environment &);
Entry const entry = reinterpret_cast<Entry>(_file->entry);
return main(genode_argc, genode_argv, genode_envp);
entry(env);
}
void relocate() override
@ -558,7 +553,12 @@ static void dump_loaded()
}
int main()
Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); }
char const * Component::name() { return "ep"; }
struct Failed_to_load_program { };
void Component::construct(Genode::Environment &env)
{
/* load program headers of linker now */
if (!Ld::linker()->file())
@ -575,7 +575,7 @@ int main()
binary = new(Genode::env()->heap()) Binary();
} catch (...) {
PERR("LD: Failed to load program");
return -1;
throw Failed_to_load_program();
}
/* print loaded object information */
@ -592,6 +592,5 @@ int main()
Link_map::dump();
/* start binary */
return binary->call_entry_point();
binary->call_entry_point(env);
}

View File

@ -2,6 +2,7 @@
* \brief Startup code
* \author Christian Helmuth
* \author Christian Prochaska
* \author Norman Feske
* \date 2006-04-12
*
* The startup code calls constructors for static objects before calling
@ -12,7 +13,7 @@
*/
/*
* Copyright (C) 2006-2013 Genode Labs GmbH
* Copyright (C) 2006-2016 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.
@ -22,16 +23,13 @@
#include <base/env.h>
#include <base/sleep.h>
#include <base/printf.h>
#include <base/component.h>
/* platform-specific local helper functions */
#include <startup/internal/_main_parent_cap.h>
#include <base/internal/crt0.h>
using namespace Genode;
extern int main(int argc, char **argv, char **envp);
enum { ATEXIT_SIZE = 256 };
@ -64,9 +62,9 @@ static struct atexit
} _atexit;
static Lock &atexit_lock()
static Genode::Lock &atexit_lock()
{
static Lock _atexit_lock;
static Genode::Lock _atexit_lock;
return _atexit_lock;
}
@ -79,7 +77,7 @@ static void atexit_enable()
static int atexit_register(struct atexit_fn *fn)
{
Lock::Guard atexit_lock_guard(atexit_lock());
Genode::Lock::Guard atexit_lock_guard(atexit_lock());
if (!_atexit.enabled)
return 0;
@ -188,10 +186,10 @@ void genode_exit(int status)
for (func = &_dtors_start; func != &_dtors_end; (*func++)());
/* inform parent about the exit status */
env()->parent()->exit(status);
Genode::env()->parent()->exit(status);
/* wait for destruction by the parent */
sleep_forever();
Genode::sleep_forever();
}
@ -213,15 +211,28 @@ int genode_argc = 1;
char **genode_envp = 0;
namespace Genode { extern bool inhibit_tracing; }
/******************************************************
** C entry function called by the crt0 startup code **
******************************************************/
namespace Genode {
/*
* To be called from the context of the initial entrypoiny before
* passing control to the 'Component::construct' function.
*/
void call_global_static_constructors()
{
void (**func)();
for (func = &_ctors_end; func != &_ctors_start; (*--func)());
}
/* XXX move to base-internal header */
extern void bootstrap_component();
}
/**
* C entry function called by the crt0 startup code
*
* Note, _main is executed twice when starting dynamic programs: in ld.lib.so
* and also in the loaded binary.
*/
extern "C" int _main()
{
/*
@ -234,20 +245,8 @@ extern "C" int _main()
*/
atexit_enable();
/* call constructors for static objects */
void (**func)();
for (func = &_ctors_end; func != &_ctors_start; (*--func)());
Genode::bootstrap_component();
/* now, it is save to call printf */
/* enable tracing support */
inhibit_tracing = false;
/* call real main function */
int ret = main(genode_argc, genode_argv, genode_envp);
genode_exit(ret);
/* not reached */
return ret;
/* never reached */
return 0;
}

View File

@ -0,0 +1,98 @@
/*
* \brief Startup code for component construction
* \author Christian Helmuth
* \date 2016-01-21
*
* The component construction code is used by the startup library, which is
* linked to static binaries and ld.lib.so. The code is also used by the
* component_entry_point static library, which is linked to all dynamic
* executables to make the fallback implementation and the
* call_component_construct-hook function pointer available to these binaries.
*
* Note, for dynamic binaries we can't refer to the default implementation in
* ld.lib.so as it is a component itself implementing the Component functions.
*/
/*
* Copyright (C) 2016 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.
*/
/* Genode includes */
#include <base/component.h>
namespace Genode {
/*
* Hook for intercepting the call of the 'Component::construct' method. By
* hooking this function pointer in a library constructor, the libc is able
* to create a task context for the component code. This context is
* scheduled by the libc in a cooperative fashion, i.e. when the
* component's entrypoint is activated.
*/
extern void (*call_component_construct)(Genode::Environment &) __attribute__((weak));
}
static void default_component_construct(Genode::Environment &env)
{
Component::construct(env);
}
void (*Genode::call_component_construct)(Genode::Environment &) = &default_component_construct;
/****************************************************
** Fallback implementation of Component interface **
****************************************************/
extern void genode_exit(int status);
static int exit_status;
static void exit_on_suspended() { genode_exit(exit_status); }
/*
* Regular components provide the 'Component' interface as defined in
* base/component.h. This fallback accommodates legacy components that lack the
* implementation of this interface but come with a main function.
*/
/*
* XXX these symbols reside in the startup library - candidate for
* base-internal header?
*/
extern char **genode_argv;
extern int genode_argc;
extern char **genode_envp;
extern int main(int argc, char **argv, char **envp);
void Component::construct(Genode::Environment &env) __attribute__((weak));
void Component::construct(Genode::Environment &env)
{
/* call real main function */
exit_status = main(genode_argc, genode_argv, genode_envp);
/* trigger suspend in the entry point */
env.ep().schedule_suspend(exit_on_suspended, nullptr);
/* return to entrypoint and exit via exit_on_suspended() */
}
Genode::size_t Component::stack_size() __attribute__((weak));
Genode::size_t Component::stack_size()
{
return 16UL * 1024 * sizeof(Genode::addr_t);
}
char const *Component::name() __attribute__((weak));
char const *Component::name()
{
return "ep";
}

View File

@ -0,0 +1,32 @@
/*
* \brief Component entry point for dynamic executables
* \author Christian Helmuth
* \date 2016-01-21
*
* The ELF entry point of dynamic binaries is set to component_entry_point(),
* which calls the call_component_construct-hook function pointer.
*/
/*
* Copyright (C) 2016 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.
*/
/* Genode includes */
#include <base/component.h>
/* FIXME move to base-internal header */
namespace Genode {
extern void (*call_component_construct)(Environment &);
}
namespace Genode {
void component_entry_point(Genode::Environment &env)
{
call_component_construct(env);
}
}

View File

@ -25,7 +25,7 @@ addr_t init_main_thread_result;
extern void init_exception_handling();
namespace Genode { Rm_session * env_stack_area_rm_session(); }
namespace Genode { extern Rm_session * const env_stack_area_rm_session; }
void prepare_init_main_thread();
@ -93,12 +93,6 @@ extern "C" void init_main_thread()
/* initialize exception handling */
init_exception_handling();
/*
* We create the thread-context area as early as possible to prevent other
* mappings from occupying the predefined virtual-memory region.
*/
env_stack_area_rm_session();
/*
* Trigger first exception. This step has two purposes.
* First, it enables us to detect problems related to exception handling as