From 051e84c4b47f89b0d321147ec01cd0cee4e0961c Mon Sep 17 00:00:00 2001 From: Norman Feske Date: Wed, 23 Dec 2015 15:22:33 +0100 Subject: [PATCH] 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 --- repos/base-fiasco/lib/mk/base-common.mk | 2 + repos/base-foc/include/signal_source/client.h | 7 + repos/base-foc/lib/mk/base-common.inc | 2 + repos/base-hw/lib/mk/base-common.inc | 2 + repos/base-hw/lib/mk/core.inc | 1 + repos/base-hw/src/base/env.cc | 1 + repos/base-hw/src/base/signal/signal.cc | 13 + repos/base-hw/src/base/thread/start.cc | 8 +- .../base-linux/lib/import/import-lx_hybrid.mk | 25 +- repos/base-linux/lib/mk/base-common.mk | 2 + repos/base-linux/src/base/env/platform_env.cc | 15 +- repos/base-linux/src/core/include/core_env.h | 16 +- repos/base-linux/src/core/stack_area.cc | 16 +- .../src/include/base/internal/platform_env.h | 22 +- .../base-linux/src/lib/lx_hybrid/lx_hybrid.cc | 48 +++- .../src/test/lx_hybrid_ctors/main.cc | 24 +- .../src/test/lx_hybrid_errno/main.cc | 22 +- .../src/test/lx_hybrid_exception/main.cc | 26 +- .../src/test/lx_hybrid_pthread_ipc/main.cc | 19 +- .../base-nova/include/signal_source/client.h | 32 +-- repos/base-nova/lib/mk/base-common.mk | 2 + repos/base-nova/src/base/server/server.cc | 2 + .../core/include/signal_source_component.h | 3 - repos/base-okl4/lib/mk/base-common.mk | 2 + repos/base-pistachio/lib/mk/base-common.mk | 2 + repos/base-sel4/lib/mk/base-common.inc | 2 + repos/base-sel4/src/core/stack_area.cc | 19 +- repos/base/include/base/component.h | 78 ++++++ repos/base/include/base/entrypoint.h | 165 ++++++++++++ repos/base/include/base/env.h | 3 +- repos/base/include/base/signal.h | 42 +++ repos/base/include/util/volatile_object.h | 5 +- repos/base/lib/import/import-ld.mk | 6 + repos/base/lib/mk/component_entry_point.mk | 7 + repos/base/lib/mk/ldso.inc | 2 + repos/base/lib/mk/startup.inc | 2 +- repos/base/mk/prg.mk | 7 + repos/base/src/base/component/component.cc | 76 ++++++ repos/base/src/base/entrypoint/entrypoint.cc | 191 ++++++++++++++ repos/base/src/base/env/reinitialize.cc | 9 +- repos/base/src/base/env/stack_area.cc | 48 +--- repos/base/src/base/server/common.cc | 3 + repos/base/src/base/signal/signal.cc | 69 +++-- repos/base/src/base/thread/thread.cc | 16 +- repos/base/src/core/include/core_env.h | 18 +- repos/base/src/core/main.cc | 17 ++ repos/base/src/core/stack_area.cc | 31 +-- .../src/include/base/internal/platform_env.h | 19 +- .../base/internal/platform_env_common.h | 37 +++ repos/base/src/ld/genode_dyn.ld | 20 +- repos/base/src/lib/ldso/main.cc | 33 ++- repos/base/src/lib/startup/_main.cc | 63 +++-- .../src/lib/startup/component_construct.cc | 98 +++++++ .../src/lib/startup/component_entry_point.cc | 32 +++ .../base/src/lib/startup/init_main_thread.cc | 8 +- repos/libports/lib/mk/libc.mk | 6 +- repos/libports/lib/mk/spec/arm/libc.mk | 3 + repos/libports/lib/mk/spec/x86_32/libc.mk | 3 + repos/libports/lib/mk/spec/x86_64/libc.mk | 3 + repos/libports/run/ldso.run | 6 +- repos/libports/run/libc.run | 2 +- .../include/spec/arm/internal/call_func.h | 34 +++ .../include/spec/x86_32/internal/call_func.h | 34 +++ .../include/spec/x86_64/internal/call_func.h | 38 +++ repos/libports/src/lib/libc/task.cc | 198 ++++++++++++++ repos/libports/src/test/libc/main.cc | 4 +- repos/os/include/os/server.h | 51 +--- repos/os/include/os/signal_rpc_dispatcher.h | 57 +--- .../drivers/framebuffer/spec/sdl/fb_sdl.cc | 248 ++++++++++-------- .../src/drivers/framebuffer/spec/sdl/input.cc | 56 ++-- .../src/drivers/framebuffer/spec/sdl/input.h | 16 +- repos/os/src/lib/server/server.cc | 123 +-------- repos/ports/src/lib/libc_noux/plugin.cc | 31 ++- repos/ports/src/noux/cpu_session_component.h | 15 +- 74 files changed, 1730 insertions(+), 638 deletions(-) create mode 100644 repos/base/include/base/component.h create mode 100644 repos/base/include/base/entrypoint.h create mode 100644 repos/base/lib/import/import-ld.mk create mode 100644 repos/base/lib/mk/component_entry_point.mk create mode 100644 repos/base/src/base/component/component.cc create mode 100644 repos/base/src/base/entrypoint/entrypoint.cc create mode 100644 repos/base/src/lib/startup/component_construct.cc create mode 100644 repos/base/src/lib/startup/component_entry_point.cc create mode 100644 repos/libports/lib/mk/spec/arm/libc.mk create mode 100644 repos/libports/lib/mk/spec/x86_32/libc.mk create mode 100644 repos/libports/lib/mk/spec/x86_64/libc.mk create mode 100644 repos/libports/src/lib/libc/include/spec/arm/internal/call_func.h create mode 100644 repos/libports/src/lib/libc/include/spec/x86_32/internal/call_func.h create mode 100644 repos/libports/src/lib/libc/include/spec/x86_64/internal/call_func.h create mode 100644 repos/libports/src/lib/libc/task.cc diff --git a/repos/base-fiasco/lib/mk/base-common.mk b/repos/base-fiasco/lib/mk/base-common.mk index 99d12a164..bb85cbe9c 100644 --- a/repos/base-fiasco/lib/mk/base-common.mk +++ b/repos/base-fiasco/lib/mk/base-common.mk @@ -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 diff --git a/repos/base-foc/include/signal_source/client.h b/repos/base-foc/include/signal_source/client.h index 16be3fdef..aa8b42cbd 100644 --- a/repos/base-foc/include/signal_source/client.h +++ b/repos/base-foc/include/signal_source/client.h @@ -70,6 +70,13 @@ namespace Genode { : Rpc_client(static_cap_cast(cap)) { _init_sem(); } + /** + * Destructor + */ + ~Signal_source_client() + { + Fiasco::l4_irq_detach(_sem.dst()); + } /***************************** ** Signal source interface ** diff --git a/repos/base-foc/lib/mk/base-common.inc b/repos/base-foc/lib/mk/base-common.inc index 4c912c959..5c2ecd633 100644 --- a/repos/base-foc/lib/mk/base-common.inc +++ b/repos/base-foc/lib/mk/base-common.inc @@ -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 diff --git a/repos/base-hw/lib/mk/base-common.inc b/repos/base-hw/lib/mk/base-common.inc index 49842603f..570bd1c73 100644 --- a/repos/base-hw/lib/mk/base-common.inc +++ b/repos/base-hw/lib/mk/base-common.inc @@ -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 diff --git a/repos/base-hw/lib/mk/core.inc b/repos/base-hw/lib/mk/core.inc index ebe3c8733..9912106da 100644 --- a/repos/base-hw/lib/mk/core.inc +++ b/repos/base-hw/lib/mk/core.inc @@ -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 diff --git a/repos/base-hw/src/base/env.cc b/repos/base-hw/src/base/env.cc index 31d976a1e..656e1938c 100644 --- a/repos/base-hw/src/base/env.cc +++ b/repos/base-hw/src/base/env.cc @@ -16,6 +16,7 @@ #include #include + void Genode::upgrade_pd_session_quota(Genode::size_t quota) { char buf[128]; diff --git a/repos/base-hw/src/base/signal/signal.cc b/repos/base-hw/src/base/signal/signal.cc index 6b300c4d2..4767eccfb 100644 --- a/repos/base-hw/src/base/signal/signal.cc +++ b/repos/base-hw/src/base/signal/signal.cc @@ -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 ** ************************/ diff --git a/repos/base-hw/src/base/thread/start.cc b/repos/base-hw/src/base/thread/start.cc index 58019cec7..3341b42dc 100644 --- a/repos/base-hw/src/base/thread/start.cc +++ b/repos/base-hw/src/base/thread/start.cc @@ -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(); diff --git a/repos/base-linux/lib/import/import-lx_hybrid.mk b/repos/base-linux/lib/import/import-lx_hybrid.mk index fd8fbc316..860ba8e3f 100644 --- a/repos/base-linux/lib/import/import-lx_hybrid.mk +++ b/repos/base-linux/lib/import/import-lx_hybrid.mk @@ -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++ diff --git a/repos/base-linux/lib/mk/base-common.mk b/repos/base-linux/lib/mk/base-common.mk index 6dbec89bc..18575c461 100644 --- a/repos/base-linux/lib/mk/base-common.mk +++ b/repos/base-linux/lib/mk/base-common.mk @@ -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 diff --git a/repos/base-linux/src/base/env/platform_env.cc b/repos/base-linux/src/base/env/platform_env.cc index b33c673c6..1eef3716e 100644 --- a/repos/base-linux/src/base/env/platform_env.cc +++ b/repos/base-linux/src/base/env/platform_env.cc @@ -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::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(_parent().session("Env::cpu_session", "")), static_cap_cast (_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()); diff --git a/repos/base-linux/src/core/include/core_env.h b/repos/base-linux/src/core/include/core_env.h index 9aad5d5b7..711366f34 100644 --- a/repos/base-linux/src/core/include/core_env.h +++ b/repos/base-linux/src/core/include/core_env.h @@ -28,6 +28,8 @@ /* base-internal includes */ #include +namespace Genode { void init_stack_area(); } + namespace Genode { /** @@ -136,7 +138,15 @@ namespace Genode { typedef Synchronized_ram_session 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(); diff --git a/repos/base-linux/src/core/stack_area.cc b/repos/base-linux/src/core/stack_area.cc index fa57477c4..95f47c1af 100644 --- a/repos/base-linux/src/core/stack_area.cc +++ b/repos/base-linux/src/core/stack_area.cc @@ -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; } } diff --git a/repos/base-linux/src/include/base/internal/platform_env.h b/repos/base-linux/src/include/base/internal/platform_env.h index b398950ed..bc3abb2cf 100644 --- a/repos/base-linux/src/include/base/internal/platform_env.h +++ b/repos/base-linux/src/include/base/internal/platform_env.h @@ -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 * diff --git a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc index 95f72e7b5..e71ef9011 100644 --- a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc +++ b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc @@ -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 +#include #include #include @@ -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 */ +} /************ diff --git a/repos/base-linux/src/test/lx_hybrid_ctors/main.cc b/repos/base-linux/src/test/lx_hybrid_ctors/main.cc index 17cb56da4..e91b30251 100644 --- a/repos/base-linux/src/test/lx_hybrid_ctors/main.cc +++ b/repos/base-linux/src/test/lx_hybrid_ctors/main.cc @@ -11,11 +11,16 @@ * under the terms of the GNU General Public License version 2. */ - +/* Genode includes */ +#include #include +/* local includes */ #include "testlib.h" +/* Linux includes */ +#include + 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); } diff --git a/repos/base-linux/src/test/lx_hybrid_errno/main.cc b/repos/base-linux/src/test/lx_hybrid_errno/main.cc index a60371f03..cf9549949 100644 --- a/repos/base-linux/src/test/lx_hybrid_errno/main.cc +++ b/repos/base-linux/src/test/lx_hybrid_errno/main.cc @@ -5,6 +5,7 @@ */ /* Genode includes */ +#include #include #include @@ -12,6 +13,7 @@ #include #include #include +#include enum { STACK_SIZE = 4096 }; @@ -40,7 +42,20 @@ struct Thread : Genode::Thread }; -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); } diff --git a/repos/base-linux/src/test/lx_hybrid_exception/main.cc b/repos/base-linux/src/test/lx_hybrid_exception/main.cc index 50639cd46..aada945a8 100644 --- a/repos/base-linux/src/test/lx_hybrid_exception/main.cc +++ b/repos/base-linux/src/test/lx_hybrid_exception/main.cc @@ -11,27 +11,41 @@ * under the terms of the GNU General Public License version 2. */ +/* Genode includes */ +#include #include +/* Linux includes */ +#include + 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); } diff --git a/repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc b/repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc index 6c55a33af..3aa3f487d 100644 --- a/repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc +++ b/repos/base-linux/src/test/lx_hybrid_pthread_ipc/main.cc @@ -12,11 +12,14 @@ */ /* Genode includes */ +#include #include #include /* libc includes */ #include +#include + 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); } diff --git a/repos/base-nova/include/signal_source/client.h b/repos/base-nova/include/signal_source/client.h index 484f550cd..c96132a4a 100644 --- a/repos/base-nova/include/signal_source/client.h +++ b/repos/base-nova/include/signal_source/client.h @@ -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(_sem); - } - public: /** @@ -67,11 +51,17 @@ namespace Genode { Signal_source_client(Capability cap) : Rpc_client(static_cap_cast(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(_sem); + } + + ~Signal_source_client() + { + Nova::revoke(Nova::Obj_crd(_sem.local_name(), 0)); } diff --git a/repos/base-nova/lib/mk/base-common.mk b/repos/base-nova/lib/mk/base-common.mk index 776b79bb9..48b53b96e 100644 --- a/repos/base-nova/lib/mk/base-common.mk +++ b/repos/base-nova/lib/mk/base-common.mk @@ -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 diff --git a/repos/base-nova/src/base/server/server.cc b/repos/base-nova/src/base/server/server.cc index 550c860a7..d52537ed7 100644 --- a/repos/base-nova/src/base/server/server.cc +++ b/repos/base-nova/src/base/server/server.cc @@ -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. diff --git a/repos/base-nova/src/core/include/signal_source_component.h b/repos/base-nova/src/core/include/signal_source_component.h index d284ca658..cebb97ecb 100644 --- a/repos/base-nova/src/core/include/signal_source_component.h +++ b/repos/base-nova/src/core/include/signal_source_component.h @@ -47,9 +47,6 @@ class Genode::Signal_source_component : public Rpc_object +#include +#include +#include +#include +#include +#include + + +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_ */ diff --git a/repos/base/include/base/entrypoint.h b/repos/base/include/base/entrypoint.h new file mode 100644 index 000000000..b270edac3 --- /dev/null +++ b/repos/base/include/base/entrypoint.h @@ -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 +#include +#include +#include +#include + + +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 + { + 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 + { + Entrypoint &ep; + Signal_proxy_thread(Entrypoint &ep) + : + Thread("signal_proxy"), + ep(ep) + { } + + void entry() override { ep._process_incoming_signals(); } + }; + + Environment &_env; + + Volatile_object _rpc_ep; + + Signal_proxy_component _signal_proxy {*this}; + Capability _signal_proxy_cap = _rpc_ep->manage(&_signal_proxy); + + Volatile_object _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> _suspend_dispatcher; + + void _dispatch_signal(Signal &sig); + + void _process_incoming_signals(); + + Lazy_volatile_object _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 + Capability + manage(Rpc_object &obj) + { + return _rpc_ep->manage(&obj); + } + + /** + * Dissolve RPC object from entry point + */ + template + void dissolve(Rpc_object &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_ */ diff --git a/repos/base/include/base/env.h b/repos/base/include/base/env.h index d0b9bec53..b6920c184 100644 --- a/repos/base/include/base/env.h +++ b/repos/base/include/base/env.h @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -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. diff --git a/repos/base/include/base/signal.h b/repos/base/include/base/signal.h index 259afe771..eedc6ce88 100644 --- a/repos/base/include/base/signal.h +++ b/repos/base/include/base/signal.h @@ -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 +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_ */ diff --git a/repos/base/include/util/volatile_object.h b/repos/base/include/util/volatile_object.h index eb7aae94a..92d7b9633 100644 --- a/repos/base/include/util/volatile_object.h +++ b/repos/base/include/util/volatile_object.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: diff --git a/repos/base/lib/import/import-ld.mk b/repos/base/lib/import/import-ld.mk new file mode 100644 index 000000000..4f3570c78 --- /dev/null +++ b/repos/base/lib/import/import-ld.mk @@ -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 diff --git a/repos/base/lib/mk/component_entry_point.mk b/repos/base/lib/mk/component_entry_point.mk new file mode 100644 index 000000000..75726e055 --- /dev/null +++ b/repos/base/lib/mk/component_entry_point.mk @@ -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 diff --git a/repos/base/lib/mk/ldso.inc b/repos/base/lib/mk/ldso.inc index 04603b980..46cfcce83 100644 --- a/repos/base/lib/mk/ldso.inc +++ b/repos/base/lib/mk/ldso.inc @@ -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 diff --git a/repos/base/lib/mk/startup.inc b/repos/base/lib/mk/startup.inc index 42fe29824..3e6da1757 100644 --- a/repos/base/lib/mk/startup.inc +++ b/repos/base/lib/mk/startup.inc @@ -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 diff --git a/repos/base/mk/prg.mk b/repos/base/mk/prg.mk index 45322530d..42b0b31eb 100644 --- a/repos/base/mk/prg.mk +++ b/repos/base/mk/prg.mk @@ -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 # diff --git a/repos/base/src/base/component/component.cc b/repos/base/src/base/component/component.cc new file mode 100644 index 000000000..5cd12f21b --- /dev/null +++ b/repos/base/src/base/component/component.cc @@ -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 +#include + + +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 */ +} diff --git a/repos/base/src/base/entrypoint/entrypoint.cc b/repos/base/src/base/entrypoint/entrypoint.cc new file mode 100644 index 000000000..787f5afc4 --- /dev/null +++ b/repos/base/src/base/entrypoint/entrypoint.cc @@ -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 +#include +#include +#include + + +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(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( + [&] () { _signal_proxy_cap.call(); }, + [] () { PWRN("Catched Blocking_canceled on signal processing"); } + ); + + } while (!_suspended_callback); + + _suspend_dispatcher.destruct(); + _sig_rec.destruct(); + dissolve(_signal_proxy); + _signal_proxy_cap = Capability(); + _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 + { + 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_cap = + _rpc_ep->manage(&constructor); + + try { + constructor_cap.call(); + } 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); +} + diff --git a/repos/base/src/base/env/reinitialize.cc b/repos/base/src/base/env/reinitialize.cc index 6190d1fd4..e0b7b0981 100644 --- a/repos/base/src/base/env/reinitialize.cc +++ b/repos/base/src/base/env/reinitialize.cc @@ -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(rms); construct_at(rmc, stack_area_rm); diff --git a/repos/base/src/base/env/stack_area.cc b/repos/base/src/base/env/stack_area.cc index da71743cf..34c6b40d0 100644 --- a/repos/base/src/base/env/stack_area.cc +++ b/repos/base/src/base/env/stack_area.cc @@ -11,56 +11,12 @@ * under the terms of the GNU General Public License version 2. */ -/* Genode includes */ -#include - /* base-internal includes */ #include #include -using namespace Genode; - - -struct Expanding_rm_connection : Connection, 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( - 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; } diff --git a/repos/base/src/base/server/common.cc b/repos/base/src/base/server/common.cc index b91e27112..213de0c71 100644 --- a/repos/base/src/base/server/common.cc +++ b/repos/base/src/base/server/common.cc @@ -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 */ } diff --git a/repos/base/src/base/signal/signal.cc b/repos/base/src/base/signal/signal.cc index 2a8e11ec8..00b3c8e57 100644 --- a/repos/base/src/base/signal/signal.cc +++ b/repos/base/src/base/signal/signal.cc @@ -17,6 +17,7 @@ #include #include #include +#include using namespace Genode; @@ -27,19 +28,19 @@ class Signal_handler_thread : Thread, 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; 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, 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() { - static Signal_source_client sigsrc(env()->pd_session()->alloc_signal_source()); - return &sigsrc; + static Lazy_volatile_object 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) diff --git a/repos/base/src/base/thread/thread.cc b/repos/base/src/base/thread/thread.cc index 19c056d97..f07548aed 100644 --- a/repos/base/src/base/thread/thread.cc +++ b/repos/base/src/base/thread/thread.cc @@ -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); diff --git a/repos/base/src/core/include/core_env.h b/repos/base/src/core/include/core_env.h index a5456a0b3..20d109fc6 100644 --- a/repos/base/src/core/include/core_env.h +++ b/repos/base/src/core/include/core_env.h @@ -32,6 +32,8 @@ #include #include +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::Dst, long) { } + void reinit(Capability::Dst, long) override { } - void reinit_main_thread(Rm_session_capability &) { } + void reinit_main_thread(Rm_session_capability &) override { } }; diff --git a/repos/base/src/core/main.cc b/repos/base/src/core/main.cc index 1c5edd14e..70b5eecbb 100644 --- a/repos/base/src/core/main.cc +++ b/repos/base/src/core/main.cc @@ -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() { /** diff --git a/repos/base/src/core/stack_area.cc b/repos/base/src/core/stack_area.cc index 642bd3627..c3960cc10 100644 --- a/repos/base/src/core/stack_area.cc +++ b/repos/base/src/core/stack_area.cc @@ -27,6 +27,16 @@ #include #include + +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; } diff --git a/repos/base/src/include/base/internal/platform_env.h b/repos/base/src/include/base/internal/platform_env.h index 5769f5d94..72cb5141c 100644 --- a/repos/base/src/include/base/internal/platform_env.h +++ b/repos/base/src/include/base/internal/platform_env.h @@ -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; /************************************* diff --git a/repos/base/src/include/base/internal/platform_env_common.h b/repos/base/src/include/base/internal/platform_env_common.h index f3982dc1e..1db60c4a6 100644 --- a/repos/base/src/include/base/internal/platform_env_common.h +++ b/repos/base/src/include/base/internal/platform_env_common.h @@ -25,6 +25,9 @@ #include #include + +#include + 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(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_ */ diff --git a/repos/base/src/ld/genode_dyn.ld b/repos/base/src/ld/genode_dyn.ld index 825412846..b16f2050d 100644 --- a/repos/base/src/ld/genode_dyn.ld +++ b/repos/base/src/ld/genode_dyn.ld @@ -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) } diff --git a/repos/base/src/lib/ldso/main.cc b/repos/base/src/lib/ldso/main.cc index b0ace26b4..ff89413d7 100644 --- a/repos/base/src/lib/ldso/main.cc +++ b/repos/base/src/lib/ldso/main.cc @@ -12,7 +12,7 @@ */ /* Genode includes */ -#include +#include #include #include #include @@ -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
(_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(_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); } - diff --git a/repos/base/src/lib/startup/_main.cc b/repos/base/src/lib/startup/_main.cc index 90c8ad430..3d2095524 100644 --- a/repos/base/src/lib/startup/_main.cc +++ b/repos/base/src/lib/startup/_main.cc @@ -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 #include #include +#include /* platform-specific local helper functions */ #include #include -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; } diff --git a/repos/base/src/lib/startup/component_construct.cc b/repos/base/src/lib/startup/component_construct.cc new file mode 100644 index 000000000..067400947 --- /dev/null +++ b/repos/base/src/lib/startup/component_construct.cc @@ -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 + + +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"; +} diff --git a/repos/base/src/lib/startup/component_entry_point.cc b/repos/base/src/lib/startup/component_entry_point.cc new file mode 100644 index 000000000..16d3255e8 --- /dev/null +++ b/repos/base/src/lib/startup/component_entry_point.cc @@ -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 + + +/* 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); + } +} diff --git a/repos/base/src/lib/startup/init_main_thread.cc b/repos/base/src/lib/startup/init_main_thread.cc index c8c2f15f3..b28a93be2 100644 --- a/repos/base/src/lib/startup/init_main_thread.cc +++ b/repos/base/src/lib/startup/init_main_thread.cc @@ -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 diff --git a/repos/libports/lib/mk/libc.mk b/repos/libports/lib/mk/libc.mk index 4aa7a1205..f9f347029 100644 --- a/repos/libports/lib/mk/libc.mk +++ b/repos/libports/lib/mk/libc.mk @@ -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 diff --git a/repos/libports/lib/mk/spec/arm/libc.mk b/repos/libports/lib/mk/spec/arm/libc.mk new file mode 100644 index 000000000..619a751db --- /dev/null +++ b/repos/libports/lib/mk/spec/arm/libc.mk @@ -0,0 +1,3 @@ +include $(REP_DIR)/lib/mk/libc.mk + +INC_DIR += $(REP_DIR)/src/lib/libc/include/spec/arm diff --git a/repos/libports/lib/mk/spec/x86_32/libc.mk b/repos/libports/lib/mk/spec/x86_32/libc.mk new file mode 100644 index 000000000..1ca59db70 --- /dev/null +++ b/repos/libports/lib/mk/spec/x86_32/libc.mk @@ -0,0 +1,3 @@ +include $(REP_DIR)/lib/mk/libc.mk + +INC_DIR += $(REP_DIR)/src/lib/libc/include/spec/x86_32 diff --git a/repos/libports/lib/mk/spec/x86_64/libc.mk b/repos/libports/lib/mk/spec/x86_64/libc.mk new file mode 100644 index 000000000..0fbac66af --- /dev/null +++ b/repos/libports/lib/mk/spec/x86_64/libc.mk @@ -0,0 +1,3 @@ +include $(REP_DIR)/lib/mk/libc.mk + +INC_DIR += $(REP_DIR)/src/lib/libc/include/spec/x86_64 diff --git a/repos/libports/run/ldso.run b/repos/libports/run/ldso.run index ffab732d4..fc48912e6 100644 --- a/repos/libports/run/ldso.run +++ b/repos/libports/run/ldso.run @@ -1,8 +1,8 @@ -build "core init test/ldso test/ldso/dl" +build "core init test/ldso" create_boot_directory -install_config { +set config { @@ -23,6 +23,8 @@ install_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 diff --git a/repos/libports/run/libc.run b/repos/libports/run/libc.run index 61c2b9b19..12ed9c719 100644 --- a/repos/libports/run/libc.run +++ b/repos/libports/run/libc.run @@ -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 diff --git a/repos/libports/src/lib/libc/include/spec/arm/internal/call_func.h b/repos/libports/src/lib/libc/include/spec/arm/internal/call_func.h new file mode 100644 index 000000000..ad9b4ef5e --- /dev/null +++ b/repos/libports/src/lib/libc/include/spec/arm/internal/call_func.h @@ -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() 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_ */ diff --git a/repos/libports/src/lib/libc/include/spec/x86_32/internal/call_func.h b/repos/libports/src/lib/libc/include/spec/x86_32/internal/call_func.h new file mode 100644 index 000000000..4f1610606 --- /dev/null +++ b/repos/libports/src/lib/libc/include/spec/x86_32/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() 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_ */ diff --git a/repos/libports/src/lib/libc/include/spec/x86_64/internal/call_func.h b/repos/libports/src/lib/libc/include/spec/x86_64/internal/call_func.h new file mode 100644 index 000000000..14c3afbf5 --- /dev/null +++ b/repos/libports/src/lib/libc/include/spec/x86_64/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() 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_ */ diff --git a/repos/libports/src/lib/libc/task.cc b/repos/libports/src/lib/libc/task.cc new file mode 100644 index 000000000..79bae498a --- /dev/null +++ b/repos/libports/src/lib/libc/task.cc @@ -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 +#include +#include +#include +#include + +/* libc-internal includes */ +#include +#include + + +#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 +{ + 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 cap = _env.ep().manage(*this); + cap.call(); + _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(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; +} diff --git a/repos/libports/src/test/libc/main.cc b/repos/libports/src/test/libc/main.cc index 593fa039e..04c35d668 100644 --- a/repos/libports/src/test/libc/main.cc +++ b/repos/libports/src/test/libc/main.cc @@ -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); } diff --git a/repos/os/include/os/server.h b/repos/os/include/os/server.h index bd9e24f64..ec5f865e8 100644 --- a/repos/os/include/os/server.h +++ b/repos/os/include/os/server.h @@ -14,15 +14,12 @@ #ifndef _INCLUDE__OS__SERVER_H_ #define _INCLUDE__OS__SERVER_H_ +#include #include -#include - 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 - Capability - manage(Rpc_object &obj) - { - return _rpc_ep.manage(&obj); - } - - /** - * Dissolve RPC object from entry point - */ - template - void dissolve(Rpc_object &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_ */ diff --git a/repos/os/include/os/signal_rpc_dispatcher.h b/repos/os/include/os/signal_rpc_dispatcher.h index 2aa133b84..23b429c69 100644 --- a/repos/os/include/os/signal_rpc_dispatcher.h +++ b/repos/os/include/os/signal_rpc_dispatcher.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 #include namespace Genode { - template class Signal_rpc_member; + + template + struct Signal_rpc_member : Signal_handler + { + using Signal_handler::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 -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_ */ diff --git a/repos/os/src/drivers/framebuffer/spec/sdl/fb_sdl.cc b/repos/os/src/drivers/framebuffer/spec/sdl/fb_sdl.cc index d038fc5f3..b50aeb692 100644 --- a/repos/os/src/drivers/framebuffer/spec/sdl/fb_sdl.cc +++ b/repos/os/src/drivers/framebuffer/spec/sdl/fb_sdl.cc @@ -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 -/* Genode */ +/* Genode includes */ #include -#include -#include +#include #include #include #include @@ -27,45 +26,23 @@ #include /* local includes */ -#include +#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 { 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 /** * 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 /* 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 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 cap) : cap(cap) { } - SDL_ShowCursor(0); + void event(Input::Event ev) override + { + cap.call(ev); + } + }; - Genode::printf("creating virtual framebuffer for mode %ldx%ld@%zd\n", - scr_width, scr_height, bpp*8); + struct Handler_component : Genode::Rpc_object + { + 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(); - } 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 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 +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() }; + + Genode::Static_root 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); } diff --git a/repos/os/src/drivers/framebuffer/spec/sdl/input.cc b/repos/os/src/drivers/framebuffer/spec/sdl/input.cc index d9fa82628..fc4a9e1e7 100644 --- a/repos/os/src/drivers/framebuffer/spec/sdl/input.cc +++ b/repos/os/src/drivers/framebuffer/spec/sdl/input.cc @@ -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 -/* Genode */ -#include +/* Genode includes */ #include +#include +#include + +/* local includes */ +#include "input.h" -/* local */ -#include /** * 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 +{ + Handler &handler; + + Backend(Input::Handler &handler) + : + Genode::Thread("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); } diff --git a/repos/os/src/drivers/framebuffer/spec/sdl/input.h b/repos/os/src/drivers/framebuffer/spec/sdl/input.h index 6bb4f4041..2aea8b8ec 100644 --- a/repos/os/src/drivers/framebuffer/spec/sdl/input.h +++ b/repos/os/src/drivers/framebuffer/spec/sdl/input.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 -/** - * 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_ */ diff --git a/repos/os/src/lib/server/server.cc b/repos/os/src/lib/server/server.cc index 1b9061e27..deb7a71be 100644 --- a/repos/os/src/lib/server/server.cc +++ b/repos/os/src/lib/server/server.cc @@ -11,131 +11,34 @@ * under the terms of the GNU General Public License version 2. */ +#include #include -#include - -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(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 -{ - 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 constructor_cap = ep.manage(constructor); - - constructor_cap.call(); - - /* 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(); - } catch(Genode::Ipc_error) { } - } + if (_env) + _env->ep().wait_and_dispatch_one_signal(); } diff --git a/repos/ports/src/lib/libc_noux/plugin.cc b/repos/ports/src/lib/libc_noux/plugin.cc index 88c6cf995..57524bbc3 100644 --- a/repos/ports/src/lib/libc_noux/plugin.cc +++ b/repos/ports/src/lib/libc_noux/plugin.cc @@ -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(); } diff --git a/repos/ports/src/noux/cpu_session_component.h b/repos/ports/src/noux/cpu_session_component.h index cd34a3883..d8e6bccf5 100644 --- a/repos/ports/src/noux/cpu_session_component.h +++ b/repos/ports/src/noux/cpu_session_component.h @@ -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) {