mirror of
https://github.com/genodelabs/genode.git
synced 2025-03-14 00:06:40 +00:00
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:
parent
4ac7127f89
commit
051e84c4b4
@ -24,6 +24,8 @@ SRC_CC += thread/myself.cc
|
||||
SRC_CC += thread/stack_allocator.cc
|
||||
SRC_CC += sleep.cc
|
||||
SRC_CC += rm_session_client.cc
|
||||
SRC_CC += entrypoint/entrypoint.cc
|
||||
SRC_CC += component/component.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/include $(BASE_DIR)/src/include
|
||||
|
||||
|
@ -70,6 +70,13 @@ namespace Genode {
|
||||
: Rpc_client<Foc_signal_source>(static_cap_cast<Foc_signal_source>(cap))
|
||||
{ _init_sem(); }
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
~Signal_source_client()
|
||||
{
|
||||
Fiasco::l4_irq_detach(_sem.dst());
|
||||
}
|
||||
|
||||
/*****************************
|
||||
** Signal source interface **
|
||||
|
@ -25,6 +25,8 @@ SRC_CC += thread/stack_allocator.cc
|
||||
SRC_CC += thread/thread_utcb.cc
|
||||
SRC_CC += sleep.cc
|
||||
SRC_CC += rm_session_client.cc
|
||||
SRC_CC += entrypoint/entrypoint.cc
|
||||
SRC_CC += component/component.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/include $(BASE_DIR)/src/include
|
||||
|
||||
|
@ -29,6 +29,8 @@ SRC_CC += thread/stack_allocator.cc
|
||||
SRC_CC += kernel/interface.cc
|
||||
SRC_CC += sleep.cc
|
||||
SRC_CC += rm_session_client.cc
|
||||
SRC_CC += entrypoint/entrypoint.cc
|
||||
SRC_CC += component/component.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/include $(BASE_DIR)/src/include
|
||||
|
||||
|
@ -44,6 +44,7 @@ SRC_CC += env.cc
|
||||
SRC_CC += rm_session_support.cc
|
||||
SRC_CC += pager.cc
|
||||
SRC_CC += _main.cc
|
||||
SRC_CC += component_construct.cc
|
||||
SRC_CC += kernel/cpu_scheduler.cc
|
||||
SRC_CC += kernel/double_list.cc
|
||||
SRC_CC += kernel/init.cc
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <base/env.h>
|
||||
#include <base/native_env.h>
|
||||
|
||||
|
||||
void Genode::upgrade_pd_session_quota(Genode::size_t quota)
|
||||
{
|
||||
char buf[128];
|
||||
|
@ -26,12 +26,25 @@
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/*
|
||||
* On base-hw, no signal thread is needed.
|
||||
*/
|
||||
void init_signal_thread() __attribute__((weak));
|
||||
void init_signal_thread() { }
|
||||
void destroy_signal_thread() { }
|
||||
}
|
||||
|
||||
|
||||
/********************
|
||||
** Signal context **
|
||||
********************/
|
||||
|
||||
void Signal_context::submit(unsigned) { PERR("not implemented"); }
|
||||
|
||||
|
||||
/************************
|
||||
** Signal transmitter **
|
||||
************************/
|
||||
|
@ -24,7 +24,7 @@
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
namespace Genode { Rm_session * env_stack_area_rm_session(); }
|
||||
namespace Genode { extern Rm_session * const env_stack_area_rm_session; }
|
||||
|
||||
namespace Hw {
|
||||
extern Ram_dataspace_capability _main_thread_utcb_ds;
|
||||
@ -51,7 +51,7 @@ void Thread_base::_init_platform_thread(size_t weight, Type type)
|
||||
size_t const utcb_size = sizeof(Native_utcb);
|
||||
addr_t const stack_area = stack_area_virtual_base();
|
||||
addr_t const utcb_new = (addr_t)&_stack->utcb() - stack_area;
|
||||
Rm_session * const rm = env_stack_area_rm_session();
|
||||
Rm_session * const rm = env_stack_area_rm_session;
|
||||
|
||||
if (type == REINITIALIZED_MAIN) { rm->detach(utcb_new); }
|
||||
|
||||
@ -78,7 +78,7 @@ void Thread_base::_deinit_platform_thread()
|
||||
size_t const size = sizeof(_stack->utcb());
|
||||
addr_t utcb = Stack_allocator::addr_to_base(_stack) +
|
||||
stack_virtual_size() - size - stack_area_virtual_base();
|
||||
env_stack_area_rm_session()->detach(utcb);
|
||||
env_stack_area_rm_session->detach(utcb);
|
||||
|
||||
if (_pager_cap.valid()) {
|
||||
env()->rm_session()->remove_client(_pager_cap);
|
||||
@ -101,7 +101,7 @@ void Thread_base::start()
|
||||
size_t const size = sizeof(_stack->utcb());
|
||||
addr_t dst = Stack_allocator::addr_to_base(_stack) +
|
||||
stack_virtual_size() - size - stack_area_virtual_base();
|
||||
env_stack_area_rm_session()->attach_at(ds, dst, size);
|
||||
env_stack_area_rm_session->attach_at(ds, dst, size);
|
||||
} catch (...) {
|
||||
PERR("failed to attach userland stack");
|
||||
sleep_forever();
|
||||
|
@ -49,18 +49,6 @@ HOST_SO_SEARCH_DIRS := $(sort $(dir $(shell $(LDCONFIG) -p | sed "s/^.* \//\//"
|
||||
LINK_ARG_PREFIX := -Wl,
|
||||
CXX_LINK_OPT += $(addprefix $(LINK_ARG_PREFIX)-rpath-link $(LINK_ARG_PREFIX),$(HOST_SO_SEARCH_DIRS))
|
||||
|
||||
#
|
||||
# The '__libc_csu_init' function is normally provided by the C library. We
|
||||
# override the libc's version in our 'lx_hybrid' library to have a hook for
|
||||
# Genode-specific initializations. Unfortunately, this way, we get two symbols
|
||||
# with the same name. So we have to tell the linker to be forgiving. The order
|
||||
# of the libraries at the linker command line determines which symbol is used.
|
||||
# Therefore it is important to have 'lx_hybrid.lib.so' listed before '-lc',
|
||||
# which is always the case when supplying '-lc' via 'EXT_OBJECTS' (not
|
||||
# 'CXX_LINK_OPT').
|
||||
#
|
||||
CXX_LINK_OPT += -Wl,--allow-multiple-definition
|
||||
|
||||
#
|
||||
# Make exceptions work
|
||||
#
|
||||
@ -71,7 +59,7 @@ CXX_LINK_OPT += -Wl,--eh-frame-hdr
|
||||
# variable to the linker command line
|
||||
#
|
||||
ifneq ($(LX_LIBS),)
|
||||
EXT_OBJECTS = $(shell pkg-config --static --libs $(LX_LIBS))
|
||||
LX_LIBS_OPT = $(shell pkg-config --static --libs $(LX_LIBS))
|
||||
endif
|
||||
|
||||
#
|
||||
@ -89,8 +77,8 @@ EXT_OBJECTS += $(shell $(CUSTOM_CC) $(CC_MARCH) -print-file-name=crtbegin.o)
|
||||
EXT_OBJECTS += $(shell $(CUSTOM_CC) $(CC_MARCH) -print-file-name=crtend.o)
|
||||
endif
|
||||
EXT_OBJECTS += $(shell cc $(CC_MARCH) -print-file-name=crtn.o)
|
||||
EXT_OBJECTS += -lgcc -lgcc_s -lsupc++ -lc
|
||||
EXT_OBJECTS += -lpthread
|
||||
|
||||
LX_LIBS_OPT += -lgcc -lgcc_s -lsupc++ -lc -lpthread
|
||||
|
||||
USE_HOST_LD_SCRIPT = yes
|
||||
|
||||
@ -104,8 +92,11 @@ CXX_LINK_OPT += -Wl,--dynamic-linker=/lib/ld-linux.so.2
|
||||
endif
|
||||
endif
|
||||
|
||||
# because we use the host compiler's libgcc, omit the Genode toolchain's version
|
||||
LD_LIBGCC =
|
||||
#
|
||||
# Because we use the host compiler's libgcc, omit the Genode toolchain's
|
||||
# version and put all libraries here we depend on.
|
||||
#
|
||||
LD_LIBGCC = $(LX_LIBS_OPT)
|
||||
|
||||
# use the host c++ for linking to find shared libraries in DT_RPATH library paths
|
||||
LD_CMD = c++
|
||||
|
@ -23,6 +23,8 @@ SRC_CC += thread/trace.cc thread/thread_env.cc thread/stack_allocator.cc
|
||||
SRC_CC += irq/platform.cc
|
||||
SRC_CC += sleep.cc
|
||||
SRC_CC += rm_session_client.cc
|
||||
SRC_CC += entrypoint/entrypoint.cc
|
||||
SRC_CC += component/component.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/include $(BASE_DIR)/src/include
|
||||
|
||||
|
15
repos/base-linux/src/base/env/platform_env.cc
vendored
15
repos/base-linux/src/base/env/platform_env.cc
vendored
@ -76,8 +76,7 @@ Platform_env::Local_parent::session(Service_name const &service_name,
|
||||
if (size != ~0UL)
|
||||
size = align_addr(size, get_page_size_log2());
|
||||
|
||||
Rm_session_mmap *rm = new (env()->heap())
|
||||
Rm_session_mmap(true, size);
|
||||
Rm_session_mmap *rm = new (_alloc) Rm_session_mmap(true, size);
|
||||
|
||||
return Local_capability<Session>::local_cap(rm);
|
||||
}
|
||||
@ -106,8 +105,10 @@ void Platform_env::Local_parent::close(Session_capability session)
|
||||
|
||||
|
||||
Platform_env::Local_parent::Local_parent(Parent_capability parent_cap,
|
||||
Emergency_ram_reserve &reserve)
|
||||
: Expanding_parent_client(parent_cap, reserve)
|
||||
Emergency_ram_reserve &reserve,
|
||||
Allocator &alloc)
|
||||
:
|
||||
Expanding_parent_client(parent_cap, reserve), _alloc(alloc)
|
||||
{ }
|
||||
|
||||
|
||||
@ -150,7 +151,7 @@ static Parent_capability obtain_parent_cap()
|
||||
|
||||
Platform_env::Local_parent &Platform_env::_parent()
|
||||
{
|
||||
static Local_parent local_parent(obtain_parent_cap(), *this);
|
||||
static Local_parent local_parent(obtain_parent_cap(), *this, _heap);
|
||||
return local_parent;
|
||||
}
|
||||
|
||||
@ -161,8 +162,12 @@ Platform_env::Platform_env()
|
||||
static_cap_cast<Cpu_session>(_parent().session("Env::cpu_session", "")),
|
||||
static_cap_cast<Pd_session> (_parent().session("Env::pd_session", ""))),
|
||||
_heap(Platform_env_base::ram_session(), Platform_env_base::rm_session()),
|
||||
_stack_area(*parent(), *rm_session()),
|
||||
_emergency_ram_ds(ram_session()->alloc(_emergency_ram_size()))
|
||||
{
|
||||
env_stack_area_ram_session = ram_session();
|
||||
env_stack_area_rm_session = &_stack_area;
|
||||
|
||||
/* register TID and PID of the main thread at core */
|
||||
cpu_session()->thread_id(parent()->main_thread_cap(),
|
||||
lx_getpid(), lx_gettid());
|
||||
|
@ -28,6 +28,8 @@
|
||||
/* base-internal includes */
|
||||
#include <base/internal/platform_env.h>
|
||||
|
||||
namespace Genode { void init_stack_area(); }
|
||||
|
||||
namespace Genode {
|
||||
|
||||
/**
|
||||
@ -136,7 +138,15 @@ namespace Genode {
|
||||
|
||||
typedef Synchronized_ram_session<Ram_session_component> Core_ram_session;
|
||||
|
||||
Core_parent _core_parent;
|
||||
Core_parent _core_parent;
|
||||
|
||||
/*
|
||||
* 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();
|
||||
|
||||
Entrypoint _entrypoint;
|
||||
Core_ram_session _ram_session;
|
||||
|
||||
@ -153,6 +163,8 @@ namespace Genode {
|
||||
Heap _heap;
|
||||
Ram_session_capability const _ram_session_cap;
|
||||
|
||||
enum { SIGNAL_RAM_QUOTA = 1024*sizeof(long) };
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -195,7 +207,7 @@ namespace Genode {
|
||||
Pd_session *pd_session() override { return &_pd_session_client; }
|
||||
Allocator *heap() override { return &_heap; }
|
||||
|
||||
Cpu_session_capability cpu_session_cap()
|
||||
Cpu_session_capability cpu_session_cap() override
|
||||
{
|
||||
PWRN("%s:%u not implemented", __FILE__, __LINE__);
|
||||
return Cpu_session_capability();
|
||||
|
@ -105,16 +105,16 @@ class Stack_area_ram_session : public Genode::Ram_session
|
||||
*/
|
||||
namespace Genode {
|
||||
|
||||
Rm_session *env_stack_area_rm_session()
|
||||
{
|
||||
static Stack_area_rm_session inst;
|
||||
return &inst;
|
||||
}
|
||||
Rm_session *env_stack_area_rm_session;
|
||||
Ram_session *env_stack_area_ram_session;
|
||||
|
||||
Ram_session *env_stack_area_ram_session()
|
||||
void init_stack_area()
|
||||
{
|
||||
static Stack_area_ram_session inst;
|
||||
return &inst;
|
||||
static Stack_area_rm_session rm_inst;
|
||||
env_stack_area_rm_session = &rm_inst;
|
||||
|
||||
static Stack_area_ram_session ram_inst;
|
||||
env_stack_area_ram_session = &ram_inst;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -314,10 +314,6 @@ namespace Genode {
|
||||
|
||||
private:
|
||||
|
||||
/*******************************
|
||||
** Platform-specific members **
|
||||
*******************************/
|
||||
|
||||
Ram_session_capability _ram_session_cap;
|
||||
Expanding_ram_session_client _ram_session_client;
|
||||
Cpu_session_capability _cpu_session_cap;
|
||||
@ -362,8 +358,8 @@ namespace Genode {
|
||||
*
|
||||
* Not supported on Linux.
|
||||
*/
|
||||
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 { }
|
||||
};
|
||||
|
||||
|
||||
@ -388,6 +384,10 @@ namespace Genode {
|
||||
*/
|
||||
class Local_parent : public Expanding_parent_client
|
||||
{
|
||||
private:
|
||||
|
||||
Allocator &_alloc;
|
||||
|
||||
public:
|
||||
|
||||
/**********************
|
||||
@ -407,7 +407,8 @@ namespace Genode {
|
||||
* services
|
||||
*/
|
||||
Local_parent(Parent_capability parent_cap,
|
||||
Emergency_ram_reserve &);
|
||||
Emergency_ram_reserve &,
|
||||
Allocator &);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -417,6 +418,13 @@ namespace Genode {
|
||||
|
||||
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;
|
||||
|
||||
/*
|
||||
* Emergency RAM reserve
|
||||
*
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* \brief Supplemental code for hybrid Genode/Linux programs
|
||||
* \brief Supplemental code for hybrid Genode/Linux components
|
||||
* \author Norman Feske
|
||||
* \date 2011-09-02
|
||||
*/
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <base/component.h>
|
||||
#include <linux_syscalls.h>
|
||||
#include <linux_cpu_session/linux_cpu_session.h>
|
||||
|
||||
@ -66,16 +67,45 @@ __attribute__((constructor(101))) void lx_hybrid_init()
|
||||
lx_sigaction(LX_SIGUSR1, empty_signal_handler);
|
||||
}
|
||||
|
||||
namespace Genode {
|
||||
extern void bootstrap_component();
|
||||
extern void call_global_static_constructors();
|
||||
|
||||
/*
|
||||
* 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 lx_hybrid_component_construct(Genode::Environment &env)
|
||||
{
|
||||
Component::construct(env);
|
||||
}
|
||||
|
||||
void (*Genode::call_component_construct)(Genode::Environment &) = &lx_hybrid_component_construct;
|
||||
|
||||
/*
|
||||
* Dummy symbols to let generic tests programs (i.e., 'test-config_args') link
|
||||
* successfully. Please note that such programs are not expected to work when
|
||||
* built as hybrid Linux/Genode programs because when using the glibc startup
|
||||
* code, we cannot manipulate argv prior executing main. However, by defining
|
||||
* these symbols, we prevent the automated build bot from stumbling over such
|
||||
* binaries.
|
||||
* Static constructors are handled by the Linux startup code - so implement
|
||||
* this as empty function.
|
||||
*/
|
||||
char **genode_argv = 0;
|
||||
int genode_argc = 1;
|
||||
void Genode::call_global_static_constructors() { }
|
||||
|
||||
/*
|
||||
* Hybrid components are not allowed to implement legacy main(). This enables
|
||||
* us to hook in and bootstrap components as usual.
|
||||
*/
|
||||
|
||||
int main()
|
||||
{
|
||||
Genode::bootstrap_component();
|
||||
|
||||
/* never reached */
|
||||
}
|
||||
|
||||
|
||||
/************
|
||||
|
@ -11,11 +11,16 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/component.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
/* local includes */
|
||||
#include "testlib.h"
|
||||
|
||||
/* Linux includes */
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
@ -35,7 +40,18 @@ extern Testlib_testclass testlib_testobject;
|
||||
Testapp_testclass testapp_testobject;
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
static int exit_status;
|
||||
static void exit_on_suspended() { exit(exit_status); }
|
||||
|
||||
|
||||
Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); }
|
||||
char const * Component::name() { return "lx_hybrid_ctors"; }
|
||||
|
||||
|
||||
/*
|
||||
* Component implements classical main function in construct.
|
||||
*/
|
||||
void Component::construct(Genode::Environment &env)
|
||||
{
|
||||
printf("--- lx_hybrid global static constructor test ---\n");
|
||||
|
||||
@ -47,6 +63,6 @@ int main(int argc, char *argv[])
|
||||
testapp_testobject.dummy();
|
||||
|
||||
printf("--- returning from main ---\n");
|
||||
|
||||
return 0;
|
||||
exit_status = 0;
|
||||
env.ep().schedule_suspend(exit_on_suspended, nullptr);
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/component.h>
|
||||
#include <base/thread.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
@ -12,6 +13,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
enum { STACK_SIZE = 4096 };
|
||||
|
||||
@ -40,7 +42,20 @@ struct Thread : Genode::Thread<STACK_SIZE>
|
||||
};
|
||||
|
||||
|
||||
int main(int, char **)
|
||||
static int exit_status;
|
||||
static void exit_on_suspended() { exit(exit_status); }
|
||||
|
||||
|
||||
Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); }
|
||||
char const * Component::name() { return "lx_hybrid_errno"; }
|
||||
|
||||
|
||||
struct Unexpected_errno_change { };
|
||||
|
||||
/*
|
||||
* Component implements classical main function in construct.
|
||||
*/
|
||||
void Component::construct(Genode::Environment &env)
|
||||
{
|
||||
Genode::printf("--- thread-local errno test ---\n");
|
||||
|
||||
@ -60,9 +75,10 @@ int main(int, char **)
|
||||
|
||||
if (orig_errno != errno) {
|
||||
PERR("unexpected change of main thread's errno value");
|
||||
return -1;
|
||||
throw Unexpected_errno_change();
|
||||
}
|
||||
|
||||
Genode::printf("--- finished thread-local errno test ---\n");
|
||||
return 0;
|
||||
exit_status = 0;
|
||||
env.ep().schedule_suspend(exit_on_suspended, nullptr);
|
||||
}
|
||||
|
@ -11,27 +11,41 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/component.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
/* Linux includes */
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace Genode;
|
||||
|
||||
|
||||
class Test_exception { };
|
||||
|
||||
/**
|
||||
* Main program
|
||||
static int exit_status;
|
||||
static void exit_on_suspended() { exit(exit_status); }
|
||||
|
||||
|
||||
Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); }
|
||||
char const * Component::name() { return "lx_hybrid_exception"; }
|
||||
|
||||
|
||||
/*
|
||||
* Component implements classical main function in construct.
|
||||
*/
|
||||
int main(int, char **)
|
||||
void Component::construct(Genode::Environment &env)
|
||||
{
|
||||
printf("--- lx_hybrid exception test ---\n");
|
||||
|
||||
try {
|
||||
printf("Throwing Test_exception\n");
|
||||
throw Test_exception();
|
||||
} catch(Test_exception) {
|
||||
} catch (Test_exception) {
|
||||
printf("Caught Test_exception\n");
|
||||
}
|
||||
|
||||
printf("--- returning from main ---\n");
|
||||
|
||||
return 0;
|
||||
exit_status = 0;
|
||||
env.ep().schedule_suspend(exit_on_suspended, nullptr);
|
||||
}
|
||||
|
@ -12,11 +12,14 @@
|
||||
*/
|
||||
|
||||
/* Genode includes */
|
||||
#include <base/component.h>
|
||||
#include <base/thread.h>
|
||||
#include <base/printf.h>
|
||||
|
||||
/* libc includes */
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
|
||||
static Genode::Lock *main_wait_lock()
|
||||
@ -46,7 +49,18 @@ static void *pthread_entry(void *)
|
||||
}
|
||||
|
||||
|
||||
int main(int, char **)
|
||||
static int exit_status;
|
||||
static void exit_on_suspended() { exit(exit_status); }
|
||||
|
||||
|
||||
Genode::size_t Component::stack_size() { return 16*1024*sizeof(long); }
|
||||
char const * Component::name() { return "lx_hybrid_pthread_ipc"; }
|
||||
|
||||
|
||||
/*
|
||||
* Component implements classical main function in construct.
|
||||
*/
|
||||
void Component::construct(Genode::Environment &env)
|
||||
{
|
||||
Genode::printf("--- pthread IPC test ---\n");
|
||||
|
||||
@ -58,5 +72,6 @@ int main(int, char **)
|
||||
main_wait_lock()->lock();
|
||||
|
||||
Genode::printf("--- finished pthread IPC test ---\n");
|
||||
return 0;
|
||||
exit_status = 0;
|
||||
env.ep().schedule_suspend(exit_on_suspended, nullptr);
|
||||
}
|
||||
|
@ -43,22 +43,6 @@ namespace Genode {
|
||||
*/
|
||||
Native_capability _sem;
|
||||
|
||||
/**
|
||||
* Request NOVA semaphore from signal-source server
|
||||
*/
|
||||
void _init_sem()
|
||||
{
|
||||
/* initialize semaphore only once */
|
||||
if (_sem.valid()) return;
|
||||
|
||||
/* request mapping of semaphore capability selector */
|
||||
Thread_base * myself = Thread_base::myself();
|
||||
request_signal_sm_cap(Native_capability(myself->native_thread().ec_sel + 1),
|
||||
myself->native_thread().exc_pt_sel + Nova::PT_SEL_STARTUP);
|
||||
_sem = Native_capability(myself->native_thread().exc_pt_sel + Nova::PT_SEL_STARTUP);
|
||||
call<Rpc_register_semaphore>(_sem);
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
@ -67,11 +51,17 @@ namespace Genode {
|
||||
Signal_source_client(Capability<Signal_source> cap)
|
||||
: Rpc_client<Nova_signal_source>(static_cap_cast<Nova_signal_source>(cap))
|
||||
{
|
||||
/*
|
||||
* Make sure that we have acquired the
|
||||
* semaphore from the server
|
||||
*/
|
||||
_init_sem();
|
||||
/* request mapping of semaphore capability selector */
|
||||
Thread_base * myself = Thread_base::myself();
|
||||
request_signal_sm_cap(Native_capability(myself->native_thread().ec_sel + 1),
|
||||
myself->native_thread().exc_pt_sel + Nova::PT_SEL_STARTUP);
|
||||
_sem = Native_capability(myself->native_thread().exc_pt_sel + Nova::PT_SEL_STARTUP);
|
||||
call<Rpc_register_semaphore>(_sem);
|
||||
}
|
||||
|
||||
~Signal_source_client()
|
||||
{
|
||||
Nova::revoke(Nova::Obj_crd(_sem.local_name(), 0));
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,6 +23,8 @@ SRC_CC += thread/myself.cc
|
||||
SRC_CC += thread/stack_allocator.cc env/cap_map.cc
|
||||
SRC_CC += sleep.cc
|
||||
SRC_CC += rm_session_client.cc
|
||||
SRC_CC += entrypoint/entrypoint.cc
|
||||
SRC_CC += component/component.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/include $(BASE_DIR)/src/include
|
||||
|
||||
|
@ -70,6 +70,8 @@ void Rpc_entrypoint::_dissolve(Rpc_object_base *obj)
|
||||
/* make sure nobody is able to find this object */
|
||||
remove(obj);
|
||||
|
||||
/* effectively invalidate the capability used before */
|
||||
obj->cap(Untyped_capability());
|
||||
|
||||
/*
|
||||
* The activation may execute a blocking operation in a dispatch function.
|
||||
|
@ -47,9 +47,6 @@ class Genode::Signal_source_component : public Rpc_object<Nova_signal_source,
|
||||
|
||||
void register_semaphore(Native_capability const &cap)
|
||||
{
|
||||
if (_blocking_semaphore.valid())
|
||||
PWRN("overwritting blocking signal semaphore !!!");
|
||||
|
||||
_blocking_semaphore = cap;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,8 @@ SRC_CC += thread/myself.cc
|
||||
SRC_CC += thread/stack_allocator.cc
|
||||
SRC_CC += sleep.cc
|
||||
SRC_CC += rm_session_client.cc
|
||||
SRC_CC += entrypoint/entrypoint.cc
|
||||
SRC_CC += component/component.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/include $(BASE_DIR)/src/include
|
||||
|
||||
|
@ -24,6 +24,8 @@ SRC_CC += thread/myself.cc
|
||||
SRC_CC += thread/stack_allocator.cc
|
||||
SRC_CC += sleep.cc
|
||||
SRC_CC += rm_session_client.cc
|
||||
SRC_CC += entrypoint/entrypoint.cc
|
||||
SRC_CC += component/component.cc
|
||||
|
||||
# suppress warning caused by Pistachio's 'l4/message.h'
|
||||
CC_WARN += -Wno-array-bounds
|
||||
|
@ -26,6 +26,8 @@ SRC_CC += thread/thread_bootstrap.cc
|
||||
SRC_CC += env/capability.cc
|
||||
SRC_CC += sleep.cc
|
||||
SRC_CC += rm_session_client.cc
|
||||
SRC_CC += entrypoint/entrypoint.cc
|
||||
SRC_CC += component/component.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/include $(BASE_DIR)/src/include
|
||||
|
||||
|
@ -133,20 +133,17 @@ class Stack_area_ram_session : public Ram_session
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Return single instance of the context-area RM and RAM session
|
||||
*/
|
||||
namespace Genode {
|
||||
|
||||
Rm_session *env_stack_area_rm_session()
|
||||
{
|
||||
static Stack_area_rm_session inst;
|
||||
return &inst;
|
||||
}
|
||||
Rm_session *env_stack_area_rm_session;
|
||||
Ram_session *env_stack_area_ram_session;
|
||||
|
||||
Ram_session *env_stack_area_ram_session()
|
||||
void init_stack_area()
|
||||
{
|
||||
static Stack_area_ram_session inst;
|
||||
return &inst;
|
||||
static Stack_area_rm_session rm_inst;
|
||||
env_stack_area_rm_session = &rm_inst;
|
||||
|
||||
static Stack_area_ram_session ram_inst;
|
||||
env_stack_area_ram_session = &ram_inst;
|
||||
}
|
||||
}
|
||||
|
78
repos/base/include/base/component.h
Normal file
78
repos/base/include/base/component.h
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* \brief Hook functions for bootstrapping the component
|
||||
* \author Norman Feske
|
||||
* \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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__BASE__COMPONENT_H_
|
||||
#define _INCLUDE__BASE__COMPONENT_H_
|
||||
|
||||
#include <base/stdint.h>
|
||||
#include <parent/parent.h>
|
||||
#include <base/entrypoint.h>
|
||||
#include <ram_session/capability.h>
|
||||
#include <cpu_session/capability.h>
|
||||
#include <rm_session/rm_session.h>
|
||||
#include <pd_session/pd_session.h>
|
||||
|
||||
|
||||
namespace Genode { struct Environment; }
|
||||
|
||||
|
||||
/**
|
||||
* Interface to be provided by the component implementation
|
||||
*/
|
||||
namespace Component
|
||||
{
|
||||
Genode::size_t stack_size();
|
||||
char const *name();
|
||||
void construct(Genode::Environment &);
|
||||
}
|
||||
|
||||
|
||||
struct Genode::Environment
|
||||
{
|
||||
virtual Parent &parent() = 0;
|
||||
|
||||
/**
|
||||
* RAM session of the component
|
||||
*
|
||||
* The RAM Session represents a budget of memory (quota) that is available
|
||||
* to the component. This budget can be used to allocate RAM dataspaces.
|
||||
*/
|
||||
virtual Ram_session &ram() = 0;
|
||||
|
||||
/**
|
||||
* CPU session of the component
|
||||
*
|
||||
* This session is used to create the threads of the component.
|
||||
*/
|
||||
virtual Cpu_session &cpu() = 0;
|
||||
|
||||
/**
|
||||
* Region-manager session of the component as created by the parent
|
||||
*/
|
||||
virtual Rm_session &rm() = 0;
|
||||
|
||||
/**
|
||||
* PD session of the component as created by the parent
|
||||
*/
|
||||
virtual Pd_session &pd() = 0;
|
||||
|
||||
/**
|
||||
* Entrypoint for handling RPC requests and signals
|
||||
*/
|
||||
virtual Entrypoint &ep() = 0;
|
||||
|
||||
virtual Ram_session_capability ram_session_cap() = 0;
|
||||
virtual Cpu_session_capability cpu_session_cap() = 0;
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__BASE__COMPONENT_H_ */
|
165
repos/base/include/base/entrypoint.h
Normal file
165
repos/base/include/base/entrypoint.h
Normal file
@ -0,0 +1,165 @@
|
||||
/*
|
||||
* \brief Entrypoint for serving RPC requests and dispatching signals
|
||||
* \author Norman Feske
|
||||
* \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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__BASE__ENTRYPOINT_H_
|
||||
#define _INCLUDE__BASE__ENTRYPOINT_H_
|
||||
|
||||
#include <util/volatile_object.h>
|
||||
#include <util/noncopyable.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <base/signal.h>
|
||||
#include <base/thread.h>
|
||||
|
||||
|
||||
namespace Genode {
|
||||
class Startup;
|
||||
class Entrypoint;
|
||||
class Environment;
|
||||
}
|
||||
|
||||
|
||||
class Genode::Entrypoint : Genode::Noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
struct Signal_proxy
|
||||
{
|
||||
GENODE_RPC(Rpc_signal, void, signal);
|
||||
GENODE_RPC_INTERFACE(Rpc_signal);
|
||||
};
|
||||
|
||||
struct Signal_proxy_component :
|
||||
Rpc_object<Signal_proxy, Signal_proxy_component>
|
||||
{
|
||||
Entrypoint &ep;
|
||||
Signal_proxy_component(Entrypoint &ep) : ep(ep) { }
|
||||
|
||||
void signal()
|
||||
{
|
||||
try {
|
||||
Signal sig = ep._sig_rec->pending_signal();
|
||||
ep._dispatch_signal(sig);
|
||||
} catch (Signal_receiver::Signal_not_pending) { }
|
||||
}
|
||||
};
|
||||
|
||||
enum { STACK_SIZE = 1024*sizeof(long) };
|
||||
|
||||
struct Signal_proxy_thread : Thread<STACK_SIZE>
|
||||
{
|
||||
Entrypoint &ep;
|
||||
Signal_proxy_thread(Entrypoint &ep)
|
||||
:
|
||||
Thread<STACK_SIZE>("signal_proxy"),
|
||||
ep(ep)
|
||||
{ }
|
||||
|
||||
void entry() override { ep._process_incoming_signals(); }
|
||||
};
|
||||
|
||||
Environment &_env;
|
||||
|
||||
Volatile_object<Rpc_entrypoint> _rpc_ep;
|
||||
|
||||
Signal_proxy_component _signal_proxy {*this};
|
||||
Capability<Signal_proxy> _signal_proxy_cap = _rpc_ep->manage(&_signal_proxy);
|
||||
|
||||
Volatile_object<Signal_receiver> _sig_rec;
|
||||
|
||||
void (*_suspended_callback) () = nullptr;
|
||||
void (*_resumed_callback) () = nullptr;
|
||||
|
||||
/*
|
||||
* This signal handler is solely used to force an iteration of the
|
||||
* signal-dispatch loop. It is triggered by 'schedule_suspend' to
|
||||
* let the signal-dispatching thread execute the actual suspend-
|
||||
* resume mechanism.
|
||||
*/
|
||||
void _handle_suspend(unsigned) { }
|
||||
Lazy_volatile_object<Genode::Signal_handler<Entrypoint>> _suspend_dispatcher;
|
||||
|
||||
void _dispatch_signal(Signal &sig);
|
||||
|
||||
void _process_incoming_signals();
|
||||
|
||||
Lazy_volatile_object<Signal_proxy_thread> _signal_proxy_thread;
|
||||
|
||||
friend class Startup;
|
||||
|
||||
|
||||
/**
|
||||
* Called by the startup code only
|
||||
*/
|
||||
Entrypoint(Environment &env);
|
||||
|
||||
public:
|
||||
|
||||
Entrypoint(Environment &env, size_t stack_size, char const *name);
|
||||
|
||||
/**
|
||||
* Associate RPC object with the entry point
|
||||
*/
|
||||
template <typename RPC_INTERFACE, typename RPC_SERVER>
|
||||
Capability<RPC_INTERFACE>
|
||||
manage(Rpc_object<RPC_INTERFACE, RPC_SERVER> &obj)
|
||||
{
|
||||
return _rpc_ep->manage(&obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dissolve RPC object from entry point
|
||||
*/
|
||||
template <typename RPC_INTERFACE, typename RPC_SERVER>
|
||||
void dissolve(Rpc_object<RPC_INTERFACE, RPC_SERVER> &obj)
|
||||
{
|
||||
_rpc_ep->dissolve(&obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate signal dispatcher with entry point
|
||||
*/
|
||||
Signal_context_capability manage(Signal_dispatcher_base &);
|
||||
|
||||
/**
|
||||
* Disassociate signal dispatcher from entry point
|
||||
*/
|
||||
void dissolve(Signal_dispatcher_base &);
|
||||
|
||||
/**
|
||||
* Block and dispatch a single signal, return afterwards
|
||||
*
|
||||
* XXX Turn into static function that ensures that the used signal
|
||||
* receiver belongs to the calling entrypoint. Alternatively,
|
||||
* remove it.
|
||||
*/
|
||||
void wait_and_dispatch_one_signal()
|
||||
{
|
||||
Signal sig = _sig_rec->wait_for_signal();
|
||||
_dispatch_signal(sig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return RPC entrypoint
|
||||
*/
|
||||
Rpc_entrypoint &rpc_ep() { return *_rpc_ep; }
|
||||
|
||||
/**
|
||||
* Trigger a suspend-resume cycle in the entrypoint
|
||||
*
|
||||
* 'suspended' is called after the entrypoint entered the safe suspend
|
||||
* state, while 'resumed is called when the entrypoint is fully functional again.
|
||||
*/
|
||||
void schedule_suspend(void (*suspended)(), void (*resumed)());
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__BASE__ENTRYPOINT_H_ */
|
@ -22,7 +22,6 @@
|
||||
#include <cpu_session/cpu_session.h>
|
||||
#include <cpu_session/capability.h>
|
||||
#include <pd_session/capability.h>
|
||||
#include <cap_session/cap_session.h>
|
||||
#include <base/allocator.h>
|
||||
#include <base/snprintf.h>
|
||||
#include <base/lock.h>
|
||||
@ -107,7 +106,7 @@ struct Genode::Env
|
||||
/**
|
||||
* Reinitialize main-thread object
|
||||
*
|
||||
* \param stack_area_rm new RM session of the context area
|
||||
* \param stack_area_rm new RM session of the stack area
|
||||
*
|
||||
* This function is solely used for implementing fork semantics
|
||||
* as provided by the Noux environment.
|
||||
|
@ -27,6 +27,7 @@ namespace Kernel { struct Signal_receiver; }
|
||||
|
||||
namespace Genode {
|
||||
|
||||
class Entrypoint;
|
||||
class Signal_source;
|
||||
|
||||
class Signal_receiver;
|
||||
@ -433,4 +434,45 @@ class Genode::Signal_dispatcher : public Signal_dispatcher_base,
|
||||
void dispatch(unsigned num) { (obj.*member)(num); }
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Signal dispatcher for handling signals by an object method
|
||||
*
|
||||
* This utility associates object methods with signals. It is intended to
|
||||
* be used as a member variable of the class that handles incoming signals
|
||||
* of a certain type. The constructor takes a pointer-to-member to the
|
||||
* signal-handling method as argument. If a signal is received at the
|
||||
* common signal reception code, this method will be invoked by calling
|
||||
* 'Signal_dispatcher_base::dispatch'.
|
||||
*
|
||||
* \param T type of signal-handling class
|
||||
* \param EP type of entrypoint handling signal RPC
|
||||
*/
|
||||
template <typename T, typename EP = Genode::Entrypoint>
|
||||
struct Genode::Signal_handler : Genode::Signal_dispatcher_base,
|
||||
Genode::Signal_context_capability
|
||||
{
|
||||
EP &ep;
|
||||
T &obj;
|
||||
void (T::*member) (unsigned);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param ep entrypoint managing this signal RPC
|
||||
* \param obj,member object and method to call when
|
||||
* the signal occurs
|
||||
*/
|
||||
Signal_handler(EP &ep, T &obj, void (T::*member)(unsigned))
|
||||
: Signal_context_capability(ep.manage(*this)),
|
||||
ep(ep), obj(obj), member(member) { }
|
||||
|
||||
~Signal_handler() { ep.dissolve(*this); }
|
||||
|
||||
/**
|
||||
* Interface of Signal_dispatcher_base
|
||||
*/
|
||||
void dispatch(unsigned num) { (obj.*member)(num); }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__BASE__SIGNAL_H_ */
|
||||
|
@ -61,8 +61,11 @@ class Genode::Volatile_object
|
||||
|
||||
void _check_constructed() const
|
||||
{
|
||||
if (!_constructed)
|
||||
if (!_constructed) {
|
||||
PDBG("Deref_unconstructed_object");
|
||||
PDBG("bt: %p", __builtin_return_address(0));
|
||||
throw Deref_unconstructed_object();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
|
6
repos/base/lib/import/import-ld.mk
Normal file
6
repos/base/lib/import/import-ld.mk
Normal file
@ -0,0 +1,6 @@
|
||||
#
|
||||
# All dynamic executables must be linked to the component entry-point library
|
||||
# (a trampoline for component startup from ldso), so, enforce the library
|
||||
# dependency here.
|
||||
#
|
||||
LIBS += component_entry_point
|
7
repos/base/lib/mk/component_entry_point.mk
Normal file
7
repos/base/lib/mk/component_entry_point.mk
Normal file
@ -0,0 +1,7 @@
|
||||
#
|
||||
# Component entry point (a trampoline for component startup from ldso)
|
||||
#
|
||||
|
||||
SRC_CC = component_entry_point.cc component_construct.cc
|
||||
|
||||
vpath %.cc $(REP_DIR)/src/lib/startup
|
@ -24,6 +24,8 @@ ENTRY_POINT = _start
|
||||
LD_OPT += -T$(DIR)/linker.ld
|
||||
endif
|
||||
|
||||
include $(REP_DIR)/lib/import/import-ld.mk
|
||||
|
||||
vpath %.cc $(DIR)
|
||||
|
||||
# vi:ft=make
|
||||
|
@ -1,5 +1,5 @@
|
||||
SRC_S += crt0.s
|
||||
SRC_CC += _main.cc init_main_thread.cc
|
||||
SRC_CC += _main.cc init_main_thread.cc component_construct.cc
|
||||
REP_INC_DIR += src/include
|
||||
LIBS += syscall
|
||||
|
||||
|
@ -128,6 +128,13 @@ LD_CMD += -Wl,--dynamic-linker=$(DYNAMIC_LINKER).lib.so \
|
||||
FILTER_DEPS := $(filter-out $(BASE_LIBS),$(DEPS:.lib=))
|
||||
SHARED_LIBS += $(LIB_CACHE_DIR)/$(DYNAMIC_LINKER)/$(DYNAMIC_LINKER).lib.so
|
||||
|
||||
|
||||
#
|
||||
# Link all dynamic executables to the component entry-point library (a
|
||||
# trampoline for component startup from ldso)
|
||||
#
|
||||
FILTER_DEPS += component_entry_point
|
||||
|
||||
#
|
||||
# Build program position independent as well
|
||||
#
|
||||
|
76
repos/base/src/base/component/component.cc
Normal file
76
repos/base/src/base/component/component.cc
Normal 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 */
|
||||
}
|
191
repos/base/src/base/entrypoint/entrypoint.cc
Normal file
191
repos/base/src/base/entrypoint/entrypoint.cc
Normal 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);
|
||||
}
|
||||
|
9
repos/base/src/base/env/reinitialize.cc
vendored
9
repos/base/src/base/env/reinitialize.cc
vendored
@ -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);
|
||||
|
||||
|
48
repos/base/src/base/env/stack_area.cc
vendored
48
repos/base/src/base/env/stack_area.cc
vendored
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 */
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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 { }
|
||||
};
|
||||
|
||||
|
||||
|
@ -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()
|
||||
{
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
||||
/*************************************
|
||||
|
@ -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_ */
|
||||
|
@ -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) }
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
98
repos/base/src/lib/startup/component_construct.cc
Normal file
98
repos/base/src/lib/startup/component_construct.cc
Normal 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";
|
||||
}
|
32
repos/base/src/lib/startup/component_entry_point.cc
Normal file
32
repos/base/src/lib/startup/component_entry_point.cc
Normal 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);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -15,9 +15,13 @@ SRC_CC = atexit.cc dummies.cc rlimit.cc sysctl.cc \
|
||||
plugin.cc plugin_registry.cc select.cc exit.cc environ.cc nanosleep.cc \
|
||||
libc_mem_alloc.cc pread_pwrite.cc readv_writev.cc poll.cc \
|
||||
libc_pdbg.cc vfs_plugin.cc rtc.cc dynamic_linker.cc signal.cc \
|
||||
socket_operations.cc
|
||||
socket_operations.cc task.cc
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/lib/libc
|
||||
INC_DIR += $(REP_DIR)/src/lib/libc/include
|
||||
|
||||
# needed for base/internal/unmanaged_singleton.h
|
||||
INC_DIR += $(BASE_DIR)/src/include
|
||||
|
||||
#
|
||||
# Files from string library that are not included in libc-raw_string because
|
||||
|
3
repos/libports/lib/mk/spec/arm/libc.mk
Normal file
3
repos/libports/lib/mk/spec/arm/libc.mk
Normal file
@ -0,0 +1,3 @@
|
||||
include $(REP_DIR)/lib/mk/libc.mk
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/lib/libc/include/spec/arm
|
3
repos/libports/lib/mk/spec/x86_32/libc.mk
Normal file
3
repos/libports/lib/mk/spec/x86_32/libc.mk
Normal file
@ -0,0 +1,3 @@
|
||||
include $(REP_DIR)/lib/mk/libc.mk
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/lib/libc/include/spec/x86_32
|
3
repos/libports/lib/mk/spec/x86_64/libc.mk
Normal file
3
repos/libports/lib/mk/spec/x86_64/libc.mk
Normal file
@ -0,0 +1,3 @@
|
||||
include $(REP_DIR)/lib/mk/libc.mk
|
||||
|
||||
INC_DIR += $(REP_DIR)/src/lib/libc/include/spec/x86_64
|
@ -1,8 +1,8 @@
|
||||
build "core init test/ldso test/ldso/dl"
|
||||
build "core init test/ldso"
|
||||
|
||||
create_boot_directory
|
||||
|
||||
install_config {
|
||||
set config {
|
||||
<config>
|
||||
<parent-provides>
|
||||
<service name="ROM"/>
|
||||
@ -23,6 +23,8 @@ install_config {
|
||||
</config>
|
||||
}
|
||||
|
||||
install_config $config
|
||||
|
||||
set boot_modules {
|
||||
core init test-ldso test-ldso_lib_1.lib.so
|
||||
test-ldso_lib_2.lib.so test-ldso_lib_dl.lib.so
|
||||
|
@ -37,5 +37,5 @@ build_boot_image {
|
||||
|
||||
append qemu_args " -nographic -m 64 "
|
||||
|
||||
run_genode_until "--- returning from main ---" 10
|
||||
run_genode_until "child .* exited with exit value 0.*\n" 10
|
||||
|
||||
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* \brief User-level task helpers (arm)
|
||||
* \author Christian Helmuth
|
||||
* \date 2016-01-22
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__SPEC__ARM__INTERNAL__CALL_FUNC_H_
|
||||
#define _INCLUDE__SPEC__ARM__INTERNAL__CALL_FUNC_H_
|
||||
|
||||
/* Libc includes */
|
||||
#include <setjmp.h> /* _setjmp() as we don't care about signal state */
|
||||
|
||||
|
||||
/**
|
||||
* Call function with a new stack
|
||||
*/
|
||||
[[noreturn]] inline void call_func(void *sp, void *func, void *arg)
|
||||
{
|
||||
asm volatile ("mov r0, %2;" /* set arg */
|
||||
"mov sp, %0;" /* set stack */
|
||||
"mov pc, %1;" /* call func */
|
||||
""
|
||||
: : "r"(sp), "r"(func), "r"(arg) : "r0");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__SPEC__ARM__INTERNAL__CALL_FUNC_H_ */
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* \brief User-level task helpers (x86_32)
|
||||
* \author Christian Helmuth
|
||||
* \date 2016-01-22
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__SPEC__X86_32__INTERNAL__CALL_FUNC_H_
|
||||
#define _INCLUDE__SPEC__X86_32__INTERNAL__CALL_FUNC_H_
|
||||
|
||||
/* Libc includes */
|
||||
#include <setjmp.h> /* _setjmp() as we don't care about signal state */
|
||||
|
||||
|
||||
/**
|
||||
* Call function with a new stack
|
||||
*/
|
||||
[[noreturn]] inline void call_func(void *sp, void *func, void *arg)
|
||||
{
|
||||
asm volatile ("movl %2, 0(%0);"
|
||||
"movl %1, -0x4(%0);"
|
||||
"movl %0, %%esp;"
|
||||
"call *-4(%%esp);"
|
||||
: : "r" (sp), "r" (func), "r" (arg));
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__SPEC__X86_32__INTERNAL__CALL_FUNC_H_ */
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* \brief User-level task helpers (x86_64)
|
||||
* \author Christian Helmuth
|
||||
* \date 2016-01-22
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _INCLUDE__SPEC__X86_64__INTERNAL__CALL_FUNC_H_
|
||||
#define _INCLUDE__SPEC__X86_64__INTERNAL__CALL_FUNC_H_
|
||||
|
||||
/* Libc includes */
|
||||
#include <setjmp.h> /* _setjmp() as we don't care about signal state */
|
||||
|
||||
|
||||
/**
|
||||
* Call function with a new stack
|
||||
*/
|
||||
[[noreturn]] inline void call_func(void *sp, void *func, void *arg)
|
||||
{
|
||||
asm volatile ("movq %0, %%rsp;" /* load stack pointer */
|
||||
"movq %%rsp, %%rbp;" /* caller stack frame (for GDB debugging) */
|
||||
"movq %0, -8(%%rbp);"
|
||||
"movq %1, -16(%%rbp);"
|
||||
"movq %2, -24(%%rbp);"
|
||||
"sub $24, %%rsp;" /* adjust to next stack frame */
|
||||
"movq %2, %%rdi;" /* 1st argument */
|
||||
"call *-16(%%rbp);" /* call func */
|
||||
: : "r" (sp), "r" (func), "r" (arg));
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif /* _INCLUDE__SPEC__X86_64__INTERNAL__CALL_FUNC_H_ */
|
198
repos/libports/src/lib/libc/task.cc
Normal file
198
repos/libports/src/lib/libc/task.cc
Normal file
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* \brief User-level task based libc
|
||||
* \author Christian Helmuth
|
||||
* \date 2016-01-22
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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/printf.h>
|
||||
#include <base/thread.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <base/rpc_client.h>
|
||||
|
||||
/* libc-internal includes */
|
||||
#include <internal/call_func.h>
|
||||
#include <base/internal/unmanaged_singleton.h>
|
||||
|
||||
|
||||
#define P(fmt,...) \
|
||||
do { \
|
||||
int dummy; \
|
||||
Genode::printf(ESC_INF "[%lx] %s:%u " fmt ESC_END "\n", \
|
||||
(unsigned long)&dummy >> 20, \
|
||||
__PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
|
||||
namespace Libc {
|
||||
class Task;
|
||||
|
||||
void (*original_call_component_construct)(Genode::Environment &);
|
||||
void call_component_construct(Genode::Environment &env);
|
||||
}
|
||||
|
||||
|
||||
struct Task_resume
|
||||
{
|
||||
GENODE_RPC(Rpc_resume, void, resume);
|
||||
GENODE_RPC_INTERFACE(Rpc_resume);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Libc task
|
||||
*
|
||||
* The libc task represents the "kernel" of the libc-based application.
|
||||
* Blocking and deblocking happens here on libc functions like read() or
|
||||
* select(). This combines blocking of the VFS backend and other signal sources
|
||||
* (e.g., timers). The libc task runs on the component thread and allocates a
|
||||
* secondary stack for the application task. Context switching uses
|
||||
* setjmp/longjmp.
|
||||
*/
|
||||
class Libc::Task : public Genode::Rpc_object<Task_resume, Libc::Task>
|
||||
{
|
||||
private:
|
||||
|
||||
Genode::Environment &_env;
|
||||
|
||||
/**
|
||||
* Application context and execution state
|
||||
*/
|
||||
bool _app_runnable = true;
|
||||
jmp_buf _app_task;
|
||||
|
||||
void *_app_stack = {
|
||||
Genode::Thread_base::myself()->alloc_secondary_stack(Component::name(),
|
||||
Component::stack_size()) };
|
||||
|
||||
/**
|
||||
* Libc context
|
||||
*/
|
||||
jmp_buf _libc_task;
|
||||
|
||||
/**
|
||||
* Trampoline to application code
|
||||
*/
|
||||
static void _app_entry(Task *);
|
||||
|
||||
/* executed in the context of the main thread */
|
||||
static void _resumed_callback();
|
||||
|
||||
public:
|
||||
|
||||
Task(Genode::Environment &env) : _env(env) { }
|
||||
|
||||
~Task() { PERR("%s should not be executed!", __PRETTY_FUNCTION__); }
|
||||
|
||||
void run()
|
||||
{
|
||||
/* save continuation of libc task (incl. current stack) */
|
||||
if (!_setjmp(_libc_task)) {
|
||||
/* _setjmp() returned directly -> switch to app stack and launch component */
|
||||
call_func(_app_stack, (void *)_app_entry, (void *)this);
|
||||
|
||||
/* never reached */
|
||||
}
|
||||
|
||||
/* _setjmp() returned after _longjmp() -> we're done */
|
||||
}
|
||||
|
||||
/**
|
||||
* Called in the context of the entrypoint via RPC
|
||||
*/
|
||||
void resume()
|
||||
{
|
||||
if (!_setjmp(_libc_task))
|
||||
_longjmp(_app_task, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the app context (by fork)
|
||||
*/
|
||||
void schedule_suspend(void(*suspended_callback) ())
|
||||
{
|
||||
if (_setjmp(_app_task))
|
||||
return;
|
||||
|
||||
_env.ep().schedule_suspend(suspended_callback, _resumed_callback);
|
||||
|
||||
/* switch to libc task, which will return to entrypoint */
|
||||
_longjmp(_libc_task, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called from the context of the initial thread
|
||||
*/
|
||||
void resumed()
|
||||
{
|
||||
Genode::Capability<Task_resume> cap = _env.ep().manage(*this);
|
||||
cap.call<Task_resume::Rpc_resume>();
|
||||
_env.ep().dissolve(*this);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/******************************
|
||||
** Libc task implementation **
|
||||
******************************/
|
||||
|
||||
void Libc::Task::_app_entry(Task *task)
|
||||
{
|
||||
original_call_component_construct(task->_env);
|
||||
|
||||
/* returned from task - switch stack to libc and return to dispatch loop */
|
||||
_longjmp(task->_libc_task, 1);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Libc task singleton
|
||||
*
|
||||
* The singleton is implemented with the unmanaged-singleton utility to ensure
|
||||
* it is never destructed like normal static global objects. Otherwise, the
|
||||
* task object may be destructed in a RPC to Rpc_resume, which would result in
|
||||
* a deadlock.
|
||||
*/
|
||||
static Libc::Task *task;
|
||||
|
||||
|
||||
void Libc::Task::_resumed_callback() { task->resumed(); }
|
||||
|
||||
|
||||
namespace Libc {
|
||||
|
||||
void schedule_suspend(void (*suspended) ())
|
||||
{
|
||||
task->schedule_suspend(suspended);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/****************************
|
||||
** Component-startup hook **
|
||||
****************************/
|
||||
|
||||
/* XXX needs base-internal header? */
|
||||
namespace Genode { extern void (*call_component_construct)(Genode::Environment &); }
|
||||
|
||||
void Libc::call_component_construct(Genode::Environment &env)
|
||||
{
|
||||
task = unmanaged_singleton<Libc::Task>(env);
|
||||
task->run();
|
||||
}
|
||||
|
||||
|
||||
static void __attribute__((constructor)) libc_task_constructor(void)
|
||||
{
|
||||
/* hook into component startup */
|
||||
Libc::original_call_component_construct = Genode::call_component_construct;
|
||||
Genode::call_component_construct = &Libc::call_component_construct;
|
||||
}
|
@ -35,6 +35,6 @@ int main(int argc, char **argv)
|
||||
addr = malloc(1234);
|
||||
printf("Malloc returned addr = %p\n", addr);
|
||||
|
||||
printf("--- returning from main ---\n");
|
||||
return 0;
|
||||
printf("--- exit(0) from main ---\n");
|
||||
exit(0);
|
||||
}
|
||||
|
@ -14,15 +14,12 @@
|
||||
#ifndef _INCLUDE__OS__SERVER_H_
|
||||
#define _INCLUDE__OS__SERVER_H_
|
||||
|
||||
#include <base/entrypoint.h>
|
||||
#include <os/signal_rpc_dispatcher.h>
|
||||
#include <util/noncopyable.h>
|
||||
|
||||
|
||||
namespace Server {
|
||||
|
||||
using namespace Genode;
|
||||
class Entrypoint;
|
||||
|
||||
|
||||
void wait_and_dispatch_one_signal();
|
||||
|
||||
@ -38,50 +35,4 @@ namespace Server {
|
||||
void construct(Entrypoint &);
|
||||
}
|
||||
|
||||
|
||||
class Server::Entrypoint : Genode::Noncopyable
|
||||
{
|
||||
private:
|
||||
|
||||
Rpc_entrypoint &_rpc_ep;
|
||||
|
||||
public:
|
||||
|
||||
Entrypoint();
|
||||
|
||||
/**
|
||||
* Associate RPC object with the entry point
|
||||
*/
|
||||
template <typename RPC_INTERFACE, typename RPC_SERVER>
|
||||
Capability<RPC_INTERFACE>
|
||||
manage(Rpc_object<RPC_INTERFACE, RPC_SERVER> &obj)
|
||||
{
|
||||
return _rpc_ep.manage(&obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dissolve RPC object from entry point
|
||||
*/
|
||||
template <typename RPC_INTERFACE, typename RPC_SERVER>
|
||||
void dissolve(Rpc_object<RPC_INTERFACE, RPC_SERVER> &obj)
|
||||
{
|
||||
_rpc_ep.dissolve(&obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Associate signal dispatcher with entry point
|
||||
*/
|
||||
Signal_context_capability manage(Signal_dispatcher_base &);
|
||||
|
||||
/**
|
||||
* Disassociate signal dispatcher from entry point
|
||||
*/
|
||||
void dissolve(Signal_dispatcher_base &);
|
||||
|
||||
/**
|
||||
* Return RPC entrypoint
|
||||
*/
|
||||
Rpc_entrypoint &rpc_ep() { return _rpc_ep; }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__OS__SERVER_H_ */
|
||||
|
@ -1,7 +1,11 @@
|
||||
/*
|
||||
* \brief Utility for dispatching signals via an RPC entrypoint **
|
||||
* \brief Utility for dispatching signals at at RPC entrypoint
|
||||
* \author Norman Feske
|
||||
* \date 2013-09-07
|
||||
*
|
||||
* \deprecated This header merely exists to maintain API compatibility
|
||||
* to Genode 15.11. Its functionality moved to base/signal.h.
|
||||
* The header will eventually be removed.
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -14,55 +18,16 @@
|
||||
#ifndef _INCLUDE__OS__SIGNAL_RPC_DISPATCHER_H_
|
||||
#define _INCLUDE__OS__SIGNAL_RPC_DISPATCHER_H_
|
||||
|
||||
#include <base/rpc_server.h>
|
||||
#include <base/signal.h>
|
||||
|
||||
namespace Genode {
|
||||
template <typename, typename> class Signal_rpc_member;
|
||||
|
||||
template <typename T, typename EP = Entrypoint>
|
||||
struct Signal_rpc_member : Signal_handler<T, EP>
|
||||
{
|
||||
using Signal_handler<T, EP>::Signal_handler;
|
||||
};
|
||||
}
|
||||
|
||||
namespace Server{
|
||||
class Entrypoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal dispatcher for directing signals via RPC to object methods
|
||||
*
|
||||
* This utility associates object methods with signals. It is intended to
|
||||
* be used as a member variable of the class that handles incoming signals
|
||||
* of a certain type. The constructor takes a pointer-to-member to the
|
||||
* signal-handling method as argument. If a signal is received at the
|
||||
* common signal reception code, this method will be invoked by calling
|
||||
* 'Signal_dispatcher_base::dispatch'.
|
||||
*
|
||||
* \param T type of signal-handling class
|
||||
* \param EP type of entrypoint handling signal RPC
|
||||
*/
|
||||
template <typename T, typename EP = Server::Entrypoint>
|
||||
struct Genode::Signal_rpc_member : Genode::Signal_dispatcher_base,
|
||||
Genode::Signal_context_capability
|
||||
{
|
||||
EP &ep;
|
||||
T &obj;
|
||||
void (T::*member) (unsigned);
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* \param ep entrypoint managing this signal RPC
|
||||
* \param obj,member object and method to call when
|
||||
* the signal occurs
|
||||
*/
|
||||
Signal_rpc_member(EP &ep, T &obj, void (T::*member)(unsigned))
|
||||
: Signal_context_capability(ep.manage(*this)),
|
||||
ep(ep), obj(obj), member(member) { }
|
||||
|
||||
~Signal_rpc_member() { ep.dissolve(*this); }
|
||||
|
||||
/**
|
||||
* Interface of Signal_dispatcher_base
|
||||
*/
|
||||
void dispatch(unsigned num) { (obj.*member)(num); }
|
||||
};
|
||||
|
||||
#endif /* _INCLUDE__OS__SIGNAL_RPC_DISPATCHER_H_ */
|
||||
|
@ -6,19 +6,18 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2015 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.
|
||||
*/
|
||||
|
||||
/* Linux */
|
||||
/* Linux includes */
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
/* Genode */
|
||||
/* Genode includes */
|
||||
#include <util/misc_math.h>
|
||||
#include <base/env.h>
|
||||
#include <base/sleep.h>
|
||||
#include <base/component.h>
|
||||
#include <base/rpc_server.h>
|
||||
#include <framebuffer_session/framebuffer_session.h>
|
||||
#include <cap_session/connection.h>
|
||||
@ -27,45 +26,23 @@
|
||||
#include <timer_session/connection.h>
|
||||
|
||||
/* local includes */
|
||||
#include <input.h>
|
||||
#include "input.h"
|
||||
|
||||
|
||||
/**
|
||||
* Read integer value from config attribute
|
||||
*/
|
||||
void config_arg(const char *attr, long *value)
|
||||
{
|
||||
try { Genode::config()->xml_node().attribute(attr).value(value); }
|
||||
catch (...) { }
|
||||
}
|
||||
using Genode::Attached_ram_dataspace;
|
||||
|
||||
|
||||
/*
|
||||
* Variables for the libSDL output window
|
||||
*/
|
||||
static SDL_Surface *screen;
|
||||
static long scr_width = 1024, scr_height = 768;
|
||||
static Framebuffer::Mode::Format scr_format = Framebuffer::Mode::RGB565;
|
||||
|
||||
/*
|
||||
* Dataspace capability and local address of virtual frame buffer
|
||||
* that is shared with the client.
|
||||
*/
|
||||
static Genode::Dataspace_capability fb_ds_cap;
|
||||
static void *fb_ds_addr;
|
||||
|
||||
|
||||
/***********************************************
|
||||
** Implementation of the framebuffer service **
|
||||
***********************************************/
|
||||
|
||||
namespace Framebuffer { class Session_component; }
|
||||
|
||||
class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
||||
{
|
||||
private:
|
||||
|
||||
Mode _mode;
|
||||
SDL_Surface *_screen { nullptr };
|
||||
|
||||
Mode _mode;
|
||||
Genode::Dataspace_capability _fb_ds_cap;
|
||||
void *_fb_ds_addr;
|
||||
|
||||
Timer::Connection _timer;
|
||||
|
||||
@ -74,9 +51,15 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
Session_component() : _mode(scr_width, scr_height, Mode::RGB565) { }
|
||||
Session_component(Framebuffer::Mode mode,
|
||||
Genode::Dataspace_capability fb_ds_cap, void *fb_ds_addr)
|
||||
:
|
||||
_mode(mode), _fb_ds_cap(fb_ds_cap), _fb_ds_addr(fb_ds_addr)
|
||||
{ }
|
||||
|
||||
Genode::Dataspace_capability dataspace() override { return fb_ds_cap; }
|
||||
void screen(SDL_Surface *screen) { _screen = screen; }
|
||||
|
||||
Genode::Dataspace_capability dataspace() override { return _fb_ds_cap; }
|
||||
|
||||
Mode mode() const override { return _mode; }
|
||||
|
||||
@ -93,105 +76,144 @@ class Framebuffer::Session_component : public Genode::Rpc_object<Session>
|
||||
/* clip refresh area to screen boundaries */
|
||||
int x1 = Genode::max(x, 0);
|
||||
int y1 = Genode::max(y, 0);
|
||||
int x2 = Genode::min(x + w - 1, scr_width - 1);
|
||||
int y2 = Genode::min(y + h - 1, scr_height - 1);
|
||||
int x2 = Genode::min(x + w - 1, _mode.width() - 1);
|
||||
int y2 = Genode::min(y + h - 1, _mode.height() - 1);
|
||||
|
||||
if (x1 <= x2 && y1 <= y2) {
|
||||
|
||||
/* copy pixels from shared dataspace to sdl surface */
|
||||
const int start_offset = _mode.bytes_per_pixel()*(y1*scr_width + x1);
|
||||
const int start_offset = _mode.bytes_per_pixel()*(y1*_mode.width() + x1);
|
||||
const int line_len = _mode.bytes_per_pixel()*(x2 - x1 + 1);
|
||||
const int pitch = _mode.bytes_per_pixel()*scr_width;
|
||||
const int pitch = _mode.bytes_per_pixel()*_mode.width();
|
||||
|
||||
char *src = (char *)fb_ds_addr + start_offset;
|
||||
char *dst = (char *)screen->pixels + start_offset;
|
||||
char *src = (char *)_fb_ds_addr + start_offset;
|
||||
char *dst = (char *)_screen->pixels + start_offset;
|
||||
|
||||
for (int i = y1; i <= y2; i++, src += pitch, dst += pitch)
|
||||
Genode::memcpy(dst, src, line_len);
|
||||
|
||||
/* flush pixels in sdl window */
|
||||
SDL_UpdateRect(screen, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
|
||||
SDL_UpdateRect(_screen, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Main program
|
||||
*/
|
||||
int main()
|
||||
{
|
||||
using namespace Genode;
|
||||
using namespace Framebuffer;
|
||||
namespace Input {
|
||||
|
||||
config_arg("width", &scr_width);
|
||||
config_arg("height", &scr_height);
|
||||
|
||||
/*
|
||||
* Initialize libSDL window
|
||||
*/
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
||||
struct Handler_rpc : Handler
|
||||
{
|
||||
PERR("SDL_Init failed (%s)", SDL_GetError());
|
||||
return -1;
|
||||
}
|
||||
GENODE_RPC(Rpc_event, void, event, Input::Event);
|
||||
GENODE_RPC_INTERFACE(Rpc_event);
|
||||
};
|
||||
|
||||
/*
|
||||
* We're testing only X11.
|
||||
*/
|
||||
static char driver[16] = { 0 };
|
||||
SDL_VideoDriverName(driver, sizeof(driver));
|
||||
if (::strcmp(driver, "x11") != 0) {
|
||||
PERR("fb_sdl works on X11 only. Your SDL backend is \"%s\".", driver);
|
||||
return -2;
|
||||
}
|
||||
struct Handler_client : Handler
|
||||
{
|
||||
Genode::Capability<Handler_rpc> cap;
|
||||
|
||||
Genode::size_t bpp = Framebuffer::Mode::bytes_per_pixel(scr_format);
|
||||
screen = SDL_SetVideoMode(scr_width, scr_height, bpp*8, SDL_SWSURFACE);
|
||||
if (!screen) {
|
||||
PERR("SDL_SetVideoMode failed (%s)", SDL_GetError());
|
||||
return -3;
|
||||
}
|
||||
Handler_client(Genode::Capability<Handler_rpc> cap) : cap(cap) { }
|
||||
|
||||
SDL_ShowCursor(0);
|
||||
void event(Input::Event ev) override
|
||||
{
|
||||
cap.call<Handler_rpc::Rpc_event>(ev);
|
||||
}
|
||||
};
|
||||
|
||||
Genode::printf("creating virtual framebuffer for mode %ldx%ld@%zd\n",
|
||||
scr_width, scr_height, bpp*8);
|
||||
struct Handler_component : Genode::Rpc_object<Handler_rpc, Handler_component>
|
||||
{
|
||||
Session_component &session;
|
||||
|
||||
/*
|
||||
* Create dataspace representing the virtual frame buffer
|
||||
*/
|
||||
try {
|
||||
static Attached_ram_dataspace fb_ds(env()->ram_session(), scr_width*scr_height*bpp);
|
||||
fb_ds_cap = fb_ds.cap();
|
||||
fb_ds_addr = fb_ds.local_addr<void>();
|
||||
} catch (...) {
|
||||
PERR("Could not allocate dataspace for virtual frame buffer");
|
||||
return -4;
|
||||
}
|
||||
Handler_component(Session_component &session) : session(session) { }
|
||||
|
||||
/*
|
||||
* Initialize server entry point
|
||||
*/
|
||||
enum { STACK_SIZE = 16*1024 };
|
||||
static Cap_connection cap;
|
||||
static Rpc_entrypoint ep(&cap, STACK_SIZE, "fb_ep");
|
||||
|
||||
static Input::Session_component input_session;
|
||||
static Input::Root_component input_root(ep, input_session);
|
||||
|
||||
static Framebuffer::Session_component fb_session;
|
||||
static Static_root<Framebuffer::Session> fb_root(ep.manage(&fb_session));
|
||||
|
||||
/*
|
||||
* Now, the root interfaces are ready to accept requests.
|
||||
* This is the right time to tell mummy about our services.
|
||||
*/
|
||||
env()->parent()->announce(ep.manage(&fb_root));
|
||||
env()->parent()->announce(ep.manage(&input_root));
|
||||
|
||||
for (;;)
|
||||
input_session.submit(wait_for_event());
|
||||
|
||||
return 0;
|
||||
void event(Input::Event e) override { session.submit(e); }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read integer value from config attribute
|
||||
*/
|
||||
template<typename T>
|
||||
static T config_arg(char const *attr, T const &default_value)
|
||||
{
|
||||
long value = default_value;
|
||||
|
||||
try { Genode::config()->xml_node().attribute(attr).value(&value); }
|
||||
catch (...) { }
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
struct Main
|
||||
{
|
||||
/* fatal exceptions */
|
||||
struct Sdl_init_failed { };
|
||||
struct Sdl_videodriver_not_supported { };
|
||||
struct Sdl_setvideomode_failed { };
|
||||
|
||||
Genode::Environment &env;
|
||||
|
||||
int fb_width { config_arg("width", 1024) };
|
||||
int fb_height { config_arg("height", 768) };
|
||||
|
||||
Framebuffer::Mode fb_mode { fb_width, fb_height, Framebuffer::Mode::RGB565 };
|
||||
|
||||
Attached_ram_dataspace fb_ds { &env.ram(),
|
||||
fb_mode.width()*fb_mode.height()*fb_mode.bytes_per_pixel() };
|
||||
|
||||
Framebuffer::Session_component fb_session { fb_mode, fb_ds.cap(), fb_ds.local_addr<void>() };
|
||||
|
||||
Genode::Static_root<Framebuffer::Session> fb_root { env.ep().manage(fb_session) };
|
||||
|
||||
Input::Session_component input_session;
|
||||
Input::Root_component input_root { env.ep().rpc_ep(), input_session };
|
||||
|
||||
Input::Handler_component input_handler_component { input_session };
|
||||
Input::Handler_client input_handler_client { env.ep().manage(input_handler_component) };
|
||||
|
||||
Main(Genode::Environment &env) : env(env)
|
||||
{
|
||||
/*
|
||||
* Initialize libSDL window
|
||||
*/
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
||||
{
|
||||
PERR("SDL_Init failed (%s)", SDL_GetError());
|
||||
throw Sdl_init_failed();
|
||||
}
|
||||
|
||||
/*
|
||||
* We're testing only X11.
|
||||
*/
|
||||
char driver[16] = { 0 };
|
||||
SDL_VideoDriverName(driver, sizeof(driver));
|
||||
if (::strcmp(driver, "x11") != 0) {
|
||||
PERR("fb_sdl works on X11 only. Your SDL backend is \"%s\".", driver);
|
||||
throw Sdl_videodriver_not_supported();
|
||||
}
|
||||
|
||||
SDL_Surface *screen = SDL_SetVideoMode(fb_mode.width(), fb_mode.height(),
|
||||
fb_mode.bytes_per_pixel()*8, SDL_SWSURFACE);
|
||||
if (!screen) {
|
||||
PERR("SDL_SetVideoMode failed (%s)", SDL_GetError());
|
||||
throw Sdl_setvideomode_failed();
|
||||
}
|
||||
fb_session.screen(screen);
|
||||
|
||||
SDL_ShowCursor(0);
|
||||
|
||||
Genode::printf("creating virtual framebuffer for mode %dx%d@%zd\n",
|
||||
fb_mode.width(), fb_mode.height(), fb_mode.bytes_per_pixel()*8);
|
||||
|
||||
env.parent().announce(env.ep().manage(fb_root));
|
||||
env.parent().announce(env.ep().manage(input_root));
|
||||
|
||||
init_input_backend(input_handler_client);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Genode::size_t Component::stack_size() { return 4*1024*sizeof(long); }
|
||||
char const * Component::name() { return "fb_sdl"; }
|
||||
void Component::construct(Genode::Environment &env) { static Main inst(env); }
|
||||
|
@ -6,21 +6,23 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2006-2015 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.
|
||||
*/
|
||||
|
||||
/* Linux */
|
||||
/* Linux includes */
|
||||
#include <SDL/SDL.h>
|
||||
|
||||
/* Genode */
|
||||
#include <input/keycodes.h>
|
||||
/* Genode includes */
|
||||
#include <base/printf.h>
|
||||
#include <base/thread.h>
|
||||
#include <input/keycodes.h>
|
||||
|
||||
/* local includes */
|
||||
#include "input.h"
|
||||
|
||||
/* local */
|
||||
#include <input.h>
|
||||
|
||||
/**
|
||||
* Convert SDL keycode to Genode keycode
|
||||
@ -210,14 +212,38 @@ static Input::Event wait_for_sdl_event()
|
||||
return Event(type, keycode, mx, my, mx - ox, my - oy);
|
||||
}
|
||||
|
||||
Input::Event wait_for_event()
|
||||
{
|
||||
Input::Event e;
|
||||
|
||||
/* prevent flooding of client with invalid events */
|
||||
do {
|
||||
e = wait_for_sdl_event();
|
||||
} while (e.type() == Input::Event::INVALID);
|
||||
|
||||
return e;
|
||||
namespace Input {
|
||||
enum { STACK_SIZE = 4096*sizeof(long) };
|
||||
struct Backend;
|
||||
}
|
||||
|
||||
struct Input::Backend : Genode::Thread<STACK_SIZE>
|
||||
{
|
||||
Handler &handler;
|
||||
|
||||
Backend(Input::Handler &handler)
|
||||
:
|
||||
Genode::Thread<STACK_SIZE>("input_backend"),
|
||||
handler(handler)
|
||||
{
|
||||
start();
|
||||
}
|
||||
|
||||
void entry()
|
||||
{
|
||||
while (true) {
|
||||
Input::Event e;
|
||||
|
||||
/* prevent flooding of client with invalid events */
|
||||
do {
|
||||
e = wait_for_sdl_event();
|
||||
} while (e.type() == Input::Event::INVALID);
|
||||
|
||||
handler.event(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void init_input_backend(Input::Handler &h) { static Input::Backend inst(h); }
|
||||
|
@ -1,11 +1,12 @@
|
||||
/*
|
||||
* \brief SDL input support
|
||||
* \author Norman Feske
|
||||
* \author Christian Helmuth
|
||||
* \date 2006-08-16
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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.
|
||||
@ -14,11 +15,16 @@
|
||||
#ifndef _DRIVERS__FRAMEBUFFER__SPEC__SDL__INPUT_H_
|
||||
#define _DRIVERS__FRAMEBUFFER__SPEC__SDL__INPUT_H_
|
||||
|
||||
/* Genode include */
|
||||
#include <input/event.h>
|
||||
|
||||
/**
|
||||
* Wait for an event, Zzz...zz..
|
||||
*/
|
||||
Input::Event wait_for_event();
|
||||
namespace Input { struct Handler; }
|
||||
|
||||
struct Input::Handler
|
||||
{
|
||||
virtual void event(Input::Event) = 0;
|
||||
};
|
||||
|
||||
void init_input_backend(Input::Handler &);
|
||||
|
||||
#endif /* _DRIVERS__FRAMEBUFFER__SPEC__SDL__INPUT_H_ */
|
||||
|
@ -11,131 +11,34 @@
|
||||
* under the terms of the GNU General Public License version 2.
|
||||
*/
|
||||
|
||||
#include <base/component.h>
|
||||
#include <os/server.h>
|
||||
#include <cap_session/connection.h>
|
||||
|
||||
using namespace Server;
|
||||
|
||||
|
||||
static Cap_session &global_cap_session()
|
||||
Genode::size_t Component::stack_size()
|
||||
{
|
||||
static Cap_connection inst;
|
||||
return inst;
|
||||
return Server::stack_size();
|
||||
}
|
||||
|
||||
|
||||
static Rpc_entrypoint &global_rpc_ep()
|
||||
char const *Component::name()
|
||||
{
|
||||
static Rpc_entrypoint inst(&global_cap_session(),
|
||||
stack_size(),
|
||||
name());
|
||||
return inst;
|
||||
return Server::name();
|
||||
}
|
||||
|
||||
|
||||
static Entrypoint &global_ep()
|
||||
static Genode::Environment *_env;
|
||||
|
||||
|
||||
void Component::construct(Genode::Environment &env)
|
||||
{
|
||||
static Server::Entrypoint inst;
|
||||
return inst;
|
||||
_env = &env;
|
||||
Server::construct(env.ep());
|
||||
}
|
||||
|
||||
|
||||
static Genode::Signal_receiver &global_sig_rec()
|
||||
{
|
||||
static Genode::Signal_receiver inst;
|
||||
return inst;
|
||||
}
|
||||
|
||||
|
||||
static void dispatch(Signal &sig)
|
||||
{
|
||||
Signal_dispatcher_base *dispatcher = 0;
|
||||
dispatcher = dynamic_cast<Signal_dispatcher_base *>(sig.context());
|
||||
|
||||
if (!dispatcher)
|
||||
return;
|
||||
|
||||
dispatcher->dispatch(sig.num());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Dispatch a signal at entry point
|
||||
*/
|
||||
void Server::wait_and_dispatch_one_signal()
|
||||
{
|
||||
Signal sig = global_sig_rec().wait_for_signal();
|
||||
dispatch(sig);
|
||||
}
|
||||
|
||||
|
||||
Signal_context_capability Entrypoint::manage(Signal_dispatcher_base &dispatcher)
|
||||
{
|
||||
return global_sig_rec().manage(&dispatcher);
|
||||
}
|
||||
|
||||
|
||||
void Server::Entrypoint::dissolve(Signal_dispatcher_base &dispatcher)
|
||||
{
|
||||
global_sig_rec().dissolve(&dispatcher);
|
||||
}
|
||||
|
||||
|
||||
Server::Entrypoint::Entrypoint() : _rpc_ep(global_rpc_ep()) { }
|
||||
|
||||
|
||||
namespace Server {
|
||||
struct Constructor;
|
||||
struct Constructor_component;
|
||||
}
|
||||
|
||||
|
||||
struct Server::Constructor
|
||||
{
|
||||
GENODE_RPC(Rpc_construct, void, construct);
|
||||
GENODE_RPC(Rpc_signal, void, signal);
|
||||
GENODE_RPC_INTERFACE(Rpc_construct, Rpc_signal);
|
||||
};
|
||||
|
||||
|
||||
struct Server::Constructor_component : Rpc_object<Server::Constructor,
|
||||
Server::Constructor_component>
|
||||
{
|
||||
void construct() { Server::construct(global_ep()); }
|
||||
|
||||
void signal()
|
||||
{
|
||||
try {
|
||||
Signal sig = global_sig_rec().pending_signal();
|
||||
::dispatch(sig);
|
||||
} catch (Signal_receiver::Signal_not_pending) { }
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static Server::Constructor_component constructor;
|
||||
|
||||
static Server::Entrypoint ep;
|
||||
|
||||
/* call Server::construct in the context of the entrypoint */
|
||||
Capability<Server::Constructor> constructor_cap = ep.manage(constructor);
|
||||
|
||||
constructor_cap.call<Server::Constructor::Rpc_construct>();
|
||||
|
||||
/* process incoming signals */
|
||||
for (;;) {
|
||||
|
||||
global_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.
|
||||
*/
|
||||
try {
|
||||
constructor_cap.call<Server::Constructor::Rpc_signal>();
|
||||
} catch(Genode::Ipc_error) { }
|
||||
}
|
||||
if (_env)
|
||||
_env->ep().wait_and_dispatch_one_signal();
|
||||
}
|
||||
|
@ -543,7 +543,16 @@ extern "C" void fork_trampoline()
|
||||
}
|
||||
|
||||
|
||||
extern "C" pid_t fork(void)
|
||||
static pid_t fork_result;
|
||||
|
||||
|
||||
/**
|
||||
* Called once the component has left the entrypoint and exited the signal
|
||||
* dispatch loop.
|
||||
*
|
||||
* This function is called from the context of the initial thread.
|
||||
*/
|
||||
static void suspended_callback()
|
||||
{
|
||||
/* stack used for executing 'fork_trampoline' */
|
||||
enum { STACK_SIZE = 8 * 1024 };
|
||||
@ -554,7 +563,7 @@ extern "C" pid_t fork(void)
|
||||
/*
|
||||
* We got here via longjmp from 'fork_trampoline'.
|
||||
*/
|
||||
return 0;
|
||||
fork_result = 0;
|
||||
|
||||
} else {
|
||||
|
||||
@ -573,17 +582,29 @@ extern "C" pid_t fork(void)
|
||||
if (!noux_syscall(Noux::Session::SYSCALL_FORK)) {
|
||||
PERR("fork error %d", sysio()->error.general);
|
||||
switch (sysio()->error.fork) {
|
||||
case Noux::Sysio::FORK_NOMEM: errno = ENOMEM; break;
|
||||
case Noux::Sysio::FORK_NOMEM: errno = ENOMEM; break;
|
||||
default: errno = EAGAIN;
|
||||
}
|
||||
return -1;
|
||||
fork_result = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
return sysio()->fork_out.pid;
|
||||
fork_result = sysio()->fork_out.pid;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace Libc { void schedule_suspend(void (*suspended) ()); }
|
||||
|
||||
|
||||
extern "C" pid_t fork(void)
|
||||
{
|
||||
Libc::schedule_suspend(suspended_callback);
|
||||
|
||||
return fork_result;
|
||||
}
|
||||
|
||||
|
||||
extern "C" pid_t vfork(void) { return fork(); }
|
||||
|
||||
|
||||
|
@ -74,18 +74,13 @@ namespace Noux {
|
||||
Thread_capability create_thread(size_t weight, Name const &name,
|
||||
addr_t utcb)
|
||||
{
|
||||
/*
|
||||
* Prevent any attempt to create more than the main
|
||||
* thread.
|
||||
*/
|
||||
if (_main_thread.valid()) {
|
||||
PWRN("Invalid attempt to create a thread besides main");
|
||||
while (1);
|
||||
return Thread_capability();
|
||||
if (!_main_thread.valid()) {
|
||||
_main_thread = _cpu.create_thread(weight, name, utcb);
|
||||
return _main_thread;
|
||||
}
|
||||
_main_thread = _cpu.create_thread(weight, name, utcb);
|
||||
|
||||
return _main_thread;
|
||||
/* create non-main thread */
|
||||
return _cpu.create_thread(weight, name, utcb);
|
||||
}
|
||||
|
||||
Ram_dataspace_capability utcb(Thread_capability thread) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user